Skip to content

Master/TLS Canary Overwrite

Bir stack overflow, thread'in TLS'te yerleşik "master" canary'sine ulaşacak kadar uzun olduğunda, saldırgan hem on-stack kopyayı hem de referans değeri overwrite edebilir, böylece forge edilmiş canary yine de __stack_chk_fail'i geçer.

Mechanism

Note

Glibc'nin stack protector'ı bir equality invariant ile çalışır: local buffer'ların üstüne yazılan değer (on-stack canary), Thread-Local Storage'da tutulan per-thread bir referansla eşleşmelidir. x86-64'te bu referans, tcbhead_t'nin stack_guard field'ıdır ve %fs:0x28 üzerinden okunur (x86-32: %gs:0x14). Epilogue, stack kopyasını %fs:0x28 ile karşılaştırır; bir mismatch __stack_chk_fail'i çağırır ve abort eder. Defender'ın kör noktası: bir thread için TLS block, o thread'in stack'ine bitişik olarak allocate edilir. Bu yüzden yeterince büyük bir overflow, TLS'e ulaşıp referans canary'yi de overwrite edebilir. Saldırgan, stack kopyasını ve TLS stack_guard'ını aynı seçili değere ayarlarsa, karşılaştırma başarılı olur ve kontrol sessizce yenilir — gerçek canary'nin leak edilmesine gerek kalmaz.

Master canary, _dl_setup_stack_chk_guard() / THREAD_SET_STACK_GUARD aracılığıyla kernel'in sağladığı rastgelelikten (_dl_random) bir kez initialize edilir ve düşük byte'ı 0x00'dır, böylece string işlemleri onun üzerinde truncate olur (bu da onu string read'leri ile leak etmeyi zorlaştırır).

Walkthrough

Değerlerin yaşadığı yer (x86-64):

__stack_chk_guard  -> process master value (non-threaded path)
%fs:0x28           -> tcbhead_t.stack_guard  (per-thread reference)
[ ... buffer ... ][ saved canary ]   <- on-stack copy compared in epilogue

Function epilogue (kavramsal, GCC'nin emit ettiği şekliyle):

        mov   rax, [rbp-0x8]
        xor   rax, fs:0x28        ; compare on-stack copy to TLS reference
        je    .ok                 ; equal -> canary intact
        call  __stack_chk_fail    ; mismatch -> abort
.ok:    ; ... normal return ...

Warning

Her ikisini de overwrite etme tekniği yalnızca overflow primitive'i, vulnerable buffer'dan saved canary üzerinden thread'in TLS stack_guard'ına kadar uzanacak kadar uzun ve bitişik olduğunda geçerlidir. Bu, spawn edilen thread'ler için thread-stack/TLS bitişikliğinin bir özelliğidir; burada kavramsaldır, hazır bir exploit değil. Daha basit, daha yaygın bypass bir stack canary leak'tir — referansı yeniden yazmak yerine değeri okumak.

İki ayrı bypass ailesi
1. Leak then reuse:   info-leak the canary, write it back verbatim.
                      (see stack-canary-leak, format-string-canary-leak)
2. Overwrite master:  overflow far enough to clobber TLS stack_guard,
                      set on-stack copy == TLS copy == attacker value.
3. Brute force:       fork-without-re-randomize servers -> guess byte by
                      byte (see byte-by-byte-canary-brute-force).

"master/TLS canary overwrite"in adlandırdığı şey aile (2)'dir: sadece kopya değil, referans da attacker-controlled'dır.

Mitigation

Canary referansını bir overflow'un ulaşabileceği bir şey olarak gör: stack-canaries / stack-protector (-fstack-protector-strong) etkin kalsın ki buffer en azından guard edilsin, ama bunun TLS'in bitişik bir overwrite'ını durdurmadığını kabul et. Layout hardening (stack ve TLS arasına guard page'ler) ve bounds-checked kopyalar (FORTIFY) pencereyi daraltır. Canary, blind overflow'lara karşı savunur; bir leak (ya da ulaşılabilir bir master) onu çökerttiğinden, leak'e dirençli tasarımla birlikte kullan.

References