Showing posts with label Debugging. Show all posts
Showing posts with label Debugging. Show all posts

Tuesday, February 2, 2016

Page Heap

A large class of vulnerabilities in software is memory corruptions due to buffer overflows and underflows. An example of this type of vulnerability is an attempt to write more data into a buffer than the size of the buffer itself (buffer overflow). Page Heap is a class of Heap Allocation Policies that can be used when diagnosing or fuzzing for new buffer mismanagement vulnerabilities.

The difficulty of dealing with buffer mismanagement vulnerabilities is that the memory corruption is often not observable at the time that it happens. In the best case, memory gets corrupted badly enough at the time of the corruption, such that the program crashes immediately. In the worst case, although the memory corruption occurred, memory doesn’t get corrupted badly enough at the time of corruption (a “silent” corruption) and therefore there is no immediate crash. Rather the effect of the corruption is observable through some indirect misbehavior of the program later on in execution. An example of this worst case scenario is that an unexpected variable might have its value changed, thereby leading to a different and unexpected code execution path later on. Page Heap is useful for forcing a “fail-fast” policy for memory safety. Page Heap aims to trigger the crash immediately when the memory corruption occurs.

How it Works

In the x86 architecture, Virtual Memory gives each process the appearance that it has 4 GB of address space, whether the memory pages are actually committed or not. When an address on a page that is reserved but not committed is dereferenced, a page fault is generated by the hardware. Page Heap exploits this fact by reserving a guard page at the beginning or end of a page to make sure that any adjacent reads or writes to a buffer cross a page boundary onto a page that is not committed, leading to an immediate page fault.

Guard Pages are Reserved rather than Committed. Using the !address command returns MEM_RESERVE for the State, and PAGE_NOACCESS for the Protection, thereby disallowing reading, writing or executing on the page without taking up any physical memory or space in the page file. Due to the fact that guard pages are inaccessible but are taking up Virtual Address space, Virtual Address space is wasted. For this reason, page heap is useful for debugging, but could lead to problems in a production environment.

For the 3 main types of Heap Policies below, the following code (compiled to PageHeap.exe) will be used as an example, and the “vulnerable line of code here” comment will be replaced by one of the multiple lines of code in each section to trigger the crash.


#include "stdafx.h"

class Buffer
{
public:
       Buffer()
       {
              //initialize our buffers
              memcpy(buffer1, "AAAAAAA", 8);
              memcpy(buffer2, "BBBBBBB", 8);
       }

       char buffer1[8];
       char buffer2[8];
};

void main(int argc, char* argv[])
{
       Buffer * myBuffer = new Buffer(); 
       //vulnerable line of code here

       delete myBuffer;
       while (true){}
}


Full Page Heap

Command: “gflags /p /enable PageHeap.exe /full”

Description:

This Heap Allocation Policy allocates buffers at the END of the memory page. A buffer OVERflow would attempt to access memory PAST the END of the page into the guard page, triggering an immediate page fault.

Vulnerable line of code:


memcpy(myBuffer->buffer2 - 9, myBuffer->buffer1, 8); //Buffer Underflow (write)
memcpy(myBuffer->buffer2 + 1, myBuffer->buffer1, 8); //Buffer Overflow (write)
memcpy(myBuffer->buffer2, myBuffer->buffer1 + 9, 8); //Buffer Overflow (read)


Allocation:
Full Page Heap-allocation at end of page with guard page following

Reverse Page Heap

Command: “gflags /p /enable PageHeap.exe /full /backwards”

Description:

This Heap Allocation Policy allocates buffers at the BEGINNING of the memory page. A buffer UNDERflow would attempt to access memory BEFORE the BEGINNING of the page into the guard page, triggering an immediate page fault. Due to the way Full Page Heap handles Buffer Underflow write, one might expect Reverse Page Heap to catch Buffer Overflow writes, but it does not.

Vulnerable line of code:


memcpy(myBuffer->buffer2, myBuffer->buffer1 - 1, 8); //Buffer Underflow (read)
memcpy(myBuffer->buffer2 - 9, myBuffer->buffer1, 8); //Buffer Underflow (write)


Allocation:
Reverse Page Heap-allocation at beginning of page with guard page preceding

Standard Page Heap

