BROP - Blind Return Oriented Programming
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
इस हमले का लक्ष्य है बिना किसी जानकारी के ROP का दुरुपयोग करना। यह हमला निम्नलिखित परिदृश्य पर आधारित है:
एक स्टैक भेद्यता और इसे सक्रिय करने का ज्ञान।
एक सर्वर एप्लिकेशन जो क्रैश के बाद पुनः प्रारंभ होता है।
आप इन प्रक्रियाओं के बारे में अधिक जानकारी यहाँ (BF Forked & Threaded Stack Canaries) और यहाँ (BF Addresses in the Stack) पा सकते हैं।
यह गैजेट मूल रूप से यह पुष्टि करने की अनुमति देता है कि ROP गैजेट द्वारा कुछ दिलचस्प निष्पादित किया गया था क्योंकि निष्पादन क्रैश नहीं हुआ। आमतौर पर, यह गैजेट कुछ ऐसा होगा जो निष्पादन को रोकता है और यह ROP श्रृंखला के अंत में स्थित होता है जब एक विशिष्ट ROP गैजेट के निष्पादन की पुष्टि करने के लिए ROP गैजेट्स की खोज की जाती है।
यह तकनीक ret2csu गैजेट का उपयोग करती है। और इसका कारण यह है कि यदि आप कुछ निर्देशों के बीच में इस गैजेट तक पहुँचते हैं तो आपको rsi
और rdi
को नियंत्रित करने के लिए गैजेट मिलते हैं:
ये गैजेट होंगे:
pop rsi; pop r15; ret
pop rdi; ret
ध्यान दें कि इन गैजेट्स के साथ एक फ़ंक्शन को कॉल करने के लिए 2 तर्कों को नियंत्रित करना संभव है।
इसके अलावा, ध्यान दें कि ret2csu गैजेट का बहुत अद्वितीय हस्ताक्षर है क्योंकि यह स्टैक से 6 रजिस्टर को पॉप करेगा। इसलिए एक श्रृंखला भेजना जैसे:
'A' * offset + canary + rbp + ADDR + 0xdead * 6 + STOP
यदि STOP निष्पादित होता है, तो इसका अर्थ है कि एक पता जो स्टैक से 6 रजिस्टर को पॉप कर रहा है का उपयोग किया गया था। या कि उपयोग किया गया पता भी एक STOP पता था।
इस अंतिम विकल्प को हटाने के लिए एक नई श्रृंखला जैसे निम्नलिखित निष्पादित की जाती है और इसे पिछले वाले को पुष्टि करने के लिए STOP गैजेट को निष्पादित नहीं करना चाहिए:
'A' * offset + canary + rbp + ADDR
ret2csu गैजेट का पता जानने पर, यह संभव है कि rsi
और rdi
को नियंत्रित करने के लिए गैजेट्स के पते का अनुमान लगाया जाए।
PLT तालिका को 0x400000 से या स्टैक से लीक किए गए RIP पते से खोजा जा सकता है (यदि PIE का उपयोग किया जा रहा है)। तालिका के प्रविष्टियाँ 16B (0x10B) द्वारा अलग होती हैं, और जब एक फ़ंक्शन को कॉल किया जाता है तो सर्वर क्रैश नहीं होता है भले ही तर्क सही न हों। इसके अलावा, PLT में एक प्रविष्टि के पते की जाँच करना + 6B भी क्रैश नहीं होता क्योंकि यह पहला कोड है जो निष्पादित होता है।
इसलिए, निम्नलिखित व्यवहारों की जाँच करके PLT तालिका को खोजना संभव है:
'A' * offset + canary + rbp + ADDR + STOP
-> कोई क्रैश नहीं
'A' * offset + canary + rbp + (ADDR + 0x6) + STOP
-> कोई क्रैश नहीं
'A' * offset + canary + rbp + (ADDR + 0x10) + STOP
-> कोई क्रैश नहीं
strcmp
फ़ंक्शन रजिस्टर rdx
को तुलना की जा रही स्ट्रिंग की लंबाई पर सेट करता है। ध्यान दें कि rdx
तीसरा तर्क है और हमें इसे 0 से बड़ा होना चाहिए ताकि बाद में write
का उपयोग करके प्रोग्राम को लीक किया जा सके।
हम strcmp
के PLT में स्थान का पता उसके व्यवहार के आधार पर खोज सकते हैं, यह तथ्य का उपयोग करते हुए कि हम अब फ़ंक्शनों के पहले 2 तर्कों को नियंत्रित कर सकते हैं:
strcmp(<non read addr>, <non read addr>) -> क्रैश
strcmp(<non read addr>, <read addr>) -> क्रैश
strcmp(<read addr>, <non read addr>) -> क्रैश
strcmp(<read addr>, <read addr>) -> कोई क्रैश नहीं
इसकी जाँच करने के लिए PLT तालिका के प्रत्येक प्रविष्टि को कॉल करके या PLT धीमी पथ का उपयोग करके किया जा सकता है, जो मूल रूप से PLT तालिका में एक प्रविष्टि को कॉल करना + 0xb (जो dlresolve
को कॉल करता है) और स्टैक में प्रविष्टि संख्या जिसे आप जांचना चाहते हैं (शून्य से शुरू) को स्कैन करने के लिए:
strcmp(<non read addr>, <read addr>) -> क्रैश
b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0x300) + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
-> क्रैश होगा
strcmp(<read addr>, <non read addr>) -> क्रैश
b'A' * offset + canary + rbp + (BROP + 0x9) + p64(0x300) + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
strcmp(<read addr>, <read addr>) -> कोई क्रैश नहीं
b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
याद रखें कि:
BROP + 0x7 pop RSI; pop R15; ret;
की ओर इशारा करता है
BROP + 0x9 pop RDI; ret;
की ओर इशारा करता है
PLT + 0xb dl_resolve को कॉल करने की ओर इशारा करता है।
strcmp
को खोजने के बाद, rdx
को 0 से बड़ा मान सेट करना संभव है।
ध्यान दें कि आमतौर पर rdx
पहले से ही 0 से बड़ा मान रखेगा, इसलिए यह कदम आवश्यक नहीं हो सकता।
अंत में, डेटा को एक्सफिल्ट्रेट करने के लिए एक गैजेट की आवश्यकता होती है ताकि बाइनरी को एक्सफिल्ट्रेट किया जा सके। और इस समय यह संभव है कि 2 तर्कों को नियंत्रित करें और rdx
को 0 से बड़ा सेट करें।
इसके लिए 3 सामान्य फ़ंक्शन हैं जिनका दुरुपयोग किया जा सकता है:
puts(data)
dprintf(fd, data)
write(fd, data, len(data)
हालांकि, मूल पेपर केवल write
का उल्लेख करता है, इसलिए आइए इसके बारे में बात करें:
वर्तमान समस्या यह है कि हमें नहीं पता write फ़ंक्शन PLT के अंदर कहाँ है और हमें नहीं पता डेटा को हमारे सॉकेट पर भेजने के लिए fd संख्या।
हालांकि, हम जानते हैं PLT तालिका कहाँ है और इसके व्यवहार के आधार पर write को खोजना संभव है। और हम सर्वर के साथ कई कनेक्शन बना सकते हैं और एक उच्च FD का उपयोग कर सकते हैं यह उम्मीद करते हुए कि यह हमारे कुछ कनेक्शनों से मेल खाता है।
उन फ़ंक्शनों को खोजने के लिए व्यवहार हस्ताक्षर:
'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0) + p64(0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> यदि डेटा प्रिंट होता है, तो इसका अर्थ है कि puts मिला
'A' * offset + canary + rbp + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> यदि डेटा प्रिंट होता है, तो इसका अर्थ है कि dprintf मिला
'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + (RIP + 0x1) + p64(0x0) + (PLT + 0xb ) + p64(STRCMP ENTRY) + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> यदि डेटा प्रिंट होता है, तो इसका अर्थ है कि write मिला
Original paper: https://www.scs.stanford.edu/brop/bittau-brop.pdf
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)