Professional Documents
Culture Documents
dev/post/frida-fuzz/
bananamafia.dev
Why would you want to do this? There may be various reasons, but
the most outstanding one for me is building a fuzzing harness for
closed source applications and libraries. Just take Counter Strike
GO as an example:
If you want to fuzz the map loading routines with maximum speed,
you’d (ideally) want to create a minimized environment that only
performs the map loading. Now the CS:GO client is a graphical
application that performs all kinds of stuff when being launched and
it’s not scriptable to an extent that allows efficient fuzzing. To avoid
executing all this code that’s not even related to map loading, a
fuzzing harness is required. A great example of such a harness for
CS:GO can be found here - the harness consists of a custom
wrapper and some patches.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
1 of 10 25-Feb-20, 12:12 PM
In-Process Fuzzing With Frida about:reader?url=https://bananamafia.dev/post/frida-fuzz/
{
char buffer[1337];
strcpy(buffer, b);
}
Yes, the vulnerability is obvious and yes, you can find it using
simple reverse engineering but I don’t want to build a better PoC
just for people to stop complaining, okay? :)
The idea is to inject some code into the target process and use it to
perform the fuzzing directly in the process as soon as the target
function would be called regularly. This causes the target to
execute all setup routines for us, up to the point where the harness
would also hand over the work to the fuzzer. The target function will
then be called in an infinite loop, with some optional cleanup in
between, while mutating the input. This mutation can also happen
directly in memory, if applicable.
I’ve created this highly complex fuzzing setup using Frida’s Python
bindings:
import frida
import time
import sys
js = """
2 of 10 25-Feb-20, 12:12 PM
In-Process Fuzzing With Frida about:reader?url=https://bananamafia.dev/post/frida-fuzz/
if (lolAddr == null) {
die("Error finding symbol");
}
3 of 10 25-Feb-20, 12:12 PM
In-Process Fuzzing With Frida about:reader?url=https://bananamafia.dev/post/frida-fuzz/
fuzzData.push(0x41);
Memory.writeByteArray(arg, fuzzData);
try {
lolHandle(arg);
}
catch(e) {
console.log("[!] Crash found for
size " + fuzzData.length);
break;
}
}
},
});
"""
script = session.create_script(js)
script.on('message', on_message)
script.load()
frida.resume(pid)
sys.stdin.read()
The script causes Frida to spawn the process, inject the JavaScript
4 of 10 25-Feb-20, 12:12 PM
In-Process Fuzzing With Frida about:reader?url=https://bananamafia.dev/post/frida-fuzz/
code into it and resume the target afterwards. The target process
will then proceed with its normal execution up to the point where
lol() gets called. The JavaScript code defines a hook for this
function that hijacks the program flow and causes the target to fuzz
itself using mutated input. This mutation happens directly in
memory using a buffer that Frida allocated for itself. This mutation
can do all kinds of things, for the example it’s enough to simply
grow the string length over time until the target crashes.
Frizzer Example
You can find some fuzzing targets in the Frizzer repository, but I’ve
built one myself in order to see how Frizzer performs and what it
expects. I’m using a target modified from my previous stack canary
post:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
5 of 10 25-Feb-20, 12:12 PM
In-Process Fuzzing With Frida about:reader?url=https://bananamafia.dev/post/frida-fuzz/
#include <netinet/in.h>
#include <arpa/inet.h>
void thisIsBad()
{
char yolo[12];
strcpy(yolo,
"13333333333333333333333333333333333333333333333333337");
}
int main()
{
int sockfd, ret;
struct sockaddr_in serverAddr;
6 of 10 25-Feb-20, 12:12 PM
In-Process Fuzzing With Frida about:reader?url=https://bananamafia.dev/post/frida-fuzz/
int newSocket;
struct sockaddr_in newAddr;
socklen_t addr_size;
char buffer[1024];
pid_t childpid;
while (1)
{
newSocket = accept(sockfd, (struct
sockaddr *)&newAddr, &addr_size);
printf("[*] Got Connection from %s:%d\n",
inet_ntoa(newAddr.sin_addr),
ntohs(newAddr.sin_port));
char data[32];
7 of 10 25-Feb-20, 12:12 PM
In-Process Fuzzing With Frida about:reader?url=https://bananamafia.dev/post/frida-fuzz/
bzero(data, sizeof(data));
recv(newSocket, data, 32, 0);
if (!strlen(data))
{
continue;
}
pwned(data);
return 0;
}
This is a simple server application that accepts user input via TCP.
This was compiled using gcc -no-pie test.c -o test.
Disabling PIE theoretically isn’t necessary because Frizzer could
get the address of the function to fuzz directly on run time, as seen
in the first example at the beginning of this post.
#!/bin/bash
rm -rf tmpprojdir
[target]
process_name = "test"
8 of 10 25-Feb-20, 12:12 PM
In-Process Fuzzing With Frida about:reader?url=https://bananamafia.dev/post/frida-fuzz/
function = 0x00401294
remote_frida = false
fuzz_in_process = true
modules = [
"/<path to target>/yolotest/test",
]
EOF
$ r2 -A -c "afl~pwned" -q test
0x00401294 5 179 sym.pwned
The directory indir will be filled with files that contain corpus data.
This data is the basis for all the fuzzing that’s going on.
9 of 10 25-Feb-20, 12:12 PM
In-Process Fuzzing With Frida about:reader?url=https://bananamafia.dev/post/frida-fuzz/
And that’s it :)
K THX BYE
10 of 10 25-Feb-20, 12:12 PM