Metasm recipes: working with a process image

Tue 18 January 2011 by jj

Today we'll discuss how metasm can be used to work with a process memory dump, and also how to search for gadgets suitable for a short ROP sequence.

While working on a vulnerability on a windows server, we had the following premises:

  • Non-executable heap
  • Randomised address space (except for the main binary)
  • We had the address of a buffer we control
  • Small stack overflow
  • Additional flaw allowing to read arbitrary 4bytes anywhere

From there, the tactic was simple:

  • Inject our shellcode in the buffer
  • Find the address of VirtualProtect
  • Jump on it to make the buffer executable
  • Return to the shellcode

We chose the easy path: determine the base address of kernel32. This is done by finding a pointer to k32 somewhere, the main binary IAT sounded like a good candidate. You just have to be careful to not use the address of some kernel32 import that is actually forwarded to some other library, like ntdll.

Once you have a pointer to some part of the library, you then scan backward, 0x10000 bytes at a time, until you find the MZ header. We were unsure of the version of the dll that was present on the server, so we used the read4 repeatedly to dump the whole library image from the process memory. On recent windows versions, you have to be careful, as some libraries include a virtual address gap, usually right after the PE header ; you need to jump over it, if you try to read this area the target will crash and you need to start all over again.

So this gave us the raw memory dump of the kernel32 module (fill the memory gap with zeroes). Now how can we work with it ? The usual tools are pretty useless there, they only handle disk images, and the memory image has not the exact same layout: PE sections are loaded at their memory offset, which is (usually) different from the disk file offset.

This was the time to unsheath Metasm. The standard disassembler GUI has the handy option --exe to change the default auto-determined file type. This way, we can tell that the PE file is a memory image, by using the LoadedPE class, generally used by the debugger, instead of the standard PE class.

Once in the GUI, type gvirtualp to find the address of the function we need (g opens the goto dialog, where we can put a fragment of a label name. If the fragment is ambiguous, this will pop a list of all the possible completions).

Additionally, we need to execute our shellcode.Now that we have given it RWX memory permissions, we still need to divert EIP to it; for that we will use a simple Return Oriented Programming sequence:

  • pop eax; ret put the address of our buffer in eax
  • mov esp, eax; ret stack points to our buffer
  • jmp esp execute the shellcode in the buffer

To find those in the library, we can use the brand new findgadget.rb disassembler plugin.

You can load it using ctrl+r, then type dasm.load_plugin \"findgadget\", or click the menu/action/run ruby plugin.

Once loaded, type the G key (or menu/action/scan for gadget), and type your asm in the box.You can separate instructions with ';' or spaces.

So, the magic commandline:

ruby samples/disassemble-gui.rb --exe LoadedPE -P findgadget k32_dump.bin

Job done.

Also, hacky new year !