https://lcamtuf.blogspot.dk/2014/11/pulling-jpegs-out-of-thin-air.html
# CC=~/tools/afl-2.35b/afl-clang-fast \CXX=~/tools/afl-2.35b/afl-clang-fast++ make clean all# ~/tools/afl-2.35b/afl-fuzz -i testcases/ \-o output -- ./upx-3.91-src/src/upx.out -d @@
dude@dudebox:~/projects/demo$ tree output/
output/├── crashes│ ├── id:000000,sig:06,src:000000,op:flip1,pos:201│ ├── id:000001,sig:06,src:000000,op:flip1,pos:205│ ├── id:000002,sig:06,src:000000,op:flip1,pos:206│ ├── id:000003,sig:06,src:000000,op:flip1,pos:206│ ├── id:000004,sig:06,src:000000,op:flip1,pos:206│ └── README.txt├── fuzz_bitmap├── fuzzer_stats├── hangs├── plot_data└── queue ├── id:000000,orig:ls.compressed ├── id:000001,src:000000,op:flip1,pos:0,+cov ├── id:000002,src:000000,op:flip1,pos:4 ├── id:000003,src:000000,op:flip1,pos:5,+cov ├── id:000004,src:000000,op:flip1,pos:6,+cov ... ├── id:000089,src:000000,op:flip1,pos:4101 ├── id:000090,src:000000,op:flip1,pos:4384 └── id:000091,src:000000,op:flip1,pos:47643 directories, 101 files
'
#ifdef __AFL_HAVE_MANUAL_CONTROL__AFL_INIT();#endif
readInput()parseInput()
init()while (__AFL_LOOP(1000)) { readInput(); parseInput();}exit(0);
init();while (keep_running) { waitForData(); // blocking readInput(); parseInput(); housekeeping();}cleanup();
init();//while (keep_running) { //waitForData(); // blocking //readInput(); readFromStdin(); (or) readFromFile(); parseInput(); exit(0); housekeeping();//}cleanup();
init();//while (keep_running) { //waitForData(); // blocking //readInput();#ifdef __AFL_HAVE_MANUAL_CONTROL __AFL_INIT();#endif readFromStdin(); (or) readFromFile(); parseInput(); exit(0); housekeeping();//}cleanup();
init();//while (keep_running) {while (__AFL_LOOP(1000) { //waitForData(); // blocking //readInput(); readFromStdin(); (or) readFromFile(); parseInput(); housekeeping();}exit(0);cleanup();
init();//while (keep_running) {while (__AFL_LOOP(1000) { input = readFromStdin(); (or) readFromFile(); sendToItself(input); waitForData(); // blocking readInput(); parseInput(); housekeeping();}exit(0);cleanup();
network time protocol daemon
for (;;) {#if !defined(SIM) && defined(SIGDIE1) if (signalled) finish_safe(signo);#endif if (alarm_flag) { /* alarmed? */ was_alarmed = TRUE; alarm_flag = FALSE; } /* collect async name/addr results */ if (!was_alarmed) harvest_blocking_responses(); if (!was_alarmed && !has_full_recv_buffer()) { /* * Nothing to do. Wait for something. */ io_handler(); }
#define BUFLEN 5120 struct sockaddr_in si_other; int s, slen=sizeof(si_other); char buf[BUFLEN]; if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) { perror("socket"); abort(); } memset((char *) &si_other, 0, sizeof(si_other)); si_other.sin_family = AF_INET; si_other.sin_addr.s_addr = inet_addr("127.0.0.1"); si_other.sin_port = htons(123); while (__AFL_LOOP(1000)) { ... if (!was_alarmed && !has_full_recv_buffer()) { memset(buf, 0, BUFLEN); size_t insize = read(0, buf, BUFLEN); if (sendto(s, buf, insize, 0, (struct sockaddr *)&si_other, slen)==-1) { perror("sendto()"); abort(); } io_handler(); }
afl-plot
dude@dudebox:~/projects/ntpd/run/in$ ls -l | wc -l43dude@dudebox:~/projects/ntpd/run/in$ ls -ltotal 168-rw-r--r-- 2 dude dude 68 Jun 18 11:57 decodenetnumtrigger1.raw-rw-r--r-- 2 dude dude 12 Jun 18 11:57 ntpassociations-rw-r--r-- 1 dude dude 36 Jun 18 11:57 ntpauth-rw-r--r-- 4 dude dude 12 Jun 18 11:57 ntpbeginningstrange-rw-r--r-- 2 dude dude 20 Jun 18 11:57 ntpclockvarassocid-rw-r--r-- 2 dude dude 24 Jun 18 11:57 ntpclockvarassocidset-rw-r--r-- 2 dude dude 24 Jun 18 11:57 ntpclockvarbadformat-rw-r--r-- 2 dude dude 24 Jun 18 11:57 ntpclockvarbadformatset-rw-r--r-- 2 dude dude 20 Jun 18 11:57 ntpclockvardevice-rw-r--r-- 2 dude dude 24 Jun 18 11:57 ntpclockvardeviceclock-rw-r--r-- 2 dude dude 24 Jun 18 11:57 ntpclockvardevicelocal-rw-r--r-- 2 dude dude 32 Jun 18 11:57 ntpclockvardeviceundisciplined-rw-r--r-- 2 dude dude 20 Jun 18 11:57 ntpclockvarflags-rw-r--r-- 7 dude dude 20 Jun 18 11:57 ntpclockvarflagsset-rw-r--r-- 8 dude dude 16 Jun 18 11:57 ntpclockvarpoll-rw-r--r-- 4 dude dude 20 Jun 18 11:57 ntpclockvarpollset-rw-r--r-- 7 dude dude 20 Jun 18 11:57 ntpclockvarstatus-rw-r--r-- 7 dude dude 20 Jun 18 11:57 ntpclockvartimecode-rw-r--r-- 2 dude dude 24 Jun 18 11:57 ntpclockvartimecodeset-rw-r--r-- 7 dude dude 104 Jun 18 11:57 ntpmonstats-rw-r--r-- 2 dude dude 52 Jun 18 11:57 ntpmrulist-rw-r--r-- 2 dude dude 68 Jun 18 11:57 ntpmrulistkod-rw-r--r-- 2 dude dude 72 Jun 18 11:57 ntpmrulistladdrset-rw-r--r-- 2 dude dude 68 Jun 18 11:57 ntpmrulistlimited-rw-r--r-- 2 dude dude 52 Jun 18 11:57 ntpmrulistmincount-rw-r--r-- 2 dude dude 68 Jun 18 11:57 ntpmrulistmincountset-rw-r--r-- 2 dude dude 68 Jun 18 11:57 ntpmrulistresallhexmask-rw-r--r-- 4 dude dude 68 Jun 18 11:57 ntpmrulistresanyhexmask-rw-r--r-- 2 dude dude 52 Jun 18 11:57 ntpmrulistsortorderaddr-rw-r--r-- 2 dude dude 52 Jun 18 11:57 ntpmrulistsortorderavgint-rw-r--r-- 2 dude dude 52 Jun 18 11:57 ntpmrulistsortordercount-rw-r--r-- 2 dude dude 52 Jun 18 11:57 ntpmrulistsortorderlstint-rw-r--r-- 2 dude dude 52 Jun 18 11:57 ntpmrulistsortorderlstintreverse-rw-r--r-- 4 dude dude 12 Jun 18 11:57 ntppeers-rw-r--r-- 4 dude dude 12 Jun 18 11:57 ntppeerschallengeresponse-rw-r--r-- 2 dude dude 16 Jun 18 11:57 ntpreadvarpeer-rw-r--r-- 2 dude dude 24 Jun 18 11:57 ntpreadvarprocessor-rw-r--r-- 4 dude dude 20 Jun 18 11:57 ntpreadvarstatus-rw-r--r-- 7 dude dude 20 Jun 18 11:57 ntpreadvaversion-rw-r--r-- 1 dude dude 44 Jun 18 11:57 ntpwritevarpeer-rw-r--r-- 1 dude dude 52 Jun 18 11:57 ntpwritevarrootdisp-rw-r--r-- 2 dude dude 48 Jun 18 11:57 raw
"What code did I actually fuzz?"
Sucks to figure out that you have been fuzzing the checksum check for multiple weeks Example: PNG
Usage: AFL_LD_PRELOAD=/path/to/libdislocator.so ./afl-fuzz [...other params...] https://github.com/mcarpenter/afl/tree/master/libdislocator
1) It allocates all buffers so that they are immediately adjacent to a subsequent PROT_NONE page, causing most off-by-one reads and writes to immediately segfault, 2) It adds a canary immediately below the allocated buffer, to catch writes to negative offsets (won't catch reads, though), 3) It sets the memory returned by malloc() to garbage values, improving the odds of crashing when the target accesses uninitialized data, 4) It sets freed memory to PROT_NONE and does not actually reuse it, causing most use-after-free bugs to segfault right away, 5) It forces all realloc() calls to return a new address - and sets PROT_NONE on the original block. This catches use-after-realloc bugs, 6) It checks for calloc() overflows and can cause soft or hard failures of alloc requests past a configurable memory limit (AFL_LD_LIMIT_MB, AFL_LD_HARD_LIMIT). Basically, it is inspired by some of the non-default options available for the OpenBSD allocator. It is meant as a more lightweight and hassle-free alternative to fuzzing with ASAN / MSAN (although it's obviously not as comprehensive).
= libdislocator + read checks + more
# AFL_USE_ASAN=1 ...
2) Long version---------------ASAN allocates a huge region of virtual address space for bookkeeping purposes.Most of this is never actually accessed, so the OS never has to allocate anyreal pages of memory for the process, and the VM grabbed by ASAN is essentially"free" - but the mapping counts against the standard OS-enforced limit(RLIMIT_AS, aka ulimit -v).On our end, afl-fuzz tries to protect you from processes that go off-railsand start consuming all the available memory in a vain attempt to parse amalformed input file. This happens surprisingly often, so enforcing such a limitis important for almost any fuzzer: the alternative is for the kernel OOMhandler to step in and start killing random processes to free up resources.Needless to say, that's not a very nice prospect to live with.
"On 64-bit systems, the situation is more murky, because the ASAN allocation is completely outlandish - around 17.5 TB in older versions, and closer to 20 TB with newest ones."
# swapoff -a
# sudo ./limit_memory.sh -u dude -m 500 -- ./afl-fuzz..
afl-cmin: https://github.com/mirrorer/afl/blob/master/afl-cmin
# This tool tries to find the smallest subset of files in the input directory# that still trigger the full range of instrumentation data points seen in# the starting corpus. This has two uses:## - Screening large corpora of input files before using them as a seed for# afl-fuzz. The tool will remove functionally redundant files and likely# leave you with a much smaller set.## (In this case, you probably also want to consider running afl-tmin on# the individual files later on to reduce their size.)## - Minimizing the corpus generated organically by afl-fuzz, perhaps when# planning to feed it to more resource-intensive tools. The tool achieves# this by removing all entries that used to trigger unique behaviors in the# past, but have been made obsolete by later finds.
afl-tmin https://github.com/mirrorer/afl/blob/master/afl-tmin.c
A simple test case minimizer that takes an input file and tries to remove as much data as possible while keeping the binary in a crashing state *or* producing consistent instrumentation output (the mode is auto-selected based on the initially observed behavior).
term coined by Ben Nagy (@rantyben)? https://github.com/bnagy/slides/blob/master/fuzzing_without_pub.pdf
e.g.
A fuzzer is good at finding crashes, so let's convert whatever we want to find into a crash.
ABORT(3) Linux Programmer's Manual ABORT(3)NAME abort - cause abnormal process terminationSYNOPSIS #include <stdlib.h> void abort(void);DESCRIPTION The abort() first unblocks the SIGABRT signal, and then raises that signal for the calling process. This results in the abnormal termination of the process unless the SIGABRT signal is caught and the signal handler does not return (see longjmp(3)). If the abort() function causes process termination, all open streams are closed and flushed. If the SIGABRT signal is ignored, or caught by a handler that returns, the abort() function will still terminate the process. It does this by restoring the default disposition for SIGABRT and then raising the signal for a second time.
input = readInput();resultA = BigNumLibraryA_call(input);resultB = BigNumLibraryB_call(input);if (resultA != resultB) { abort();}exit(0);
...if (authenticated == true) { abort();} exit(0);
If it can be converted to a crash, then it can be fuzzed
e.g. be creative and don't wait
aka "why do you spend your evenings on infosec?"
Keyboard shortcuts
↑, ←, Pg Up, k | Go to previous slide |
↓, →, Pg Dn, Space, j | Go to next slide |
Home | Go to first slide |
End | Go to last slide |
Number + Return | Go to specific slide |
b / m / f | Toggle blackout / mirrored / fullscreen mode |
c | Clone slideshow |
p | Toggle presenter mode |
t | Restart the presentation timer |
?, h | Toggle this help |
Esc | Back to slideshow |