In-Memory fuzzing with Pin
by @Jonathan Salwan - 2013-08-17In my previous blog post, I talked about the taint analysis and the pattern matching with Pin. In this short post, I will always talk about Pin, but this time about the In-Memory fuzzing.
1 - In-Memory fuzzing
1.1 - Little introduction
In-Memory fuzzing is a technique which consists to target and test a specific basic block, function or portion of a program. To be honest, this technique is not really satisfactory over a large portion of code, this is mainly used for a quick analysis. However it's really straightforward to implement it.
For that, we just need to :
- Choose a targeted piece of code.
- Set a breakpoint before and after our targeted area.
- Save the execution context when the first breakpoint occurs.
- Restore the execution context when the second breakpoint occurs.
- Catch the SIGSEGV signal.
- Repeat the operation 3 and 4 until the crash occurs.
![In-Memory fuzzing](./in-memory-fuzzing.png)
1.2 - Little example
For a little example, see the following graph. Now, imagine that the user can control the first argument, that means he can control the rdi register in the first basic block and [rbp+var_4] in this stack frame. In this case, we are interested to test the orange basic block. As you can see below, in the orange basic block we have a "mov eax, [rbp+var_4]", that means we can control the eax register. So, we will apply the In-Memory fuzzing technique in this basic block between the "cdqe" and "mov eax, 0" instructions and we will fuzz the eax register.
![BBLs](./bbls.png)
Use the Pin API
The Pin API provides all what we need to apply the In-Memory fuzzing technique. To catch the signals, we use the PIN_InterceptSignal() function. This function takes the type of signal and a callback. So, to catch the SIGSEGV signal, in our main function we have something like that:
PIN_InterceptSignal(SIGSEGV, catchSignal, 0);
Our call back catchSignal, displays just the current context when the signal occurs.
Then, because Pin is a DBI framework (Dynamic Binary Instrumentation), we can't set a breakpoint, but that's not really important. With a DBI framework we can control each instruction before and after their execution. So, we will use the PIN_SaveContext() and PIN_ExecuteAt() functions when the first and last targeted instruction occurs.
A CONTEXT in Pin, is just the registers state of the processor. That means, when you call PIN_SaveContext(), you save only the state of registers, not the memory. So, to monitor the STORE access, we use the INS_MemoryOperandIsWritten() function. When a STORE occurs, we save the original value and we restore it when the context is restored.
That's all, we can see the full source code here.
In-Memory fuzzing Pin tool
This Pin tool requires three arguments and can take three optional arguments.
Required -------- -start <address> The start address of the fuzzing area -end <address> The end address of the fuzzing area -reg <register> The register which will be fuzzed Optional -------- -startValue <value> The start value -maxValue <value> The end value -fuzzingType <"inc" | "random"> Type of fuzzing: incremental or random
If we take the above example and that we want to fuzz the orange basic block, we have something like that:
$ time pin -t ./InMemoryFuzzing.so -start 0x4005a5 -end 0x4005bb -reg rax -fuzzingType inc \ -startValue 1 -maxValue 0x3000 -- ./test 1 > dump [2] 8472 segmentation fault 0.53s user 0.20s system 99% cpu 0.729 total
I used the "time" command to show you how Pin is efficient - I've also redirected stdout in a file called 'dump' because of the output log size (5.5M). At the end of this dump, you can see the context when the SIGSEGV occurs - Current RIP = 0x4005a5 "movzx eax, byte ptr [rax]" with RAX = 0x2420.
[Restore Context] [Save Context] [CONTEXT]=---------------------------------------------------------- RAX = 0000000000002420 RBX = 0000000000000000 RCX = 00007fff3134c168 RDX = 00007fff3134abe0 RDI = 0000000000000001 RSI = 00007fff3134abe0 RBP = 00007fff3134abc0 RSP = 00007fff3134abb0 RIP = 00000000004005a5 +------------------------------------------------------------------- +--> 4005a5: cdqe +--> 4005a7: add rax, qword ptr [rbp-0x10] +--> 4005ab: movzx eax, byte ptr [rax] /!\ SIGSEGV received /!\ [SIGSGV]=---------------------------------------------------------- RAX = 00007fff3134d000 RBX = 0000000000000000 RCX = 00007fff3134c168 RDX = 00007fff3134abe0 RDI = 0000000000000001 RSI = 00007fff3134abe0 RBP = 00007fff3134abc0 RSP = 00007fff3134abb0 RIP = 00000000004005ab +-------------------------------------------------------------------
You can download this Pin tool here.