/GS stack cookie¶
Stack buffer overrun'larından gelen return-address overwrite'larını tespit eden ve fonksiyon return etmeden önce process'i abort eden, MSVC'nin compiler-inserted stack canary'si (
__security_cookie).
Mechanism¶
The invariant
Control flow'u hijack etmek isteyen stack-based bir buffer overrun, x86/x64'te
saved return address'i overwrite etmek zorundadır — ki o, local buffer'lardan
daha yüksek bir address'te, onlar ile caller'ın frame'i arasında oturur. /GS,
stack'e local buffer'lar ile saved return address / frame pointer arasına gizli
bir security cookie yerleştirir. Return address'e ulaşan linear bir overflow,
önce cookie slot'undan geçip onu corrupt etmek zorundadır. Fonksiyon çıkışında
prologue'un store ettiği cookie, per-module master cookie'ye karşı XOR-check edilir;
farklılarsa overrun varsayılır ve corrupt edilmiş return address hiç kullanılmadan
önce process sonlandırılır. Güvenlik, attacker'ın cookie değerini bilmemesine
dayanır (module load'da randomize edilir).
Master cookie, module başına bir kez initialize edilen global bir __security_cookie'dir.
Default CRT entry point'leri (mainCRTStartup, wmainCRTStartup, WinMainCRTStartup,
wWinMainCRTStartup, _DllMainCRTStartup), onu system time, process/thread ID'leri ve
QueryPerformanceCounter gibi kaynaklardan seed eden __security_init_cookie'yi çağırır
— dolayısıyla değer her koşuda ve module'ler arasında farklıdır. x64'te frame unwinding
de cookie'yi yeniden validate eder ve x86'da bir cookie ek olarak bir fonksiyonun
exception handler'ının address'ini de korur (unwind sırasında check edilir).
Compiler yalnızca bir GS buffer içeren fonksiyonları instrument eder: ikiden fazla
non-pointer element'i olan 4 byte'tan büyük bir array, 8 byte'tan büyük pointer-free
bir struct, bir _alloca allocation'ı veya bunlardan birini içeren herhangi bir
aggregate. Parameter overwrite'larını yenmek için prologue ayrıca "vulnerable
parameter"ları (pointer'lar, reference'lar, GS buffer'ları) buffer depolamasının altına
kopyalar, böylece bir overrun kullanımdan önce onlara ulaşamaz.
Walkthrough¶
Vulnerable bir fonksiyon compile edip üretilen cookie mantığını incele. /GS, MSVC'de
default olarak açıktır; /GS- onu devre dışı bırakır.
// gs.c — cl /c /FAsc /O2 gs.c (produces gs.asm)
#include <string.h>
void vulnerable(const char *str) {
char buffer[16];
strcpy(buffer, str); // classic overrun
}
Listing'deki (/FAsc) ilgili prologue/epilogue şöyle görünür:
vulnerable PROC
sub rsp, 38h
mov rax, QWORD PTR __security_cookie ; load per-module master cookie
xor rax, rsp ; mix with frame address
mov QWORD PTR [rsp+28h], rax ; store frame cookie above buffer
... ; strcpy into buffer
mov rcx, QWORD PTR [rsp+28h]
xor rcx, rsp ; un-mix
call __security_check_cookie ; compare vs __security_cookie
add rsp, 38h
ret 0
vulnerable ENDP
__security_check_cookie, geri kazanılan değeri __security_cookie'ye karşı
karşılaştırır; mismatch durumunda bir fast-fail
(__fastfail(FAST_FAIL_STACK_COOKIE_CHECK_FAILURE) / int 29h) yükselten
__report_gsfailure'ı çağırır ve process ölür.
Observed crash at runtime
> gs.exe AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
(1a2c.0b40): Security check failure or stack buffer overrun - code c0000409 (!!! second chance !!!)
Subcode: 0x2 FAST_FAIL_STACK_COOKIE_CHECK_FAILURE
0xC0000409 (STATUS_STACK_BUFFER_OVERRUN) status code'u, tetiklenmiş bir /GS
cookie'sinin (ve genel olarak __fastfail'in) kanonik signature'ıdır.
Cookie sembolünün bir binary'de var olduğunu doğrulamak için import/symbol'leri dump et:
> dumpbin /SYMBOLS gs.obj | findstr security
... __security_cookie
... __security_check_cookie
... __security_init_cookie
Detection¶
0xC0000409(STATUS_STACK_BUFFER_OVERRUN) exception code'u veFAST_FAIL_STACK_COOKIE_CHECK_FAILURE(0x2) subcode'u ile gelen bir crash, tespit edilmiş bir cookie mismatch'inin kernel/WER signature'ıdır.- Bir fonksiyon prologue'unda
__security_cookie/__security_check_cookiereferanslarının ve karakteristikxor rspkarıştırmasının varlığı/GSkapsamını gösterir.
Mitigation¶
/GS yalnızca cookie slot'undan geçen linear overwrite'ları tespit eder. Şunları
durdurmaz:
Known limitations
- Cookie'yi atlayan targeted write'lar (ör. arbitrary write, komşu bir object'e off-by-one, aynı object içinde vtable corruption).
- Cookie disclosure:
__security_cookie'yi leak'lemek (info leak / format string) attacker'ın aynı değeri tekrar yazmasına ve check'i yenmesine izin verir — bkz.stack-canary-leakveformat-string-canary-leak. - Compiler'ın bir GS buffer içermediğine kanaat getirdiği fonksiyonlar instrument edilmeden bırakılır.
Microsoft, /GS'i SEHOP, /SAFESEH, ASLR, Control Flow Guard ve hardware shadow
stack'lerle (CET) katmanlar; böylece bir return-address overwrite bile downstream'de
kısıtlanır.