diff --git a/docs/Changelog.md b/docs/Changelog.md index e24c2335..e7d4e86b 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -23,10 +23,12 @@ - MacOS aflpp driver compilation fix (-fsanitize=fuzzer implementation) - Make AFL_DUMP_MAP_SIZE work even if the target has sanitizer issues - qemuafl: - - better MIPS persistent mode support + - Better MIPS persistent mode support - afl-cmin: - - new afl-cmin.py which is much faster, will be executed by default via + - New afl-cmin.py which is much faster, will be executed by default via afl-cmin if it executes successfully (thanks to @kcwu!) + - New desocketing library: utils/libaflppdesock + - Likely works when all other desocketing options fail ### Version ++4.32c (release) diff --git a/utils/libaflppdesock/Makefile b/utils/libaflppdesock/Makefile new file mode 100644 index 00000000..97f29c5d --- /dev/null +++ b/utils/libaflppdesock/Makefile @@ -0,0 +1,12 @@ + +# For cross compilation modify this as needed +#GLIBC_PATH := /path/to/glibc-2.xx/build/local_install +#CROSS_CFLAGS := -mfloat-abi=soft -nostdlib -I$(GLIBC_PATH)/include -L$(GLIBC_PATH)/lib -Wl,-rpath=/lib -Wl,--dynamic-linker=/lib/ld-linux.so.3 + +all: libaflppdesock.so + +libaflppdesock.so: libaflppdesock.c + $(CC) $(CROSS_CFLAGS) -shared -fPIC -o libaflppdesock.so libaflppdesock.c + +clean: + rm -f libaflppdesock.so *~ core diff --git a/utils/libaflppdesock/README.md b/utils/libaflppdesock/README.md new file mode 100644 index 00000000..d1c7e314 --- /dev/null +++ b/utils/libaflppdesock/README.md @@ -0,0 +1,46 @@ +# AFL++ TCP desocket library + +Other desocketing solutions: +* https://github.com/zardus/preeny (desock and desock2) +* https://github.com/fkie-cad/libdesock +* https://github.com/zyingp/desockmulti +* https://github.com/vanhauser-thc/network-emulator + +If these desocket solutions fail, then this one will likely easily work +for you - alass with slightly lower performance. +And it is easy to extend :-) + +## Why might this solution work when others do not? + +What makes this desocket library special is that only **only** intercepts +`accept()` calls bound to a specified port. Hence any other network stuff +the application does is still working as expected. + +## How to use + +`AFL_PRELOAD` this library and use the following environment variables: + +* `DESOCK_PORT=8080` - required for intercepting incoming connections for fuzzing - sets the TCP port +* `DESOCK_FORK=1` - intercept and prevent forking +* `DESOCK_CLOSE_EXIT=1` - call _exit() when the desocketed file descriptor is `close`d or `shutdown`ed +* `DESOCK_DEBUG=1` - print debug information to `stderr` + +** Internals + +Currently the library intercepts the following calls: + +``` +shutdown +close +fork +accept +accept4 +listen +bind +setsockopt +getsockopt +getpeername +getsockname +``` + +` \ No newline at end of file diff --git a/utils/libaflppdesock/libaflppdesock.c b/utils/libaflppdesock/libaflppdesock.c new file mode 100644 index 00000000..c6fbe2f4 --- /dev/null +++ b/utils/libaflppdesock/libaflppdesock.c @@ -0,0 +1,352 @@ +/* desocket library by Marc "vanHauser" Heuse + * + * Use this library for fuzzing if preeny's desock and desock2 solutions + * do not work for you - these would provide faster performance. + * + */ + +// default: file descriptor 0 for stdin +#define FUZZ_INPUT_FD 0 + +#include +#include +#include +#include +#include +#include + +static void *handle; +static bool do_fork, do_close, debug, running; +static int port = -1; +static int listen_fd = -1; + +struct myin_addr { + + unsigned int s_addr; // IPv4 address in network byte order + +}; + +struct mysockaddr { + + unsigned short int sin_family; // Address family: AF_INET + unsigned short int sin_port; // Port number (network byte order) + struct myin_addr sin_addr; // Internet address + char sin_zero[8]; // Padding (unused) + +}; + +#define RTLD_LAZY 0x00001 + +unsigned short int htons(unsigned short int hostshort) { + + return (hostshort << 8) | (hostshort >> 8); + +} + +static void __get_handle() { + + if (!(handle = dlopen("libc.so", RTLD_NOW))) { + + if (!(handle = dlopen("libc.so.6", RTLD_NOW))) { + + if (!(handle = dlopen("libc-orig.so", RTLD_LAZY))) { + + if (!(handle = dlopen("cygwin1.dll", RTLD_LAZY))) { + + if (!(handle = dlopen("libc.so", RTLD_NOW))) { + + fprintf(stderr, "DESOCK: can not find libc!\n"); + exit(-1); + + } + + } + + } + + } + + } + + if (getenv("DESOCK_DEBUG")) { debug = true; } + if (getenv("DESOCK_PORT")) { port = atoi(getenv("DESOCK_PORT")); } + if (getenv("DESOCK_FORK")) { do_fork = true; } + if (getenv("DESOCK_CLOSE_EXIT")) { do_close = true; } + if (debug) fprintf(stderr, "DESOCK: initialized!\n"); + +} + +int (*o_shutdown)(int socket, int how); +int shutdown(int socket, int how) { + + if (port != -1 && socket == FUZZ_INPUT_FD && running) { + + running = false; + if (do_close) { + + if (debug) fprintf(stderr, "DESOCK: exiting\n"); + _exit(0); + + } + + } + + if (port == -1 && do_close) { + + if (debug) fprintf(stderr, "DESOCK: exiting\n"); + _exit(0); + + } + + if (!handle) { __get_handle(); } + if (!o_shutdown) { o_shutdown = dlsym(handle, "shutdown"); } + return o_shutdown(socket, how); + +} + +int (*o_close)(int socket); +int close(int socket) { + + if (port != -1 && socket == FUZZ_INPUT_FD && running) { + + running = false; + if (do_close) { + + if (debug) fprintf(stderr, "DESOCK: exiting\n"); + _exit(0); + + } + + } + + if (listen_fd != -1 && socket == listen_fd) { + + if (debug) fprintf(stderr, "DESOCK: close bind\n"); + listen_fd = -1; + + } + + if (!handle) { __get_handle(); } + if (!o_close) { o_close = dlsym(handle, "close"); } + return o_close(socket); + +} + +int (*o_fork)(void); +int fork() { + + if (do_fork) { + + if (debug) fprintf(stderr, "DESOCK: fake fork\n"); + return 0; + + } + + if (!handle) { __get_handle(); } + if (!o_fork) { o_fork = dlsym(handle, "fork"); } + return o_fork(); + +} + +int (*o_accept)(int sockfd, struct mysockaddr *addr, + unsigned long int *addrlen); +int accept(int sockfd, struct mysockaddr *addr, unsigned long int *addrlen) { + + if (!handle) { __get_handle(); } + if (!o_accept) { o_accept = dlsym(handle, "accept"); } + if (!running && sockfd == listen_fd) { + + if (debug) fprintf(stderr, "DESOCK: intercepted accept on %d\n", sockfd); + if (addr && addrlen) { + + // we need to fill this! + memset(addr, 0, *addrlen); + addr->sin_family = 2; // AF_INET + addr->sin_port = htons(1023); // Port 1023 in network byte order + addr->sin_addr.s_addr = 0x0100007f; + + } + + running = true; + return FUZZ_INPUT_FD; + + } + + return o_accept(sockfd, addr, addrlen); + +} + +int accept4(int sockfd, struct mysockaddr *addr, unsigned long int *addrlen, + int flags) { + + return accept(sockfd, addr, addrlen); // ignore flags + +} + +int (*o_listen)(int sockfd, int backlog); +int listen(int sockfd, int backlog) { + + if (!handle) { __get_handle(); } + if (!o_listen) { o_listen = dlsym(handle, "listen"); } + if (sockfd == listen_fd) { + + if (debug) fprintf(stderr, "DESOCK: intercepted listen on %d\n", sockfd); + return 0; + + } + + return o_listen(sockfd, backlog); + +} + +int (*o_bind)(int sockfd, const struct mysockaddr *addr, + unsigned long int addrlen); +int bind(int sockfd, const struct mysockaddr *addr, unsigned long int addrlen) { + + if (!handle) { __get_handle(); } + if (!o_bind) { o_bind = dlsym(handle, "bind"); } + if (addr->sin_port == htons(port)) { + + if (debug) fprintf(stderr, "DESOCK: intercepted bind on %d\n", sockfd); + listen_fd = sockfd; + return 0; + + } + + return o_bind(sockfd, addr, addrlen); + +} + +int (*o_setsockopt)(int sockfd, int level, int optname, const void *optval, + unsigned long int optlen); +int setsockopt(int sockfd, int level, int optname, const void *optval, + unsigned long int optlen) { + + if (!handle) { __get_handle(); } + if (!o_setsockopt) { o_setsockopt = dlsym(handle, "setsockopt"); } + if (listen_fd == sockfd) { + + if (debug) + fprintf(stderr, "DESOCK: intercepted setsockopt on %d for %d\n", sockfd, + optname); + return 0; + + } + + return o_setsockopt(sockfd, level, optname, optval, optlen); + +} + +int (*o_getsockopt)(int sockfd, int level, int optname, void *optval, + unsigned long int *optlen); +int getsockopt(int sockfd, int level, int optname, void *optval, + unsigned long int *optlen) { + + if (!handle) { __get_handle(); } + if (!o_getsockopt) { o_getsockopt = dlsym(handle, "getsockopt"); } + if (listen_fd == sockfd) { + + if (debug) + fprintf(stderr, "DESOCK: intercepted getsockopt on %d for %d\n", sockfd, + optname); + int *o = (int *)optval; + if (o != NULL) { + + *o = 1; // let's hope this is fine + + } + + return 0; + + } + + return o_getsockopt(sockfd, level, optname, optval, optlen); + +} + +int (*o_getpeername)(int sockfd, struct mysockaddr *addr, + unsigned long int *addrlen); +int getpeername(int sockfd, struct mysockaddr *addr, + unsigned long int *addrlen) { + + if (!handle) { __get_handle(); } + if (!o_getpeername) { o_getpeername = dlsym(handle, "getpeername"); } + if (port != -1 && sockfd == FUZZ_INPUT_FD) { + + if (debug) fprintf(stderr, "DESOCK: getpeername\n"); + if (addr && addrlen) { + + // we need to fill this! + memset(addr, 0, *addrlen); + addr->sin_family = 2; // AF_INET + addr->sin_port = htons(1023); // Port 1023 in network byte order + addr->sin_addr.s_addr = 0x0100007f; + + } + + return 0; + + } + + return o_getpeername(sockfd, addr, addrlen); + +} + +int (*o_getsockname)(int sockfd, struct mysockaddr *addr, + unsigned long int *addrlen); +int getsockname(int sockfd, struct mysockaddr *addr, + unsigned long int *addrlen) { + + if (!handle) { __get_handle(); } + if (!o_getsockname) { o_getsockname = dlsym(handle, "getsockname"); } + if (port != -1 && sockfd == FUZZ_INPUT_FD) { + + if (debug) fprintf(stderr, "DESOCK: getsockname\n"); + if (addr && addrlen) { + + // we need to fill this! + memset(addr, 0, *addrlen); + addr->sin_family = 2; // AF_INET + addr->sin_port = htons(port); + addr->sin_addr.s_addr = 0x0100007f; + + } + + return 0; + + } + + return o_getsockname(sockfd, addr, addrlen); + +} + +static FILE *(*o_fdopen)(int fd, const char *mode); +FILE *fdopen(int fd, const char *mode) { + + if (!o_fdopen) { + + if (!handle) { __get_handle(); } + + o_fdopen = dlsym(handle, "fdopen"); + if (!o_fdopen) { + + fprintf(stderr, "%s(): can not find fdopen\n", dlerror()); + exit(-1); + + } + + } + + if (fd == FUZZ_INPUT_FD && strcmp(mode, "r") != 0) { + + if (debug) fprintf(stderr, "DESOCK: intercepted fdopen(r+) for %d\n", fd); + return o_fdopen(fd, "r"); + + } + + return o_fdopen(fd, mode); + +} + +/* TARGET SPECIFIC HOOKS - put extra needed code for your target here */ +