Windows中__security_check_cookie与绕过
security_cookie
为了缓解栈溢出漏洞,msvc默认会在函数序言部分放置一个security_cookie(启用GS编译选项)。security_cookie(栈金丝雀)必须放在局部变量和返回地址之间,而不是局部变量之下,否则根本无法检测典型的栈溢出攻击。

在函数结尾部分,会验证这个值:

如果这个值被改变了,程序就会抛出异常:

每次运行程序,这个sercurity_cookie的值都会不同,每次都从rdata节区中选取8字节作为cookie。
关于该值是如何进行计算的,可通过搜索编译器CRT下的gs_support.c和gs_cookie.c文件进行查看了解,会进行如下的运算:
- 获得 system time
- 与 GetCurrentProcessId() 异或
- 与 GetCurrentThreadId() 异或
- 与 GetTickCount() 异或
- 与 QueryPerformanceCounter()异或
绕过
在检查security_cookie之前实现劫持
只有在函数返回处才会检查security_cookie,如果我们可以在返回之前就利用缓冲区溢出劫持程序流程,那么这个GS检查也就没用了。
比如利用虚函数表。下面是一个示例程序:
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <stdio.h>
#include <string.h>
class Vulnerable
{
public:
virtual void foo() { std::cout << "normal" << std::endl; }
};
void exploit()
{
char buffer[8];
Vulnerable obj;
strcpy(buffer, "aaaa");
obj.foo();
}
int main()
{
exploit();
return 0;
}
上面的代码中,buffer发生溢出的话,是可以覆盖vptr的。
txt
0:000>
StackOverFlow!exploit [D:\Project\Reverse\0day\0day\StackOverFlow\BypassCanary.cpp @ 14]:
14 00007ff7`c8322490 4055 push rbp
14 00007ff7`c8322492 57 push rdi
14 00007ff7`c8322493 4881ec28010000 sub rsp,128h
14 00007ff7`c832249a 488d6c2420 lea rbp,[rsp+20h]
14 00007ff7`c832249f 488d7c2420 lea rdi,[rsp+20h]
14 00007ff7`c83224a4 b912000000 mov ecx,12h
14 00007ff7`c83224a9 b8cccccccc mov eax,0CCCCCCCCh
14 00007ff7`c83224ae f3ab rep stos dword ptr [rdi]
14 00007ff7`c83224b0 488b0589bb0000 mov rax,qword ptr [StackOverFlow!__security_cookie (00007ff7`c832e040)]
14 00007ff7`c83224b7 4833c5 xor rax,rbp
14 00007ff7`c83224ba 488985f8000000 mov qword ptr [rbp+0F8h],rax
15732480 00007ff7`c83224c1 488d0db41b0100 lea rcx,[StackOverFlow!_NULL_IMPORT_DESCRIPTOR <PERF> (StackOverFlow+0x2407c) (00007ff7`c833407c)]
15732480 00007ff7`c83224c8 e840edffff call StackOverFlow!ILT+520(__CheckForDebuggerJustMyCode) (00007ff7`c832120d)
15732480 00007ff7`c83224cd 90 nop
16 00007ff7`c83224ce 488d4d28 lea rcx,[rbp+28h]
16 00007ff7`c83224d2 e8dbedffff call StackOverFlow!ILT+685(??0VulnerableQEAAXZ) (00007ff7`c83212b2)
16 00007ff7`c83224d7 90 nop
18 00007ff7`c83224d8 488d152d880000 lea rdx,[StackOverFlow!`string' (00007ff7`c832ad0c)]
18 00007ff7`c83224df 488d4d08 lea rcx,[rbp+8]
18 00007ff7`c83224e3 e886ebffff call StackOverFlow!ILT+105(strcpy) (00007ff7`c832106e)
18 00007ff7`c83224e8 90 nop
19 00007ff7`c83224e9 488d4d28 lea rcx,[rbp+28h]
19 00007ff7`c83224ed e817ecffff call StackOverFlow!ILT+260(?fooVulnerableUEAAXXZ) (00007ff7`c8321109)
19 00007ff7`c83224f2 90 nop
20 00007ff7`c83224f3 488d4de0 lea rcx,[rbp-20h]
20 00007ff7`c83224f7 488d15c2870000 lea rdx,[StackOverFlow!__xt_z+0x220 (00007ff7`c832acc0)]
20 00007ff7`c83224fe e841edffff call StackOverFlow!ILT+575(_RTC_CheckStackVars) (00007ff7`c8321244)
20 00007ff7`c8322503 488b8df8000000 mov rcx,qword ptr [rbp+0F8h]
20 00007ff7`c832250a 4833cd xor rcx,rbp
20 00007ff7`c832250d e83cedffff call StackOverFlow!ILT+585(__security_check_cookie) (00007ff7`c832124e)
20 00007ff7`c8322512 488da508010000 lea rsp,[rbp+108h]
20 00007ff7`c8322519 5f pop rdi
20 00007ff7`c832251a 5d pop rbp
20 00007ff7`c832251b c3 ret