In-Memory fuzzing with Pin

by @Jonathan Salwan - 2013-08-17

In 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 :

  1. Choose a targeted piece of code.
  2. Set a breakpoint before and after our targeted area.
  3. Save the execution context when the first breakpoint occurs.
  4. Restore the execution context when the second breakpoint occurs.
  5. Catch the SIGSEGV signal.
  6. Repeat the operation 3 and 4 until the crash occurs.

In-Memory fuzzing


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.



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.

  -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

  -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 ./ -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]
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 /!\
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.