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 गैजेट को निष्पादित नहीं करना चाहिए ताकि यह पुष्टि हो सके कि पिछले ने 6 रजिस्टर को पॉप किया था:
'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
को कॉल करता है) है, इसके बाद स्टैक में प्रविष्टि संख्या जिसे आप जांचना चाहते हैं (शून्य से शुरू) होती है ताकि पहले से सभी PLT प्रविष्टियों को स्कैन किया जा सके:
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)