
Fuzzotron and Radamsa pcap testcases
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
directory (you’ll need to compile and install this beforehand,
or fuzzotron will complain about missing dependancies), and compile it.1
radamsa
cd radamsa
make clean
make
sudo make install
cd ..
You can now move into the
dir and compile that with radamsa support.1
fuzzotron
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
file. You can view it to make sure it looks about
right by doing:1
.dat
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
.1
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:
bc1qq7vvwfe7760s3dm8uq28seck465h3tqp3fjq4l
Thank you so much and happy hacking!