Home Fuzzotron and Radamsa pcap testcases
Post

Fuzzotron and Radamsa pcap testcases

Fuzzing Script

What’s Da Fuzz

One method of finding unknown vulnerabilties is simply shooting a bunch of trash data at a program to see how it reacts, and trapping any error codes. We can fuzz TCP or UDP services with a combination of Fuzzotron and Radamsa. I’ve also written a Python script that will take pcap data, strip the packet header information (Layer, IP address, port numbers, etc) leaving you with the packet data segment only, saving this to a testcase directory. This can later be fed into Radamsa, which will mangle the data (by flipping bits, shifting data, adding or removing random data, etc), which is taken by Fuzzotron and sent to the service.

Note: Click here if you came here looking for the tutorial on fuzzing blackbox binaries with ansvif.

Installation

First you’ll need to install some prerequisite development headers so you can compile Radamsa and Fuzzotron properly.

sudo apt update
sudo apt install libssl-dev libpcre3-dev tcpdump

Then you’ll want to create a working directory for your fuzz, move into it, and clone the git repos you’ll need.

mkdir fuzzy
cd fuzzy
git clone https://gitlab.com/akihe/radamsa.git
git clone https://github.com/denandz/fuzzotron.git
git clone https://github.com/oxagast/oxasploits.git

Now move into the radamsa directory (you’ll need to compile and install this beforehand, or fuzzotron will complain about missing dependancies), and compile it.

cd radamsa
make clean
make
sudo make install
cd ..

You can now move into the fuzzotron dir and compile that with radamsa support.

cd fuzzzotron
make clean
make -j
cd ..

Generating testcases

Feel free to generate a pcap on the port of the service you’ll be fuzzing. For this writeup I’ll be using port 80 HTTP, just as an example.

sudo tcpdump -w testcase.pcap 'port 80'

Now go and do some work for a few minutes, using the server you’ll be fuzzing normally to generate some realistic datasets to build off of. Don’t leave it on all night though, it’s tempting, but the Python script we use next could potentially OOM when trying to generate the testcases if there are too many packets to analyze.

The script I wrote looks like this:

# oxagast
# use:
#   tcpdump -w ~/capture.pcap 'port 9000'
#   python3 pcap_gen_testcases.py ~/capture.pcap
# this will create a testcase directory of each destination port filled with files each
# the data section of the packets in the pcap file.  One packet is one file.  TCP header
# info is stripped.

import os
import sys
try:
    import scapy.all as scapy
except ImportError:
    import scapy
def prune_e(path):
    for (dirpath, dirnames, filenames) in os.walk(path):
        for filename in filenames:
            filef = dirpath + "/" + filename
            if os.path.getsize(filef) == 0:
                os.remove(filef)
def parse_pcap(pcap_path):
    print("Generating testcases based on " + sys.argv[1] + ".  This will take a while...")
    s = 0
    pcap_infos = list()
    packets = scapy.rdpcap(pcap_path)
    for p in packets:
        if p.haslayer("IP"):
            src_ip = p["IP"].src
            dst_ip = p["IP"].dst
        if p.haslayer("TCP"):
            raw_d = p["TCP"].payload.original
            sport = p["TCP"].sport
            dport = p["TCP"].dport
            dport_dir = str(dport)
            if not os.path.exists("testcases/" + dport_dir):
                os.mkdir("testcases/" + dport_dir)
            num = str(s)
            out = open("testcases/" + dport_dir + "/pcap.data_packet." + num + ".dat", "wb")
            out.write(raw_d) # yeah, i do hit it raw.
            s = s + 1
if len(sys.argv) != 2:
    print("You need to provide a .pcap file.")
    sys.exit(1)
if not os.path.exists(sys.argv[1]):
    print("The .pcap file does not exist.")
    sys.exit(1)
ssssssssssif not os.path.exists("testcases"):
    os.mkdir("testcases")
parse_pcap(sys.argv[1])
prune_e("testcases")
print("Done.")
sys.exit(0)

If you cloned all the earlier git repos, you can now start generating testcases like this:

python3 oxasploits/tools/pcap_gen_testcases.py testcase.pcap

Once it finishes, it will have made a directory called ‘testcases’ with a directory tree within, each numbered dir cooresponds to the destination port number of the packet, and inside is each packet’s data in a .dat file. You can view it to make sure it looks about right by doing:

hexdump -C testcases/80/pcap.data_packet.105.dat

You should see something similar to:

