Skip to content

/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 ve FAST_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_cookie referanslarının ve karakteristik xor rsp karıştırmasının varlığı /GS kapsamı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-leak ve format-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.

References