LOAD_NAME / LOAD_CONST opcode OOB Read
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)
यह जानकारी इस लेख से ली गई है.
हम LOAD_NAME / LOAD_CONST opcode में OOB read फीचर का उपयोग करके मेमोरी में कुछ प्रतीक प्राप्त कर सकते हैं। इसका मतलब है (a, b, c, ... सैकड़ों प्रतीक ..., __getattribute__) if [] else [].__getattribute__(...)
जैसे ट्रिक का उपयोग करके आप जिस प्रतीक (जैसे फ़ंक्शन का नाम) को चाहते हैं, उसे प्राप्त करना।
फिर बस अपने एक्सप्लॉइट को तैयार करें।
स्रोत कोड काफी छोटा है, केवल 4 पंक्तियाँ हैं!
आप मनमाने Python कोड को इनपुट कर सकते हैं, और इसे Python कोड ऑब्जेक्ट में संकलित किया जाएगा। हालाँकि, उस कोड ऑब्जेक्ट के co_consts
और co_names
को eval करने से पहले एक खाली ट्यूपल के साथ बदल दिया जाएगा।
इस प्रकार, सभी अभिव्यक्तियाँ जो consts (जैसे, संख्याएँ, स्ट्रिंग आदि) या नाम (जैसे, वेरिएबल, फ़ंक्शन) शामिल करती हैं, अंत में सेगमेंटेशन फॉल्ट का कारण बन सकती हैं।
सेगफॉल्ट कैसे होता है?
आइए एक सरल उदाहरण से शुरू करते हैं, [a, b, c]
निम्नलिखित बाइटकोड में संकलित हो सकता है।
लेकिन अगर co_names
खाली ट्यूपल बन जाए? LOAD_NAME 2
ऑपकोड अभी भी निष्पादित होता है, और उस मेमोरी पते से मान पढ़ने की कोशिश करता है जहाँ इसे मूल रूप से होना चाहिए था। हाँ, यह एक आउट-ऑफ-बाउंड पढ़ने की "विशेषता" है।
समाधान का मूल सिद्धांत सरल है। CPython में कुछ ऑपकोड जैसे LOAD_NAME
और LOAD_CONST
OOB पढ़ने के प्रति संवेदनशील (?) हैं।
वे consts
या names
ट्यूपल से oparg
के इंडेक्स से एक ऑब्जेक्ट प्राप्त करते हैं (यही co_consts
और co_names
के तहत नामित हैं)। हम LOAD_CONST
के बारे में निम्नलिखित छोटे स्निप्पेट का संदर्भ ले सकते हैं ताकि यह देख सकें कि CPython LOAD_CONST
ऑपकोड को प्रोसेस करते समय क्या करता है।
इस तरह हम OOB फीचर का उपयोग करके मनमाने मेमोरी ऑफसेट से "नाम" प्राप्त कर सकते हैं। यह सुनिश्चित करने के लिए कि इसमें क्या नाम है और इसका ऑफसेट क्या है, बस LOAD_NAME 0
, LOAD_NAME 1
... LOAD_NAME 99
... को आजमाते रहें। और आप लगभग oparg > 700 में कुछ पा सकते हैं। आप निश्चित रूप से gdb का उपयोग करके मेमोरी लेआउट को देखने की कोशिश कर सकते हैं, लेकिन मुझे नहीं लगता कि यह अधिक आसान होगा?
एक बार जब हम नामों / कॉन्स्ट के लिए उन उपयोगी ऑफसेट को प्राप्त कर लेते हैं, तो हम उस ऑफसेट से नाम / कॉन्स्ट कैसे प्राप्त करते हैं और इसका उपयोग करते हैं? आपके लिए एक ट्रिक है:
मान लीजिए कि हम ऑफसेट 5 (LOAD_NAME 5
) से __getattribute__
नाम प्राप्त कर सकते हैं जिसमें co_names=()
है, तो बस निम्नलिखित कार्य करें:
ध्यान दें कि इसे
__getattribute__
के रूप में नामित करना आवश्यक नहीं है, आप इसे कुछ छोटा या अजीब नाम दे सकते हैं
आप इसके बाइटकोड को देखकर इसके पीछे का कारण समझ सकते हैं:
ध्यान दें कि LOAD_ATTR
भी co_names
से नाम प्राप्त करता है। यदि नाम समान है, तो Python उसी ऑफसेट से नाम लोड करता है, इसलिए दूसरा __getattribute__
अभी भी offset=5 से लोड होता है। इस विशेषता का उपयोग करके, हम मनमाने नाम का उपयोग कर सकते हैं जब नाम पास की मेमोरी में हो।
संख्याएँ उत्पन्न करना तुच्छ होना चाहिए:
0: not [[]]
1: not []
2: (not []) + (not [])
...
मैंने लंबाई सीमा के कारण consts का उपयोग नहीं किया।
पहले, यहाँ एक स्क्रिप्ट है जो हमें उन नामों के ऑफसेट खोजने में मदद करेगी।
और निम्नलिखित असली Python एक्सप्लॉइट उत्पन्न करने के लिए है।
यह मूल रूप से निम्नलिखित चीजें करता है, उन स्ट्रिंग्स के लिए जिन्हें हम __dir__
विधि से प्राप्त करते हैं:
AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE) GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)