LOAD_NAME / LOAD_CONST opcode OOB Read
Last updated
Last updated
AWS हैकिंग सीखें और अभ्यास करें:HackTricks प्रशिक्षण AWS रेड टीम विशेषज्ञ (ARTE) GCP हैकिंग सीखें और अभ्यास करें: HackTricks प्रशिक्षण GCP रेड टीम विशेषज्ञ (GRTE)
यह जानकारी इस लेख से ली गई थी।
हम LOAD_NAME / LOAD_CONST ऑपकोड में OOB पठन की सुविधा का उपयोग कर सकते हैं ताकि हम कुछ प्रतीक मेमोरी में प्राप्त कर सकें। जिसका मतलब है आप चाहते हैं कि किसी प्रतीक (जैसे कि फ़ंक्शन का नाम) को प्राप्त करने के लिए (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__
के रूप में नाम देना आवश्यक नहीं है, आप इसे कुछ छोटा या अधिक अजीब नाम दे सकते हैं।
आप इसके bytecode को देखकर कारण को समझ सकते हैं:
ध्यान दें कि LOAD_ATTR
भी co_names
से नाम प्राप्त करता है। Python नाम को एक ही ऑफसेट से लोड करता है अगर नाम समान है, इसलिए दूसरा __getattribute__
भी ऑफसेट=5 से लोड होता है। इस सुविधा का उपयोग करके हम जब नाम मेमोरी के पास होता है तो एकाधिक नाम का उपयोग कर सकते हैं।
नंबर उत्पन्न करने के लिए सरल होना चाहिए:
0: not [[]]
1: not []
2: (not []) + (not [])
...
मैंने लंबाई सीमा के कारण स्थिरों का उपयोग नहीं किया।
पहले यहाँ एक स्क्रिप्ट है जिसका हमें उन नामों के ऑफसेट पता करने के लिए करना है।
और निम्नलिखित वास्तविक पायथन शोषण उत्पन्न करने के लिए है।
यह मुख्य रूप से निम्नलिखित कार्रवाई करता है, उन स्ट्रिंग्स के लिए जो हम __dir__
विधि से प्राप्त करते हैं:
एडब्ल्यूएस हैकिंग सीखें और प्रैक्टिस करें: HackTricks प्रशिक्षण एडब्ल्यूएस रेड टीम एक्सपर्ट (ARTE) जीसीपी हैकिंग सीखें और प्रैक्टिस करें: HackTricks प्रशिक्षण जीसीपी रेड टीम एक्सपर्ट (GRTE)