fatihpurtas/PwdNeverExpires-audit
GitHub: fatihpurtas/PwdNeverExpires-audit
一个基于 PowerShell 的 Active Directory 安全审计脚本,用于检测并导出设置了密码永不过期标志的账户报告。
Stars: 3 | Forks: 0
# 密码永不过期分析器
此 PowerShell 脚本会枚举所有启用了
**“密码永不过期”** 标志的 **Active Directory 用户和计算机账户**,并将结果导出到 CSV 文件。
## 目的
Active Directory 中的 **“密码永不过期”** 标志会带来重大的安全风险,因为这些账户:
- 永远不需要更改密码,可能会无限期地使用弱密码或已泄露的密码
- 可能代表被遗忘的服务账户、废弃的用户账户或配置错误的系统
- 可能被攻击者用作持久化机制,一旦他们攻破了这些账户
- 通常具有提升的权限,但缺乏适当的监控
定期审查和修复具有非过期密码的账户,对于降低持久化威胁风险至关重要。
## 主要特性
- 检测所有具有 **非过期密码** 的 AD 账户(用户和计算机)
- 无需 **Active Directory PowerShell 模块** 即可工作。它仅使用内置的 **System.DirectoryServices** 类,因此可以在无法安装额外模块的受限环境中运行
- 可以在 **没有管理员权限** 的情况下运行;只需要对 AD 的读取权限
- 可以使用 `-Server` 参数指定 **特定的域控制器**
- 分页 LDAP 查询(每页 1000 个对象),适用于大型域
- 将结果导出为 CSV,包含:
- 名称
- 类型(用户 / 计算机)
- 已启用(账户已启用或已禁用)
- 创建日期
- 上次登录
- 密码上次设置时间
- 可分辨名称
- CSV 中的所有时间戳均以 **UTC** 格式写入,使用可排序的 `yyyy-MM-dd HH:mm:ss` 格式
- 导出后打印摘要(总计、已禁用的账户、无记录登录或密码设置日期的账户)
## 工作原理
1. **域检测**:自动检测当前域或接受手动输入(域名或 DN)
2. **LDAP 查询构建**:构建匹配 `userAccountControl` 中 `DONT_EXPIRE_PASSWORD` (65536) 位的 LDAP 过滤器
3. **数据收集**:在单个分页搜索中检索名称、DN、创建时间戳、上次登录、密码上次设置时间和账户状态,无需逐个对象进行往返查询
4. **日期处理**:将 FileTime 和 GeneralizedTime 值转换为可读的 UTC 时间戳
5. **CSV 导出**:生成使用 UTF-8 编码的报告
**注意**:如果未指定 `-IncludeUsers` 或 `-IncludeComputers`,则默认两者都包含。
## 参数
| 参数 | 描述 |
|-----------|-------------|
| `-DomainInput` | 域名 (`example.com`) 或可分辨名称 (`DC=example,DC=com`)。省略时提示输入,默认为当前域。 |
| `-Server` | 可选的直接查询的域控制器 (`dc01.example.com` 或 `dc01.example.com:636`)。 |
| `-OutputPath` | CSV 输出路径。默认为 `.\PwdNeverExpires_.csv`。 |
| `-IncludeUsers` | 仅查询用户账户。 |
| `-IncludeComputers` | 仅查询计算机账户。 |
## 用法
### 交互模式
提示选择域并包含所有账户类型:
```
.\PwdNeverExpires.ps1
```
### 特定域分析
```
.\PwdNeverExpires.ps1 -DomainInput "example.com"
```
### 仅用户
```
.\PwdNeverExpires.ps1 -IncludeUsers -OutputPath "C:\Audit\UsersNeverExpire.csv"
```
### 仅计算机
```
.\PwdNeverExpires.ps1 -IncludeComputers -DomainInput "subsidiary.company.com"
```
### 跨域分析
```
.\PwdNeverExpires.ps1 -DomainInput "DC=remote,DC=domain,DC=com" -IncludeUsers
```
### 查询特定域控制器
```
.\PwdNeverExpires.ps1 -DomainInput "example.com" -Server "dc01.example.com"
```
## 示例输出
| 名称 | 类型 | 已启用 | 创建时间 | 上次登录 | 密码上次设置时间 | 可分辨名称 |
|------|------|---------|----------|-----------|------------|-------------------|
| ServiceAccount | User | True | 2020-01-15 08:30:00 | 2025-01-20 14:22:15 | 2020-01-15 08:30:00 | CN=ServiceAccount,OU=Service_Accounts,DC=company,DC=com |
| LegacyApp | User | False | 2018-05-10 12:00:00 | | 2018-05-10 12:00:00 | CN=LegacyApp,OU=Applications,DC=company,DC=com |
| AdminUser | User | True | 2019-03-20 09:15:30 | 2025-01-25 11:45:22 | 2019-03-20 09:15:30 | CN=AdminUser,OU=Administrators,DC=company,DC=com |
| TestComputer$ | Computer | True | 2021-07-08 16:20:00 | 2024-12-15 10:30:45 | 2021-07-08 16:20:00 | CN=TestComputer,OU=Workstations,DC=company,DC=com |
## 要求与注意事项
- **PowerShell 5.1 或更高版本**(使用 .NET DirectoryServices 类)
- **加入域的机器**或与目标域的网络连接
- 对 Active Directory 的 **读取权限**(通常 Domain Users 足矣)
- 端口 389(或 LDAPS 使用 636)上的 **LDAP 连接**
- `lastLogon` 不会在域控制器之间复制;`lastLogonTimestamp`(优先使用)会被复制,但可能比实际的上次登录时间滞后最多 14 天
## 安全影响
### 常见攻击场景
针对密码永不过期账户的攻击者通常遵循以下模式:
1. **服务账户攻陷**:通过凭证填充或密码喷洒,以具有永不过期密码的服务账户为目标
2. **休眠账户利用**:发现废弃的账户,将其作为进入环境的后门
3. **横向移动**:使用被攻陷的永不过期账户遍历网段
4. **建立持久化**:通过不需要更改密码的账户维持长期访问权限
这造成了一个长期保持稳定的 **持久化攻击面**。
### 缓解措施与最佳实践
- 为所有服务账户进行 **定期密码轮换**(尽可能使用组托管服务账户)
- **账户生命周期管理**,以识别和禁用休眠账户:
```
$Results = Import-Csv .\PwdNeverExpires_example_com.csv
$StaleAccounts = $Results | Where-Object {
-not $_.LastLogon -or [datetime]$_.LastLogon -lt (Get-Date).AddDays(-90)
}
```
- **权限审查**,确保账户具有所需的最低权限
- **实施监控**,针对这些账户的异常登录模式:
- 为永不过期账户在非工作时间登录设置警报
- 监控服务账户上的多次失败登录尝试
- 跟踪这些账户的提权尝试
- 与组织密码策略保持 **合规性一致**
- 尽可能实施 **组托管服务账户 (gMSA)**,以完全消除静态密码
标签:Active Directory, AI合规, Checkov, IPv6, LDAP查询, Libemu, MSSQL, Plaso, PowerShell, Terraform 安全, 多人体追踪, 密码策略审计, 系统运维