researchgetting from seh to nseh
Exploitation techniques utilizing SE Handler overwrites increase reliability by moving execution flow to the address on the stack where the pointer to the next SEH Record is normally located.
There are several approaches to doing this with the 'POP-POP-RET' being the most popular. Let's see exactly why this approach works and analyze potential alternatives such as JMP DWORD PTR [EBP+0x30], POPAD and ROP.
Stack after SEH overflow
Let's overflow a buffer on the stack and overwrite SE Handler with "CCCC" and the next SEH Record field with "BBBB".
0:000> g
(4f8.9ac): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=7efefefe ebx=7ffdf000 ecx=0012fda0 edx=41414141 esi=0078fec8 edi=00130000
eip=1027d2e9 esp=0012fc1c ebp=0012fe88 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
MSVCR100D!strcat+0x89:
1027d2e9 8917 mov dword ptr [edi],edx ds:0023:00130000=78746341
Here is the SEH chain:
0:000> !exchain
0012fe7c: 43434343
Invalid exception stack at 42424242
Where 42424242 is an NSEH Pointer located at 0012fe7c and 43434343 is the SE Handler we have overwritten located at 0012fe80.
Once the exception occurs, let's continue the execution and observe the stack once the SEH pointer gets executed:
0:000> g
(bf8.4f0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=43434343 edx=7c9032bc esi=00000000 edi=00000000
eip=43434343 esp=0012f84c ebp=0012f86c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
43434343 ?? ???
At the point where we attempt (and fail) to execute SEH pointer at an invalid address of 43434343, the ESP register points to the following addresses on the stack:
0:000> dd /c1 esp
0012f84c 7c9032a8
0012f850 0012f934
0012f854 0012fe7c ; nseh
0012f858 0012f950
0012f85c 0012f908
0012f860 0012fe7c ; nseh
0012f864 7c9032bc
0012f868 0012fe7c ; nseh
0012f86c 0012f91c
0012f870 7c90327a
0012f874 0012f934
0012f878 0012fe7c ; nseh
0012f87c 0012f950
0012f880 0012f908
0012f884 43434343
0012f888 00130000
0012f88c 0012f934
0012f890 0012fe7c ; nseh
0012f894 7c92a8c3
0012f898 0012f934
0012f89c 0012fe7c ; nseh
0012f8a0 0012f950
0012f8a4 0012f908
0012f8a8 43434343
The stack is littered with NSEH pointer addresses (0012fe7c). If we could somehow jump, call or return to an address on the stack which contains 0012fe7c value, then it would be possible to redirect execution flow to the stack where we can place shellcode.
Below are all instances of NSEH pointer address in memory:
0:000> s -d 0x00000000 L?0xffffffff 0012fe7c
0012f810 0012fe7c 7c90e920 7c910328 ffffffff |... ..|(..|....
0012f834 0012fe7c 7c96fd90 00150608 7c96fd74 |......|....t..|
0012f854 0012fe7c 0012f950 0012f908 0012fe7c |...P.......|...
0012f860 0012fe7c 7c9032bc 0012fe7c 0012f91c |....2.||.......
0012f868 0012fe7c 0012f91c 7c90327a 0012f934 |.......z2.|4...
0012f878 0012fe7c 0012f950 0012f908 43434343 |...P.......CCCC
0012f890 0012fe7c 7c92a8c3 0012f934 0012fe7c |......|4...|...
0012f89c 0012fe7c 0012f950 0012f908 43434343 |...P.......CCCC
POP-POP-RET
The most popular way of redirecting the execution to the NSEH pointer is to pop the first DWORDs from the stack into registers and call a value currently pointed by ESP (aka POP POP RET). Below is the location where ESP will point on the stack after popping two values and just before calling RET:
0:000> ?esp + 8
Evaluate expression: 1243220 = 0012f854
0:000> dd /c1 0012f854
0012f854 0012fe7c
After RET instruction is executed, the flow of execution will be redirected to the stack location at the NSEH pointer.
JMP/CALL DWORD PTR [ESP + nn]
Alternatively JMP DWORD PTR [ESP +/- offset] or CALL DWORD PTR [ESP +/- offset] could be used to achieve the same result. In the above example jumps or calls to pointers at ESP + 8, ESP + 14, ESP + 1c, ESP + 2c and so on will also achieve the same effect.
0:000> dd /c1 esp
0012f84c 7c9032a8
0012f850 0012f934
0012f854 0012fe7c ; nseh - esp + 8
0012f858 0012f950
0012f85c 0012f908
0012f860 0012fe7c ; nseh - esp + 14
0012f864 7c9032bc
0012f868 0012fe7c ; nseh - esp + 1c
0012f86c 0012f91c
0012f870 7c90327a
0012f874 0012f934
0012f878 0012fe7c ; nseh - esp + 2c
0012f87c 0012f950
0012f880 0012f908
0012f884 43434343
0012f888 00130000
0012f88c 0012f934
0012f890 0012fe7c ; nseh - esp + 44
0012f894 7c92a8c3
0012f898 0012f934
0012f89c 0012fe7c ; nseh - esp + 50
JMP/CALL DWORD PTR [EBP + nn]
If the use of ESP register is not possible, then EBP could be used as well:
0:000> e ebp
0012f86c 1c
Reference the table below to calculate offsets
0:000> dd /c1 ebp
0012f86c 0012f91c
0012f870 7c90327a
0012f874 0012f934
0012f878 0012fe7c ; nseh - ebp + c (also esp + 2c)
0012f87c 0012f950
0012f880 0012f908
0012f884 43434343
0012f888 00130000
0012f88c 0012f934
0012f890 0012fe7c ; nseh - ebp + 24 (also esp + 44)
0012f894 7c92a8c3
0012f898 0012f934
0012f89c 0012fe7c ; nseh - ebp + 30 (also esp + 50)
Offsets such as EBP + c, EBP + 24, EBP + 30, etc. will do the trick. Naturally it is possible can jump or call backward as well with JMP DWORD PTR [EBP - 4], CALL DWORD PTR [EBP - c] and so on.
POPAD
Another creative way of getting to NSEH pointer is utilizing POPAD instruction. POPAD will pop 7 DWORDS and skip one from the stack and place them into general purpose registers as follows:
EDI ← Pop();
ESI ← Pop();
EBP ← Pop();
increment ESP by 4 (* skip next 4 bytes of stack *)
EBX ← Pop();
EDX ← Pop();
ECX ← Pop();
EAX ← Pop();
On the stack it will look like this
0:000> dd /c1 esp
0012f84c 7c9032a8 ; -----> EDI
0012f850 0012f934 ; -----> ESI
0012f854 0012fe7c ; -----> EBP [ESP + 8]
0012f858 0012f950 ; skipped
0012f85c 0012f908 ; -----> EBX
0012f860 0012fe7c ; -----> EDX [ESP + 14]
0012f864 7c9032bc ; -----> ECX
0012f868 0012fe7c ; <----- EAX [ESP + 1c]
After the execution of the POPAD instruction it is possible to get to NSEH by JMPing or CALLing EBP, EDX or EAX registers. As a complete example, you will need to search the memory for the following sequences of instructions:
POPAD | CALL/JMP EBP
POPAD | CALL/JMP EDX
POPAD | CALL/JMP EAX
ROP
At last, it is possible to redirect the flow of execution to NSEH using Return Oriented Programming (ROP). In fact, POP | POP | RET is a great example of return oriented programming where the value of ESP is incremented with two POPs to point to desired address before calling RET. A few other examples which utilize RET instead of CALLs and JMPs:
POPAD | PUSH [EBP/EDX/EAX] | RET
ADD ESP,[8/14/1c/...] | RET
It is also possible to make a few variations on the classic POP-POP-RET as follows:
ADD ESP,4 | POP REG | RET
POP REG | ADD ESP,4 | RET
Where REG could be any convenient register.
External Links and References
- Exploit writing tutorial part 6 : Bypassing Stack Cookies, SafeSeh, SEHOP, HW DEP and ASLR
- Intel Architecture Software Developer’s Manual - Volume 2
- Defeating the Stack Based Buffer Overflow Prevention Mechanism of Microsoft Windows 2003 Server
- Corelan Mona Project
Special Note
Most of the above approaches can be automatically identified by Corelan's excellent mona.py ImmDbg plugin.
Published on April 25th, 2012 by iphelix
sprawlsimilar
A solution to an exercise in Corelan Tutorial 10 on writing DEP and ASLR bypassing exploits. The solution illustrates grabbing leaked kernel32 address from memory, calculating an offset to VirtualProtect() and at last setting up a ROP chain to make a memory location with shellcode executable. Read more.
A solution to the AIMP2 exercise at the end of the Exploit Writing Tutorial Part 7 by Corelan Team. The solution illustrates a exploitation of Unicode applications using Venetian shellcoding techniques. Read more.
A solution to the MP3 Studio exercise at the end of the Exploit Writing Tutorial Part 3b by Corelan Team. The solution illustrates a sample buffer overflow exploitation of a Windows application. Read more.
