
एक शून्य-प्रतीक स्थैतिक विश्लेषण इंजन जो AHP-आधारित जोखिम मॉडल का उपयोग करके विंडोज़ RPC आक्रमण सतह को निकालता है और गणितीय रूप से रैंक करता है।
Static बनाम dynamic, पहले यह पढ़ें। शुरू में dynamic और static विश्लेषण के बीच की रेखा को स्पष्ट करना उचित है: यह टूल अपनी रैंकिंग पूरी तरह से static analysis के माध्यम से करता है। यह बाइनरी से सीधे संकलित MIDL / NDR संरचनाओं को पढ़ता है और कभी भी कुछ निष्पादित नहीं करता है।
Windows RPC आक्रमण सतह के लिए स्टैटिक ट्राइएज। इसे PE बाइनरीज़ के फ़ोल्डर पर इंगित करें; यह उन सभी को ढूँढता है जो RPC सर्वर पंजीकृत करते हैं, संकलित MIDL संरचनाओं से सीधे प्रत्येक इंटरफ़ेस के NDR method signatures, transport bindings और registration flags को पुनर्प्राप्त करता है, और फिर प्रत्येक इंटरफ़ेस को reachability x danger द्वारा रैंक करता है, जिसमें हर स्कोर के साथ पूरी अंकगणितीय रसीद जुड़ी होती है ताकि आप गणित की जाँच हाथ से कर सकें।
मौजूदा RPC टूलिंग आसानी से किसी इंटरफ़ेस की method signatures और उसके registration flags को पुनर्प्राप्त कर सकती है। लेकिन उनमें से कोई भी दोनों को लेकर उस एक प्रश्न का उत्तर नहीं देता जो वास्तव में तय करता है कि आप अपना समय कहाँ बिताते हैं: यह देखते हुए कि मैं इस इंटरफ़ेस तक पहुँच सकता हूँ, और यह देखते हुए कि इसके तरीके इनपुट के रूप में क्या स्वीकार करते हैं, मुझे मशीन पर बाकी सब चीज़ों की तुलना में इसे कितनी तत्काल देखना चाहिए? यही अंतर इस टूल को भरता है।
फ़िल्टर करता है लक्ष्य फ़ोल्डर को ताकि Ghidra केवल उन बाइनरीज़ का ऑटो-विश्लेषण करे जो वास्तव में RPC सर्वर पंजीकृत करती हैं (वे rpcrt4.dll import करती हैं और RpcServerRegisterIf\* APIs में से एक को कॉल करती हैं)। System32 पर यह एक दोपहर और एक सप्ताह के बीच का अंतर है।
निकालता है, प्रति इंटरफ़ेस: UUID, RPC_SERVER_INTERFACE / MIDL_SERVER_INFO श्रृंखला, आधिकारिक DispatchTableCount, हर method का opnum + parameter directions + डिकोड किए गए NDR opcodes, registration flags (R9), security-callback ("bouncer") की उपस्थिति, security descriptor (best-effort), और endpoint / transport bindings।
रैंक करता है प्रत्येक स्वच्छ इंटरफ़ेस को दो स्वतंत्र अक्षों पर और उन्हें गुणा करके एक 0-100 समग्र स्कोर में बदलता है, जिसे Critical / High / Moderate / Low में वर्गीकृत किया जाता है।
स्वयं को स्पष्ट करता है: हर स्कोर के साथ एक रसीद स्ट्रिंग होती है जिसमें प्रत्येक घटक और वह अंकगणित सूचीबद्ध होता है जिसने अंतिम संख्या उत्पन्न की।
target dir --(pefile filter) --> only RPC-registering PEs
--(Ghidra headless auto-analysis) --> analyzed program DB
--(extract_rpc_interfaces.py script) --> interfaces + NDR + flags + endpoints
--(two-axis AHP ranking engine) --> ranked interfaces + receipts
--> single JSON report
शून्य-प्रतीक निर्भरता: इस इंजन का एक महत्वपूर्ण तकनीकी विभेदक यह है कि यह पूरी तरह से debug symbols के बिना काम करता है। dispatch tables को प्रोग्रामेटिक रूप से ट्रैवर्स करके और raw NDR (Network Data Representation) बाइटकोड्स और संकलित MIDL संरचनाओं को सीधे मेमोरी से पार्स करके, टूल Microsoft के .pdb फ़ाइलों या लाइव endpoint mapper क्वेरी की आवश्यकता को दरकिनार कर देता है। यह सुनिश्चित करता है कि इंजन stripped, production System32 बाइनरीज़ पर बिल्कुल वैसे ही out-of-the-box काम करता है जैसे वे वितरित की जाती हैं।
Ghidra 11.x (बंडल किए गए support/analyzeHeadless का उपयोग करता है)। PATH पर JDK 17+ की आवश्यकता है।
ड्राइवर पक्ष पर Python 3.8+, साथ में pefile।
निष्कर्षण स्क्रिप्ट Ghidra के बंडल किए गए Jython 2.7 के अंतर्गत चलती है - कोई तृतीय-पक्ष import नहीं, वहाँ स्थापित करने के लिए कुछ नहीं।
लक्ष्य: Windows x64 PE फ़ाइलें। विश्लेषण स्वयं OS-स्वतंत्र है (Ghidra क्रॉस-प्लेटफ़ॉर्म है), इसलिए आपको इसे Windows पर चलाने की आवश्यकता नहीं है।
git clone https://github.com/talha-nazeef-ahmed/RPC-Triage
cd RPC-Triage/
python -m pip install -r requirements.txt # just pefile
requirements.txt: pefile>=2023.2.7
सब कुछ orchestrator.py द्वारा संचालित होता है: यह आपके लिए फ़िल्टर करता है, import करता है, विश्लेषण करता है और निष्कर्षणकर्ता चलाता है।
python orchestrator.py \
-t \"C:\Windows\System32\" \
-g \"C:\ghidra_12.1.2_PUBLIC\" \
-s \".\extract_rpc_interfaces.py\" \
-o \".\out\report.json\" \
--stagedir \".\out\staged\" \
--projdir \".\out\ghidra_proj\" \
--projname RPC_Atlas
पहली बार चलाना बनाम फिर से चलाना (महत्वपूर्ण)। पहली बार चलाना धीमा हिस्सा करता है: यह फ़िल्टर करता है, मिलान करने वाली बाइनरीज़ import करता है, पूर्ण ऑटो-विश्लेषण चलाता है, फिर --projdir में एक .analysisComplete मार्कर छोड़ता है। उसी प्रोजेक्ट पर हर बाद का रन import/विश्लेषण (-process -noanalysis) को छोड़ देता है और केवल पहले से विश्लेषित प्रोग्रामों पर स्क्रिप्ट को फिर से चलाता है। इसलिए System32 का विश्लेषण एक बार की लागत है और आउटपुट पर पुनरावृत्ति सस्ती है। यदि विश्लेषण बाधित होता है तो मार्कर नहीं लिखा जाता और आंशिक प्रोजेक्ट (.rep / .gpr) को हटाकर नए सिरे से शुरू किया जाता है।
एक JSON फ़ाइल: बाइनरीज़ की एक सूची, प्रत्येक में एक Interfaces सरणी होती है। System32 पर एक पूर्ण रन इस रिपॉजिटरी में output/FullBatchRun.json पर शामिल है - यह कच्चा, बिना क्यूरेट किया हुआ आउटपुट है, ताकि आप देख सकें कि टूल बड़े पैमाने पर वास्तव में क्या उत्पन्न करता है। प्रति इंटरफ़ेस:
टैग; डेटा-स्वच्छता द्वार:
Clean: स्वच्छ रूप से पुनर्प्राप्त; सामान्य रूप से रैंक किया गया।
Needs-Review: रैंक किया गया, लेकिन dispatch table ट्रैवर्सल संग्रहीत गणना से अधिक निकल गया (आमतौर पर एक trailing thunk block)। स्कोर वास्तविक है लेकिन [Provisional] के साथ आता है; उद्धृत करने से पहले method गणना सत्यापित करें।
Diagnostics / Diagnostics (2): यह पंक्ति एक निष्कर्षण कलाकृति है (UUID के रूप में गलत तरीके से पहचाना गया एक ASCII स्ट्रिंग और/या एक दूषित MIDL पॉइंटर)। स्कोर नहीं किया गया (Rank: N/A)। इन्हें जानबूझकर रखा गया है: ये टूल के स्वास्थ्य की रिपोर्ट करते हैं, आक्रमण सतह नहीं हैं।
यह FLAG: Walked X != Stored Y नोट। संग्रहीत DispatchTableCount आधिकारिक है और हर स्कोर इसी का उपयोग करता है। walked गणना एक स्वतंत्र निष्पादन-क्षमता क्रॉस-चेक है; जब दोनों असहमत होते हैं (आमतौर पर एक स्वच्छ 2x) तो इंटरफ़ेस को Needs-Review टैग किया जाता है ताकि आप उस पर नज़र डालें। यह कभी भी चुपचाप स्कोर नहीं बदलता।
यह वह हिस्सा है जो स्कोर को तर्क-योग्य बनाता है:
Moderate/35 | Gate:35 [ncacn_np:41, MultiEndpointBonus:15, HasBouncer:-46, BouncerIsNotCaching:25] | Surface:100 [HasBogusStruct:1x(opnums 5):[in]:61, HasCallerSizedBuffer:5x(opnums 0,6,11):[in]:49, InPtrs:6:18, Count:12:6 -> raw:134 [capped to 100] * 1.0 -> 100] | (35 * 100) / 100 = 35 [Provisional]
इसे बाएँ से दाएँ पढ़ें:
Moderate/35: टियर और समग्र स्कोर।
Gate:35 [...]: पहुँच-क्षमता (reachability) अक्ष। यह ट्रांसपोर्ट बेस (ncacn_np:41, एक named pipe) से शुरू होता है, फिर प्रत्येक पंजीकरण संशोधक को उसके चिह्नित योगदान के साथ सूचीबद्ध करता है: MultiEndpointBonus:15 (कई ट्रांसपोर्ट पर पंजीकृत), HasBouncer:-46 (एक सुरक्षा कॉलबैक मौजूद है, जो पहुँच-क्षमता को कम करता है), और BouncerIsNotCaching:+25। जोड़कर फिर [5,100] पर क्लैंप किया जाता है -> 35।
Surface:100 [...]: खतरा (danger) अक्ष। प्रत्येक सक्रिय सिग्नल Name:count x(opnums):direction:weight है, जैसे HasBogusStruct 1 पैरामीटर (opnums 5) पर सक्रिय हुआ और इसका भार 61 है। फिर एक गणना-आधारित योगदान: InPtrs:6:18 = 6 कॉलर-नियंत्रित in-pointers जो +18 जोड़ते हैं, Count:12:6 = 12 methods ने +6 जोड़ा। पूर्व-कैप योग है, , विश्वास गुणक है (signatures अनिश्चित होने पर 0.5 तक गिर जाता है); अंतिम Surface ।
एक दूसरा उदाहरण जो क्लैंप और कम-विश्वास छूट दिखाता है:
Low/3 | Gate:5 [Dynamic / epmapper:29, LocalCallOnly:-100, SecureOnly:-65, HasBouncer:-46, BouncerIsNotCaching:25] | Surface:50 [... -> raw:140 [capped to 100] * 0.5 -> 50] | (5 * 50) / 100 = 3
अकेला LocalCallOnly:-100 गेट को शून्य से नीचे धकेल देता है, इसलिए यह 5 की निचली सीमा पर क्लैंप हो जाता है; signatures अनिश्चित थे इसलिए Surface आधा कर दिया गया (* 0.5); composite 3 पर पहुँचता है। खतरनाक इनपुट स्पेस, लेकिन प्रभावी रूप से अगम्य -> सही ढंग से प्राथमिकता से बाहर कर दिया गया।
Critical >= 75, High >= 50, Moderate >= 25, अन्यथा Low (शून्य पुनर्प्राप्त सतह वाला इंटरफ़ेस गेट की परवाह किए बिना Low होता है)। थ्रेशोल्ड composite पर टिके होते हैं; उनके पीछे का मॉडल docs/Surface_Scoring_Methadology.md में है।
सभी तीन भार तालिकाएँ (transport bases, gate modifiers, surface signals) Analytic Hierarchy Process से व्युत्पन्न की गई हैं; pairwise comparisons, geometric-mean weights, और एक मापा स्थिरता अनुपात। पूर्ण व्युत्पत्ति, matrices, स्थिरता संख्याएँ और हाथ से बनाए गए नोट्स docs/Surface_Scoring_Methadology.md में हैं।
अतः निष्कर्षण केवल स्व-पुष्टि नहीं है: इस टूल द्वारा पुनर्प्राप्त इंटरफ़ेसों को एक स्वतंत्र, सुस्थापित RPC IDL extractor (James Forshaw के NtObjectManager में RpcServer parser) के विरुद्ध क्रॉस-चेक किया गया था, जिसे उन्हीं बाइनरीज़ पर चलाया गया था। lsass, samsrv और winlogon के लिए संदर्भ dumps validation/ में हैं, और पूर्ण walkthrough validation/VALIDATION.md में है। उनमें से किसी की तुलना output/FullBatchRun.json में मिलान बाइनरी से करें: इंटरफ़ेस UUID, method/opnum गणनाएँ और प्रति-पैरामीटर दिशाएँ संरेखित हैं (उदाहरण के लिए, winlogon का 12E65DD8-... इंटरफ़ेस दोनों में पाँच methods, Proc0-Proc4 दिखाता है)। संदर्भ टूल केवल IDL पुनर्प्राप्त करने तक रुकता है; यह टूल उसी पुनर्प्राप्त सतह को लेता है और उसके ऊपर reachability x danger रैंकिंग जोड़ता है। उस प्रोजेक्ट से कोई संबद्धता नहीं है, इसका उपयोग पूरी तरह से एक स्वतंत्र ground-truth जाँच के रूप में किया जाता है।
केवल Static। कुछ भी निष्पादित नहीं किया जाता। पहुँच-क्षमता पंजीकरण से अनुमानित की जाती है, रनटाइम पर नहीं।
Needs-Review स्कोर अनंतिम (provisional) हैं जब तक method गणना को देखकर सत्यापित नहीं किया जाता।
यह टूल ALPC/RPC और Windows इंटर्नल्स पर मेरे चल रहे शोध का हिस्सा है। मैं निकट भविष्य में आगे के निष्कर्ष प्रकाशित करूँगा और सहायक टूल जारी करूँगा। यदि आपको यह उपयोगी लगा, तो भविष्य के रिलीज़ के लिए GitHub पर या नीचे मेरे सोशल पर मुझे फॉलो करने पर विचार करें।
उन सिस्टमों पर भेद्यता शोध के लिए एक स्टैटिक ट्राइएज / मैपिंग टूल जिनके आप स्वामी हैं। यह आक्रमण सतह की रिपोर्ट करता है, भेद्यताओं की नहीं। इसके द्वारा हाइलाइट किए गए इंटरफ़ेसों में आपको जो कुछ भी मिले, उसे किसी भी सार्वजनिक विवरण से पहले समन्वित प्रकटीकरण (MSRC) से गुजरना चाहिए।
MIT
| फ़्लैग | अर्थ |
|---|
-t / --target | स्कैन करने के लिए बाइनरीज़ का फ़ोल्डर |
-g / --ghidra | Ghidra इंस्टॉल फ़ोल्डर (जिसमें support/analyzeHeadless होता है) |
-s / --script | extract_rpc_interfaces.py का पथ |
-o / --output | लिखने के लिए JSON रिपोर्ट का पथ |
--stagedir | फ़िल्टर की गई RPC बाइनरीज़ को कॉपी करने का फ़ोल्डर (रखा जाता है) |
--projdir | स्थायी Ghidra प्रोजेक्ट के लिए फ़ोल्डर |
--projname | Ghidra प्रोजेक्ट का नाम (जैसे RPC_Atlas) |
| फ़ील्ड | अर्थ |
|---|
CallSite | RpcServerRegisterIf\* कॉल का पता |
Tag / TagDesc | डेटा-गुणवत्ता बकेट (नीचे देखें) |
Rank | \"{Tier}/{Composite}\", जैसे Critical/91 |
RankDetail | पूर्ण स्कोरिंग रसीद (नीचे देखें) |
UUID | इंटरफ़ेस UUID |
InterfaceAddress / DispatchAddress | पुनर्प्राप्त संरचना पते |
FunctionsCount | आधिकारिक संग्रहीत method गणना; (FLAG: Walked X != Stored Y) ले सकता है |
Endpoints | transport / endpoint bindings |
Security | HasBouncer, SecurityDescriptor, SecureOnly, LocalCallOnly |
Methods | प्रति-opnum पैरामीटर सूची, डिकोड किए गए NDR opcodes के साथ |
raw:134[capped to 100]* 1.0(35 * 100) / 100 = 35 [Provisional]: composite = Gate x Surface / 100. पहुँच-क्षमता और खतरे को गुणा किया जाता है, औसत नहीं, क्योंकि खतरा तभी मायने रखता है जब आप उस तक पहुँच सकते हैं: एक अत्यधिक खतरनाक इंटरफ़ेस जिसे आप छू नहीं सकते, उसे शीर्ष पर नहीं तैरना चाहिए। अंत में [Provisional] फ़्लैग चेतावनी देता है कि गतिशील मेमोरी ट्रैवर्सल संग्रहीत method गणना से थोड़ा मेल नहीं खाता, जिसका अर्थ है कि किसी मानव को सीमाओं को सत्यापित करना चाहिए।