fatihpurtas/AdminSDHolder-scanner
GitHub: fatihpurtas/AdminSDHolder-scanner
PowerShell 脚本,用于扫描 Active Directory 中受 AdminSDHolder 保护的账户(adminCount=1),检测权限提升风险并导出 CSV 审计报告。
Stars: 1 | Forks: 0
# AdminSDHolder 用户分析脚本
此 PowerShell 脚本用于识别具有 `AdminSDHolder` 保护(`adminCount=1`)的 **Active Directory** 用户,分析其组成员关系以进行高权限检测,过滤掉系统账户和禁用的账户,并将结果导出为 **CSV 报告**。
## 目的
在 Active Directory 中,具有 `adminCount=1` 的用户通常是**受保护组**(例如,Domain Admins、Enterprise Admins)的成员。
即使用户已从这些组中移除,`adminCount=1` 标志通常也会保留。这意味着该账户将继续受到 AdminSDHolder 的保护,保留其以前具有特权时继承的 ACL。
- 检测这些用户并分析其当前的权限状态。
- 根据组成员关系分析对用户进行分类。
- 排除 `krbtgt`、`Administrator`、计算机账户(以 `$` 结尾)和禁用的账户。
- 将剩余需要审查的账户导出为 **CSV 文件**。
## 工作原理
1. 使用启用了**分页**(每页 1000 个对象)的 `DirectorySearcher` 查找所有 `adminCount=1` 的用户,即使是在大型域中也能生效。
2. 收集用户属性:
- **Name**(姓名)
- **SamAccountName**
- **AdminCount**
- **DistinguishedName**
- **Group Memberships**(组成员关系)
- **UserAccountControl**
3. 分析组成员关系以确定权限状态:
- **True**:确认是高权限组的成员(见下方列表)
- **False**:具有组成员身份,但没有任何高权限组
- **No Group Membership**:未找到直接组成员关系(需要手动检查嵌套权限)
4. 评估 `userAccountControl` 以排除被禁用的用户。
5. 排除系统账户(`krbtgt`、`Administrator`、计算机对象),因为这些是默认或服务账户,不代表需要进行安全审查的真实用户账户。
6. 将过滤后的用户导出为 **CSV** 文件。
## 高权限检测逻辑
脚本从每个 `memberOf` 的可分辨名称中提取 `CN`,并将其(精确、不区分大小写)与以下已知的高权限/操作员组进行比较:
- **Domain Admins**、**Enterprise Admins**、**Schema Admins**
- **Administrators**
- **Account Operators**、**Backup Operators**、**Server Operators**、**Print Operators**
- **Key Admins**、**Enterprise Key Admins**
精确的 CN 匹配避免了子字符串匹配可能产生的误报(例如,名称仅包含 "Admins" 的自定义组)。
**重要限制:**
- 仅检测**直接组成员关系**(不包含嵌套的组关系)。
- 标记为 "No Group Membership" 的用户可能仍具有以下权限:
- 嵌套组成员关系
- 主组设置
- 特殊权限或角色
- 历史权限分配
## 输出
脚本会将摘要信息打印到控制台:
- **找到的用户总数**
- **需要审查的用户**
- **CSV 文件名**
CSV 文件命名为:
```
adminsdholder_users_.csv
```
示例:`adminsdholder_users_fatih_local.csv`
### CSV 列
- **Name**:用户的显示名称
- **SamAccountName**:登录名
- **HighPrivilege**:权限状态(True/False/No Group Membership)
- **DistinguishedName**:完整的 AD 路径
- **Groups**:组成员关系列表(或 "No Groups")
- **UserAccountControl**:账户控制标志
- **AdminCount**:AdminSDHolder 标志值
## 示例 CSV 输出
## | Name | SamAccountName | HighPrivilege | DistinguishedName | Groups | UserAccountControl | AdminCount |
|---------------|----------------|----------------------|---------------------------------------------------------|-------------------------------------------|-------------------|------------|
| Fatih Purtaş | fpurtas | True | CN=Fatih Purtaş,OU=Users,OU=IT,DC=fatih,DC=local | CN=Domain Admins,CN=Users,DC=fatih,DC=local; CN=Enterprise Admins,CN=Users,DC=fatih,DC=local; CN=IT-Admin,OU=Groups,DC=fatih,DC=local| 66048 | 1 |
| Kevin Mitnick | kmitnick | False | CN=Kevin Mitnick,OU=Support,OU=Groups,DC=fatih,DC=local | CN=Help Desk,OU=Groups,DC=fatih,DC=local; CN=IT Support,OU=Groups,DC=fatih,DC=local; CN=File Share Users,OU=Groups,DC=fatih,DC=local | 512 | 1 |
| Bruce Schneier| bschneier | No Group Membership | CN=Bruce Schneier,OU=Former\_Employees,DC=fatih,DC=local| No Groups | 512 | 1 |
| Terry Davis | tdavis | True | CN=Terry Davis,OU=Admins,OU=IT,DC=fatih,DC=local | CN=Schema Admins,CN=Users,DC=fatih,DC=local; CN=Exchange Organization Admins,OU=Exchange,DC=fatih,DC=local| 512 | 1 |
| Marcus Hutchins| mhutchins | False | CN=Marcus Hutchins,OU=Marketing,OU=Users,DC=fatih,DC=local| CN=Marketing Team,OU=Groups,DC=fatih,DC=local; CN=Sales Access,OU=Groups,DC=fatih,DC=local; CN=VPN Users,OU=Groups,DC=fatih,DC=local | 66048 | 1 |
## 用法
在 PowerShell 中运行脚本:
```
.\AdminSDHolder.ps1
```
可选参数:
```
# 查询特定的 domain controller 并选择输出路径
.\AdminSDHolder.ps1 -Server dc01.example.com -OutputPath C:\Audit\adminsd.csv
# 将搜索范围限定到特定的 OU
.\AdminSDHolder.ps1 -SearchBase "OU=IT,DC=example,DC=com"
```
| Parameter | Description |
|-----------|-------------|
| `-Server` | 直接查询的域控制器(`dc01.example.com` 或 `:636`)。默认为当前域。 |
| `-SearchBase` | 用于限制搜索范围的可分辨名称。默认为域的默认命名上下文。 |
| `-OutputPath` | CSV 输出路径。默认为 `.\adminsdholder_users_.csv`。 |
如果 PowerShell 执行策略阻止了脚本运行,您可以暂时绕过它们:
```
powershell -ExecutionPolicy Bypass -File "C:\Path\To\AdminSDHolder.ps1"
```
## 示例输出
```
=== ADMINSDHOLDER USER ANALYSIS ===
Total accounts with adminCount=1: 15
Accounts requiring review: 3
- Confirmed high privilege: 1
- No group membership (nested?): 1
CSV file saved (Unicode): .\adminsdholder_users_example_com.csv
```
## 要求与说明
- 不需要额外的 PowerShell 模块。脚本使用**内置的 .NET 类**运行。
- 必须在**加入域**的机器上执行。
- 应手动审查生成的账户,以验证它们是否具有特权访问权限。
- 标记为 "No Group Membership" 的用户需要**进一步调查**其嵌套权限。
## 安全影响
### 为什么这很重要
**AdminSDHolder** 机制旨在通过每 60 分钟应用一次静态访问控制列表(ACL)来保护特权账户(例如,Domain Admins)。
任何具有 `adminCount=1` 的账户都将继承这些保护,使其具有很高的权限并且能够抵抗委派更改。
### 攻击者如何利用它
破坏了低权限账户的攻击者可能会:
- 将该账户添加到受保护组中(例如,Domain Admins)。
- 结果,该账户获得 `adminCount=1` 并继承 AdminSDHolder 保护。
- 即使该账户后来从组中被移除,该标志(`adminCount=1`)通常仍会保持设置状态,从而使该账户具有**持续提升的权限**。
这为攻击者在 AD 环境中创建了一种**隐蔽的持久化机制**。
### 分析结果解读
- **True**:紧急安全问题 - 用户已确认具有高权限。
- **False**:优先级较低 - 用户具有组成员身份,但未检测到高权限。
- **No Group Membership**:**手动审查的高优先级** - 用户可能具有:
- 脚本未检测到的嵌套组权限
- 需要清理的历史权限
- 特殊权限或主组设置
### 缓解措施与最佳实践
- **定期审计**具有 `adminCount=1` 的账户(将此脚本作为安全检查的一部分)。
- 为不再属于特权组的账户**重置 adminCount 值**。
- 这可以通过删除属性并重新应用正常的 ACL 继承来完成。
- 方法 1:使用 PowerShell(需要 AD 模块)
- Set-ADUser -Identity "username" -Clear adminCount
- 方法 2:使用 ADSI Edit
- 打开 ADSI Edit → 连接到默认命名上下文
- 导航到该用户对象
- 右键单击 → 属性 → 找到 "adminCount" 属性
- 删除 adminCount 属性或将其设置为 0
- **手动调查**状态为 "No Group Membership" 的用户,以排查嵌套权限。
- 将受保护组的成员资格**限制**在所需的最低限度内。
- 使用 SIEM 或 AD 审计工具**监控组更改**,以检测可疑的权限提升尝试。
- **实施分层管理**,以减少高价值账户的暴露风险。
标签:Active Directory, AI合规, Libemu, Plaso, Terraform 安全, Windows PowerShell, 多人体追踪, 权限分析, 特权账号发现