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 <cstdio>

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:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值