00000000  50 4f 53 54 20 2f 20 48  54 54 50 2f 31 2e 31 0d  |POST / HTTP/1.1.|
00000010  0a 48 6f 73 74 3a 20 6f  63 73 70 2e 73 65 63 74  |.Host: ocsp.sect|
00000020  69 67 6f 2e 63 6f 6d 0d  0a 55 73 65 72 2d 41 67  |igo.com..User-Ag|
00000030  65 6e 74 3a 20 4d 6f 7a  69 6c 6c 61 2f 35 2e 30  |ent: Mozilla/5.0|
00000040  20 28 58 31 31 3b 20 55  62 75 6e 74 75 3b 20 4c  | (X11; Ubuntu; L|
00000050  69 6e 75 78 20 78 38 36  5f 36 34 3b 20 72 76 3a  |inux x86_64; rv:|
00000060  39 36 2e 30 29 20 47 65  63 6b 6f 2f 32 30 31 30  |96.0) Gecko/2010|
00000070  30 31 30 31 20 46 69 72  65 66 6f 78 2f 39 36 2e  |0101 Firefox/96.|
00000080  30 0d 0a 41 63 63 65 70  74 3a 20 2a 2f 2a 0d 0a  |0..Accept: */*..|
00000090  41 63 63 65 70 74 2d 4c  61 6e 67 75 61 67 65 3a  |Accept-Language:|
000000a0  20 65 6e 2d 55 53 2c 65  6e 3b 71 3d 30 2e 35 0d  | en-US,en;q=0.5.|
000000b0  0a 41 63 63 65 70 74 2d  45 6e 63 6f 64 69 6e 67  |.Accept-Encoding|
000000c0  3a 20 67 7a 69 70 2c 20  64 65 66 6c 61 74 65 0d  |: gzip, deflate.|
000000d0  0a 43 6f 6e 74 65 6e 74  2d 54 79 70 65 3a 20 61  |.Content-Type: a|
000000e0  70 70 6c 69 63 61 74 69  6f 6e 2f 6f 63 73 70 2d  |pplication/ocsp-|
000000f0  72 65 71 75 65 73 74 0d  0a 43 6f 6e 74 65 6e 74  |request..Content|
00000100  2d 4c 65 6e 67 74 68 3a  20 38 33 0d 0a 43 6f 6e  |-Length: 83..Con|
00000110  6e 65 63 74 69 6f 6e 3a  20 6b 65 65 70 2d 61 6c  |nection: keep-al|
00000120  69 76 65 0d 0a 50 72 61  67 6d 61 3a 20 6e 6f 2d  |ive..Pragma: no-|
00000130  63 61 63 68 65 0d 0a 43  61 63 68 65 2d 43 6f 6e  |cache..Cache-Con|
00000140  74 72 6f 6c 3a 20 6e 6f  2d 63 61 63 68 65 0d 0a  |trol: no-cache..|
00000150  0d 0a 30 51 30 4f 30 4d  30 4b 30 49 30 09 06 05  |..0Q0O0M0K0I0...|
00000160  2b 0e 03 02 1a 05 00 04  14 21 f3 45 9a 10 ca a6  |+........!.E....|
00000170  c8 4b da 1e 39 62 b1 27  d5 33 8a 7c 48 04 14 17  |.K..9b.'.3.|H...|
00000180  d9 d6 25 27 67 f9 31 c2  49 43 d9 30 36 44 8c 6c  |..%'g.1.IC.06D.l|
00000190  a9 4f eb 02 10 72 72 1a  3e c7 72 71 29 00 f8 8d  |.O...rr.>.rq)...|
000001a0  bb 83 30 12 ab                                    |..0..|
000001a5

It will differ a bit.

Fuzzing the service

Now that our setup is complete, it’s time to start actually fuzzing the service!

./fuzzotron --radamsa --directory ../testcases/80/ -h 127.0.0.1 -p 80 -P tcp -c $(pgrep -P 1 apache2) -o crash

You should see something like:

[+] Monitoring PID 2133999
[+] Spawning worker thread 1
[.] Worker 1 alive
[.] Deterministic mutations completed, sent: 51448
[|] Sent cases: 56348

Now you should be able to just let it run, and if/when the service crashes, it should drop a log file of the data that made it crash in the directory crash/.

Conclusion

Generation of a reasonable amount of quality initial data is important. This gives radamsa something to work with. You may need to let this run for a couple days to a week before it even finds a crash. It is afterall, brute force vulnerability research, and it takes a lot of time. Because of this, I usually run this kind of thing in a virtual machine, so I’m not tying up the rest of my workstation in the meantime. This also makes it simple to pause/resume a lengthy fuzz test.

I have also written my own fuzzer in C++ and you can read my short intro to ansvif and blackbox fuzzers.

Hope you enjoyed, and happy bug hunting!


If you enjoy my work, sponsor or hire me! I work hard keeping oxasploits running!
Bitcoin Address:
bc1qclqhff9dlvmmuqgu4907gh6gxy8wy8yqk596yp

Thank you so much and happy hacking!
This post is licensed under CC BY 4.0 by the author.