Command: “gflags /p /enable PageHeap.exe”

Description:

This Heap Allocation Policy tries to save Virtual Address space by avoiding allocating extra guard pages for each allocation. Rather, it adds a special pattern before and after each allocation. This allows it to detect Buffer Overflow writes and Buffer Underflow writes, but not Over/Under flow reads of any kind. One noteworthy point is that the integrity of the surrounding patterns are not checked until the buffer is freed. The significance of this fact is that it does not provide a perfect “fail-fast” scenario because a corruption only causes failure on free, not at the time of corruption.

Vulnerable line of code:


memcpy(myBuffer->buffer2 - 9, myBuffer->buffer1, 8); //Buffer Underflow (write)
memcpy(myBuffer->buffer2 + 1, myBuffer->buffer1, 8); //Buffer Overflow (write)


Allocation:
Standard Page Heap-allocation with pattern preceding and following


References:

http://msdn.microsoft.com/en-us/library/ms220938(v=vs.90).aspx

Sunday, June 30, 2013

Heap Debugging Tricks

On Windows, the LFH (Low Fragmentation Heap) is commonly used to dynamically allocate small chunks of memory (<16KB in size). Many programs use the LFH as it is intended for high performance allocation/free of small objects, even in a multithreaded environment. Debugging memory corruptions on the heap can often be complex, but the following Windbg tricks may help:
  • !heap -p -a MEMORY_ADDRESS
This command is extremely useful when tracking down Use-After-Free vulnerabilities in applications. When run on a memory address, there are 2 relevant scenarios:

1) The memory address is inside a current allocation- Windbg displays the call stack that led to the allocation.


2) The memory address is inside an allocation that was freed- Windbg displays the call stack that led to the free.



Using this command requires the page heap to be enabled. Page heap can be enabled per application using the gflags.exe utility that is distributed in the Windbg package.


  • Caller Based Conditional Breakpoint

This Caller Based Conditional Breakpoint is very useful when one is interested in the place where the object gets allocated/freed, especially when the allocation/free codepath is very “hot” (meaning it is executed very often). The idea behind this breakpoint is to only break when there is a certain function (MemberFunction in the example below) on the call stack (ie only break if a certain function called this function directly or indirectly). If a breakpoint is placed on the constructor/destructor of the object’s class, and the object is allocated/freed very often, this could result in the breakpoint getting hit many more times that a human can reasonably look at. For this reason, placing a Caller Based Conditional Breakpoint in the constructor/destructor usually greatly reduces the number of times the breakpoint is hit, allowing a human to reasonably be able to investigate each time the breakpoint is hit. The Caller Based Conditional Breakpoint is of the following format:
bp Module!MyFunctionWithConditionalBreakpoint "r $t0 = 0;.foreach (v { k }) { .if ($spat(\"v\", \"*Module!ClassA:MemberFunction*\")) { r $t0 = 1;.break } }; .if($t0 = 0) { gc }"


  • Register Watching Breakpoint

The Register Watching Breakpoint is a slight variation on the Caller Based Conditional Breakpoint. In the Register Watching Breakpoint, instead of actually breaking when the appropriate caller is on the call stack, the command in Caller Based Conditional Breakpoint is modified to just print the CPU registers (using the ‘r’ command). Very often, in destructors, the address of the object that is being destroyed is in one of the CPU registers. The end result would be that each time the Register Watching Breakpoint is hit, the CPU registers will be printed rather than breaking execution. Since computers are very deterministic machines, if there is no entropy introduced in the program’s execution, one can count the number of times the breakpoint was hit before the object of interest was freed, and predict it the next time the program is run, and eventually get a live debugging session which is watching the object as it is being freed. The Register Watching Breakpoint is of the following format:

bp Module!MyFunctionWithConditionalBreakpoint "r $t0 = 0;.foreach (v { k }) { .if ($spat(\"v\", \"* Module!ClassA:MemberFunction *\")) { r; r $t0 = 1; gc; } }; .if($t0 = 0) { gc }"


References:


Wednesday, December 12, 2012

Windows 8 Kernel Debugging

