Stack Pivoting¶
rsp'yi attacker'ın kontrol ettiği birbuffer'a yönlendirerek bir fake stack / ROP chain çalıştırmak; gerçek overflow alanı tam chain'i tutamayacak kadar küçük olduğunda kullanılır.
Mechanism¶
Invariant
ret, pop ve leave, rsp'nin gösterdiği her ne ise onu güvenilir
control data olarak ele alır: ret, [rsp]'e atlar, pop reg, [rsp]'i
tüketir ve leave, mov rsp, rbp; pop rbp yapar. Bu instruction'ların
hiçbiri rsp'nin hâlâ meşru call stack'i gösterdiğini doğrulamaz. Stack
pivoting bunu silaha dönüştürür: attacker rsp'ye kontrol ettiği bir adres
yükleyebilirse, sonraki her ret/pop gerçek stack yerine
attacker'a ait bir fake stack'i dolaşır.
Bu önemlidir çünkü güvenlik açığı olan bir buffer çoğu zaman saved return
address'ten sonra yalnızca birkaç byte bırakır — iki ya da üç halkalı bir
chain için yeterli, ama tam bir ROP payload için değil. Attacker, gerçek
(uzun) chain'i başka bir yere saklar (bir bss buffer, daha önceki bir
read, bir environment variable) ve rsp'yi o daha büyük region'a işaret
eden tek bir pivot gadget çalıştırmak için bu minik pencereyi kullanır.
Oradan tam chain çalışır.
Walkthrough¶
Kavramsal akış; ROP Emporium'un pivot challenge'ını ve herkese açık ctf writeup'larını takip eder. Yaygın pivot gadget'ları ve her birinin ne yaptığı:
| Gadget | Etki | Kaynak register |
|---|---|---|
pop rsp; ret |
rsp ← [rsp] |
sonraki stack qword'ü |
xchg rax, rsp; ret |
rax/rsp swap'ı |
rax (pop rax ile ayarlanır) |
leave; ret |
rsp ← rbp; pop rbp |
kontrol edilen rbp |
add rsp, N; ret |
rsp'yi N kadar kaydır |
sabit offset |
# Small overflow: only room for a 3-link chain.
[ saved_rip ] -> pop rax ; ret # rax = address of large fake stack
-> xchg rax, rsp ; ret # rsp now points into the fake stack
-> (execution continues at the big ROP chain stashed earlier)
leave; ret varyantı özellikle yaygındır: birçok fonksiyon leave; ret ile biter,
dolayısıyla saved rbp'yi (fake_stack - 8) ile overwrite ederek epilogue'un
mov rsp, rbp'si rsp'yi attacker'ın buffer'ına oturtur ve sonraki ret fake
chain'e girer ("stack migration").
Pivot gadget'larını bulma
$ ROPgadget --binary ./pivot | grep -E 'xchg .*rsp|pop rsp|leave ; ret|add rsp'
0x...: xchg rax, rsp ; ret
0x...: leave ; ret
0x...: pop rsp ; ret
address-leak) ya da non-PIE
bir binary'deki sabit bir bss region'ı ile.
Detection¶
rsp'nin thread'in eşlenmiş stack'i olmayan bir region'a (heap,bss, mmap'lıbuffer) atlaması klasik bir anomalidir — EDR / donanımdaki (Intel CET shadow stack) stack-pointer-vs-stack-base kontrolleri bunu işaretler.- Hedefine, shadow stack ile eşleşmeyen bir
rspdeğeri üzerinden ulaşılan birret/call, bir control-protection (#CP) fault'u tetikler. - Bir fonksiyon epilogue'undan sonra
rsp'nin heap/data segment'lerine işaret ettiğini gösteren crash forensics, güçlü bir post-mortem sinyaldir.
Mitigation¶
- Intel CET shadow stack return
address'lerin korumalı bir kopyasını tutar;
rsp'yi saptıran ve forge edilmiş bir adresereteden bir pivot, shadow stack ile uyuşmaz ve fault verir. - Stack canary'ler (FORTIFY/
-fstack-protector) genellikle bir pivot'tan önce gelen lineer overflow'u tespit eder. - ASLR bir leak olmadığı sürece attacker'dan bilinen bir fake-stack adresini esirger; NX fake stack'i shellcode yerine bir ROP chain tutmaya zorlar (pivot'un kendisini durdurmaz, ama sonrasında ne geleceğini kısıtlar).