Syndicate

Syndicate content

Flattr


Flattr this

If you like this, you can use flattr. ;)

Imprint

About
eMail: wishinet at gmail . com
PGP ID: 0xCCCA5E74

Jabber: wishi@jabber.ccc.de

Tags for this post

A Paimei tutorial - simple heap-traceing - part 2

txttxt

Abstract

The following tutorial builds on the basics which are documented in the first part. For vulnerability discovery, debugging and fuzzing are essential. Furthermore the proper knowledge of memory management, assembly instructions and Python will still be needed. You cannot just scratch the surface while trying to explore these techniques. I wrote this tutorial to inspire people, or to help people coping with Windows and its restrictions. But most people in the fields will laugh at this and call it primitive. It is.

For whom this tutorial maybe of interest:

  • people developing Windows exploits and searching for vulnerabilities
  • anyone who spent more than a couple of hours using IDA, Python, or pyDBG
  • Reverse engineering folks
  • deeply security interested individuals, the common addicted seeker - again I link to good documentations

Recommended and used sources for this tutorial were:

Review: Keep things easy

Have a look at the following C# example of exception handling:

  1. #993333;">void inPutter#009900;">(Komplex zahl1#339933;">, Komplex zahl2#009900;">)#009900;">{
  2.         try #009900;">{
  3.         zahl1.#202020;">Re #339933;">= #993333;">float.#202020;">Parse#009900;">(Zahl1_r.#202020;">Text#009900;">)#339933;">;           #009900;">} catch #009900;">(Exception ex#009900;">) #009900;">{
  4.                 MessageBox.#202020;">Show#009900;">(ex.#202020;">StackTrace#009900;">)#339933;">;    #666666; font-style: italic;">// for dbg    
  5.         #009900;">} finally #009900;">{
  6.                 #666666; font-style: italic;">// something    
  7.         #009900;">}
  8. #009900;">} #666666; font-style: italic;">// end of inPutter()

It's a very primitive example of exception handling. Alternatively maybe tryParse may have been kewler... but that's not the point. The implementation of the exception objects allows us to output a Strack-trace. So in case of handled crashes we know the reason why. Easily said: with debugging in the first part of this tutorial we did the same thing with a closed-source Crackme binary. Knowing the reason why an application cashes can reveal weakness in its structure, which can be exploited to alter its execution flow. - But that's much too easy. And I guess I should have deleted this paragraph ;).

Tracing the Heap in the wild world of Windows

A script waits to be used: heap_trace.py. Again we start the uDraw server. We start our Crackme and note the PID somewhere.

  1. python heap_trace.py #ff4500;">1234

That's it. Maybe you need to elevate this process, depending on your Windows policy setups. The script will log the trace to the console and process the graph into uDraw on the fly. - As you saw on the demo by Pendam. To gain a better understanding of this "linked-list" here's some background from the Shellcoders Handbook (second edition), because in Vista a new approach to manage the Heap has been made. Simply said: instead of using the syscalls in C - like you do in *nix, for Windows you have to use the DLLs. This has got a couple of reasons. It's simply convenient, because changes to the internal Windows structure don't affect your programs. MS developers can separate their work from yours. The relocatable file-format is used in Windows, gets loaded at runtime to provide the functionalities of shared libraries. Their format is PE-COFF; and the Windows PE-loader accepts them. Most times ;).
When a DLL gets loaded, it calls an initialization function. This function often sets up its own heap using HeapCreate() and stores a global variable as a pointer to that heap so that future allocation operations can use it instead of the default heap. Most DLLs have a .data section in memory for storing global variables, and you will often find useful function pointers or data structures stored in that area. Because many DLLs are loaded, there are many heaps. With so many heaps to keep track of, heap corruption attacks can become quite confusing. In Linux, there is typically a single heap that can get corrupted, but in Windows, several heaps may get corrupted at once, which makes analyzing the situation much more complex. When a user calls malloc() in Win32, he or she is actually using a function exported by msvcrt.dll, which then calls HeapAllocate() with msvcrt.dll’s private heap. You may be tempted to try to use the HeapValidate()function to analyze a heap corruption situation, but this function does not do anything useful.
(Chapter 6, Shellcoders Handbook 2nd)


In the script's default list-output it's difficult to gain an overview which blocks are freed, or which of these are able to receive data. So have a look at the blue boxes in the graph. Attach the process to ollyDBG and have a look at the first address from the graph.

7E3A5A06   8BF0             MOV ESI#339933;">,EAX

Set a conditional breakpoint and log for RtlAllocateHeap calls. We get:
 7E3A5A00   FF15 9C13397E    CALL DWORD PTR DS#339933;">:#009900;">[#339933;">&lt#339933;">;&amp#339933;">;KERNEL32.#202020;">HeapAlloc#339933;">&gt#339933;">;&gt#339933;">;; ntdll.#202020;">RtlAllocateHeap 7E3A5A06   8BF0             MOV ESI#339933;">,EAX