Starting with Windows Vista, Microsoft changed the Windows Boot Manager, thereby changing the way we debug the Windows Kernel. Now, there is a new tool called bcdedit.exe which can be used to modify the boot configuration of a Windows installation.
The goal is to set up kernel debugging via virtual serial port, on a Windows 8 guest VM running on a Windows 8 host via the built in Hyper-V that comes with Windows 8. The pipe name will be “debug” in this example. The first step is to enable the COM port of the guest VM in the VM’s settings:


Next, enable kernel debugging on the guest VM by running the following commands from an elevated command prompt on the guest:
bcdedit /debug on
bcdedit /dbgsettings serial debugport:1 baudrate:115200
The next step is to prepare the host for debugging the guest VM. The host had the Windows 8 SDK, WDK, Visual Studio 2012, and the Visual Studio 2012 coinstaller installed, in that order. There are 2 ways to debug kernels in guest VMs from a Windows 8 host. The first is to use Visual Studio 2012 (new method), and the second is to Windbg (old method). Visual Studio 2012 now has integrated kernel debugging support using the same debugging engine as Windbg. Once the host machine has everything installed, the steps to debug using Visual Studio 2012, are as follows:
  1. Run Visual Studio 2012 as Administrator
  2. Under the Tools->Attach to Process window, select "Windows Kernel Mode Debugger" for Transport.
  3. Click "Find" next to "Qualifier"
  4. In the "Configure Computers" window use the following settings:
    Transport=Serial
    Port=\\.\pipe\debug
    Baud=115200
 
To use the old Windbg method:
  1. Run Windbg as Admin on the host
  2. Hit ctrl+k to connect to the serial port exposed by the VM
  3. Use the following settings
  
 
 Further Reading:

Tuesday, October 23, 2012

Single Step Debugging Explained



Single Step debugging of machine instructions is a technique often used during vulnerability research and exploit development to debug a program at an atomic level. At this level of granularity, one can see the individual assembly instructions as they are being executed by the CPU chip, and the states of the registers and memory as each instruction is executed.


Single step debugging is supported in part by the operating system and in part by the CPU. On Intel's x86 architecture, the EFLAGS register's bit 8 is the TF(Trap Flag) bit. If this bit is set before an assembly instruction is executed, the CPU raises an exception (Interrupt 1) after the execution of the assembly instruction is completed. Once the CPU raises the exception, the following events happen in order(see Windows Internals 5th Edition, Chapter 3):

  1. The TF bit is cleared. This is why the 3rd least significant digit of "efl" register as displayed in windbg is always an even digit when single stepping. The CPU clears the TF bit before calling the exception handler, which is invoked much before the debugger ever gets it.
  2. The kernel looks up entry number 1 in the system's IDT(Interrupt Descriptor Table).
  3. If a debugger is attached, it is alerted about the single step exception.
  4. If no debugger is attached or the exception is not handled by the debugger, the Operating System's Exception Handling mechanism is invoked.
  5. If the Exception Handling mechanism still does not handle the exception, the debugger is given a second chance to handle the exception.
  6. If no debugger is available, the process is killed.

The following test program manually sets the TF bit in the EFLAGS register:

#include <stdio.h>

void main()
{
    while(1)
    {
        printf("inside loop\n");
        __asm{
            pushfd
            pop eax
            or eax, 0x00000100 //set TF bit in EFLAGS
            push eax
            popfd
        }
    }
}

This program was run with and without a debugger(windbg) attached. When run with a debugger attached, there were no breakpoints set, but single step exceptions were set to be handled, as seen by the following:

0:000> sx
sse - Single step exception - break

When the test program was run with the debugger attached, a single step exception was caught by windbg:

(bf4.d98): Single step exception - code 80000004 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.

This proves that setting the TF flag from within a program will cause an exception that an attached debugger can catch for single stepping. In this case, the exception mentioned in step 3 above is handled by the debugger.

The next experiment was to run the program again, but without a debugger attached. Below is the result:

step 6 was reached, and the process was killed due to the unhandled exception(no debugger to handle it)
 As is clear, single step debugging is supported in part by hardware, and in part by software.

Sources:
Windows Internals 5th Edition, Chapter 3
Intel® 64 and IA-32 Architectures Software Developer’s Manual Combined Volumes: 1, 2A, 2B, 2C, 3A, 3B and 3C