In Memory Fuzzer

If you already know what is in-memory-fuzzing and has figured out what this blog post is about, here is the link to the tool. Go bag your zero days.

https://danteshub.in/tools/in-memory-fuzzer.zip

For the rest, this article will introduce in memory fuzzing and how to use the tool for fuzzing in difficult scenarios.

One of the frequent requirements in a thick client penetration test is to perform fuzzing on specific section of the code that is not easily possible to test. There may be a sequence of operations that external entities (user, server, client etc) have to perform, before the application reaches the interesting section of code that we would like to fuzz. For instance to fuzz the function that parses the value fetched from windows registry, the application may require the user to go through several steps before the particular value is being read. Such triggers are hard to emulate for fuzzing needs. Is there a way to eliminate the requirement of this trigger and directly fuzz specific functions inside a binary?  The answer is “In memory fuzzing”.

Let’s start with a sample C Code.

int XMLParse(char *xml)

{

//Code of XML Parser here

.

.

.

}

int main()

{

xmlParse(inputFromNetwork);

return 0;

}

If the source code is available, we can fuzz the XMLParse function as follows.

int XMLParse(char *xml)

{

//Code of XML Parser here

.

.

.

}

char * genRandXML()

{

//Generate Random XML

.

.

.

}

int main()

{

.

.

.

for(i=0;i<numOfTestCases;i++)

xmlParse(genRandXML());

return 0;

}

Now let’s extend this to binaries. Let’s say we need to fuzz the same function but we only have access to the compiled binary and not the source code.

What do we need to do to accomplish that?

  1. Know where the function is located in the binary
  2. Set up a breakpoint on the location found.
  3. Run the binary and when the breakpoint is hit, save the memory state.
  4. Change the arguments to the function.
  5. Call  the function with modified arguments
  6. Restore the memory state. Go to step 4.

From requirements 2-6, it is obvious that we need to find a debugging library that will attach to the process and allows us to breakpoint at the function we would like to fuzz. Once the language was chosen to be python, the next step was to choose a python debugging library. Two libraries stand out prominent.

  • Winappdbg
  • Pydbg.

Pydbg is not maintained and it is not straight forward to set it up for latest versions of python. But pydbg appears to be faster than winappdbg while taking memory snapshots and offers cross platform support. Winappdbg is well maintained, documented and offers hassle free installation. But it runs only on windows. Accessibility trumps efficiency. Winappdbg was chosen.

Let’s talk about requirement #1. We may not be always lucky to have symbol files handed over to us. Finding the function that is of interest requires reversing experience. Tools like API Monitor, Process monitor could ease the path. Nevertheless once you have identified the function that you would like to fuzz and determined the number of arguments, the rest of requirements is fulfilled by the fuzzer (How? Check the comments in code).

Let’s jump on to a quick demo. Download the project from git.

https://danteshub.in/tools/in-memory-fuzzer.zip

You will find an application named test.exe. Following is the C source code of test.exe

#include<stdio.h>

#include<string.h>

void test_func(char *src)

{

char a[1000];

strcpy(a,src);

printf(“\n%s”,src);

}

int main(int c, char *argv[])

{

printf(“Hello world”);

if(c>1)

test_func(argv[1]);

getchar();

}

We would like to fuzz test_func. If you check imf_config_test, you will find the configuration settings for fuzzing test_func. The key parameters are listed below.

#module name that contains the function.

#Leave this empty if the function to be fuzzed is in the executable and not in a DLL.

MODULE_NAME=””

#Function address – specify 0 if you are specifying function offset

#This is the one that you see in debugger

FUNCTION_ADDRESS=0x401290

#Function offset from the module base. Not the one you see in debugger.

#This is provided for ASLR enabled applications

FUNCTION_OFFSET = 0x290 #funtion start

#No of parameters that the function accepts

PARAM_COUNT=1 #function parameter count

The key functions in imf_config_test are modifyParams and freeMemory. “modifyParams” will be called by in_memory_fuzz before the start of the target function. The pentester can choose the parameters to be fuzzed and modify the value of the parameters accordingly. Regardless of the parameter’s data type (structures, string etc), it is possible to modify the parameter. However the pentester needs to take care of memory management. The parameters that are “malloc”ed in modifyParams needs to “free”d in freeMemory function. The freeMemory function will be called by in_memory_fuzz after the target function completes execution.

Check the Readme file. Make sure the prerequisites are fulfilled.

python in_memory_fuzz.py -m imf_config_test

You will first see that the fuzzer returns the disassembly of the function that you chose to fuzz as shown below.

If you press any key, it will start fuzzing the function and you will find that the application crashes as shown below.

You can find the input that crashed the application and other crash relevant details including the value of registers, stack trace in the log created.

As you can observe from the imf_config_test file, the fuzzer offers complete control to the pentester on how the fuzzing operation needs to be carried out. The downside is the pentester might have to hit the python and winappdbg docs a few times to carry out complex tasks.

The fuzzer supports fuzzing ASLR enabled applications. The pentester have to specify the function offset and the module in order to exploit this feature. The fuzzer can fuzz only one function at a time. I am not sure if it is advisable to allow fuzzing multiple functions at the same time. Also the fuzzer does not completely eliminate triggers that we discussed before. After the crash, the fuzzer provides the option of restarting the process to resume the fuzzing, however if there is a series of operations needs to be performed again, the fuzzer doesn’t help with that. Alternatively AutoIt, VM Snapshot options may be explored to solve this issue. Another one on the to-do list for this project is writing a fuzzing library to fuzz at least basic data types that the config modules can in turn use.

Bug reports/feedbacks are welcome

[This blog post was resurrected from 2014 version of this blog]