It could look like this, where there's a breakpoint log at [ESP +8] - where the heap size is stored in hex. If you run the programm you see that the sizes of the created blocks are logged. Of course these are the same sizes heap_trace.py showed. Each time the process runs, the RtlAllocateHeap will run, allocating different spaces. We just know the sizes for sure. So the condition of our breakpoint is: [ebp +8] == 0b8. We trigger for that size.

heap_trace.py does what?

I guess the imports are understood jet, because I mentioned utils in part 1 as part of pyDBG. I'll skip trivial parts as long as they're not related with our heap-tracing tasks.

  1. USAGE = #483d8b;">"USAGE: heap_trace.py"#66cc66;">;
  2. error = #ff7700;font-weight:bold;">lambda msg: #dc143c;">sys.stderr.write(#483d8b;">"ERROR" + msg + #483d8b;">"#000099; font-weight: bold;">\n") #ff7700;font-weight:bold;">or #dc143c;">sys.exit(#ff4500;">1)



  1. #ff7700;font-weight:bold;">if #008000;">len(#dc143c;">sys.argv) #66cc66;">!= #ff4500;">2:
  2.      error(USAGE)  
  3. #ff7700;font-weight:bold;">try:
  4.      pid = #008000;">int(#dc143c;">sys.argv[#ff4500;">1])
  5. #ff7700;font-weight:bold;">except:
  6.      error(USAGE)

I think the lambda error here is a kind of elegant solution, because it'll show whether any errors occurred and use sys.stderr to store these.

  1. dbg.set_callback(LOAD_DLL_DEBUG_EVENT, dll_load_handler)
  2. #808080; font-style: italic;"># refers to part 1
  3. addrRtlAllocateHeap   = dbg.func_resolve(#483d8b;">"ntdll", #483d8b;">"RtlAllocateHeap")
  4. addrRtlFreeHeap       = dbg.func_resolve(#483d8b;">"ntdll", #483d8b;">"RtlFreeHeap")
  5. addrRtlReAllocateHeap = dbg.func_resolve(#483d8b;">"ntdll", #483d8b;">"RtlReAllocateHeap"
  6. #808080; font-style: italic;"># we also had this in part 1
  7. hooks = utils.hook_container()
  8. hooks.add(dbg, addrRtlAllocateHeap,   #ff4500;">3, #008000;">None, RtlAllocateHeap)
  9. hooks.add(dbg, addrRtlFreeHeap,       #ff4500;">3, #008000;">None, RtlFreeHeap)
  10. hooks.add(dbg, addrRtlReAllocateHeap, #ff4500;">4, #008000;">None, RtlReAllocateHeap)
  11. #808080; font-style: italic;"># and this

It's very similar what we see here. Throgh dbg.set_callback we create a hook for each DLL calling event, enter the function dll_load_handler, which is defined in Pendam's script at this point:

  1. #ff7700;font-weight:bold;">def dll_load_handler (dbg):
  2.      last_dll = dbg.get_system_dll(-#ff4500;">1)
  3.      #ff7700;font-weight:bold;">print #483d8b;">"Loading 0x%08x %s" #66cc66;">% (last_dll.base, last_dll.path)
  4.      #ff7700;font-weight:bold;">return DBG_CONTINUE

The hook instances we created get to find the addresses of the APIs RtlAllocateHeap, RtlFreeHeap, RtlReAllocateHeap. If we use Wing (or any capable Python script debugger) and set a breakpoint to halt after this function has been called we are able to print out the addresses:

 #008000;">hex(addrRtlFreeGeap)

In Wing we could continue the execution, or just do something else (in the same function context!). You can have a look at Ricardo's tutorials at this point. They are in Spain. Or at Chuck's translations, but these are in robo-english. - But dumping the heap isn't a problem any more. So far for this journey. If you're fuzzing some processes at some time, maybe in MacOS, Windows 7 or XP... think of this as an opportunity to get good information.

So long,
wishi

Post new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.

Save the nature. Don't print this!


I provide textual exports for every blog entry. However let's save the nature together. The nature is everything around us. Every being should be respected. Save the nature - don't print too much.


Die Umgehung dieser Ausdrucksperre ist nach § 95a UrhG verboten!
Inhaltlich Verantwortlicher gemäß § 10 Absatz 3 MDStV: Marius Ciepluch - Anschrift via eMail. Die eMail Adresse entnehmen sie dem Impresseum dieser englischsprachigen Seite.
Aus Datenschutzgründen habe ich weder offiziellen noch behördlichen Schriftverkehr via eMail. Dazu ist die postalische, beim Dienstleister hinterlegte, Anschrift zu verwenden.

Datenerfassung

Es werden keine personenbezogenen Daten erfasst. Logdaten werden anonymisiert.