UzmaSami/ADSAE-Custom-PAM-Tool
GitHub: UzmaSami/ADSAE-Custom-PAM-Tool
ADSAE 是一个基于 PowerShell 的 Active Directory 安全自动化引擎,通过监控 Windows 事件日志自动检测并响应暴力破解、权限提升和可疑 PowerShell 活动,以零许可成本替代商业 PAM 方案。
Stars: 0 | Forks: 0
# ADSAE 自定义 PAM 工具
## 概述
本项目记录了 ADSAE — Active Directory Security Automation Engine (Active Directory 安全自动化引擎) — 的设计、开发和生产部署。这是一个基于 PowerShell 的自定义安全自动化平台,每五分钟监控一次 Active Directory 安全事件,并自动修复包括暴力破解攻击、权限提升尝试和可疑 PowerShell 执行在内的威胁。
ADSAE 在项目 0 中记录的 Windows Server 2022 Domain Controller 上投入生产运行。它已经检测并响应了真实的安全威胁。它生成一个动态 HTML 安全仪表板,反映 Active Directory 环境的当前安全状态。它还生成结构化的证据日志,为项目 5 中实施的 Sentinel SOC 提供数据。
商业 Privileged Access Management 解决方案 — CyberArk、BeyondTrust、Delinea — 以企业规模解决此问题,每年的成本从数万到数十万英镑不等。ADSAE 通过用精确校准以应对此环境所面临威胁的自定义自动化替代商业工具,以零许可成本为特定环境解决了这个问题。
## 解决的问题
Active Directory 是企业环境中最容易被攻击的目标。原因很简单 — 它保存着域内每个用户和每个系统的凭据和访问权限。攻破 Active Directory 不是对组织的部分妥协,而是彻底沦陷。
针对 Active Directory 的攻击模式遵循可预测的序列。暴力破解和密码喷洒攻击试图获取有效的凭据。一旦获得有效凭据,攻击者就会提升权限 — 将他们的账户添加到 Domain Admins 或创建一个新的特权账户。拥有 Domain Admin 访问权限后,攻击者可以在环境中自由移动,访问任何系统,并通过能在修复尝试后幸存的机制来维持持久性。
从初始凭据泄露到权限提升之间的窗口期通常很短。拥有有效凭据且能连接到 Domain Controller 的攻击者可以在几分钟内提升权限。因此,安全响应必须在相同的时间尺度上运作 — 以分钟计,而不是小时。依靠分析师阅读警报并采取行动的人工安全流程无法在此窗口期内可靠地做出响应。而自动化响应可以。
ADSAE 通过监控指示这些攻击模式的特定事件日志条目,并在检测到后的几分钟内执行修复来关闭这个窗口期 — 比任何人工操作的流程都要快,并且不需要分析师全天候待命。
## 架构
生产环境
════════════════════════════════════════════
Windows Server 2022 DC (UzmaSamiDC01)
- │
- ├── ADSAE 核心引擎
- │ └── ADSAE-Monitor.ps1
- │ 通过 Task Scheduler 以 SYSTEM 身份运行
- │ 执行间隔:每 5 分钟
- │ 触发器:基于时间 + 基于事件
- │
- ├── 检测模块
- │ │
- │ ├── 模块 1:暴力破解检测
- │ │ 监控:Event ID 4625
- │ │ 阈值:5 分钟内失败 5 次以上
- │ │ 范围:按源 IP + 按目标账户
- │ │ 响应:禁用账户 + 告警
- │ │
- │ ├── 模块 2:权限提升检测
- │ │ 监控:Event ID 4728, 4732, 4756
- │ │ 范围:所有特权组
- │ │ 受保护组:
- │ │ Domain Admins
- │ │ Enterprise Admins
- │ │ Schema Admins
- │ │ Administrators
- │ │ Group Policy Creator Owners
- │ │ 响应:从组中移除 + 告警
- │ │ 白名单:已批准的管理员账户
- │ │
- │ └── 模块 3:可疑 PowerShell
- │ 监控:Event ID 4104
- │ 检测:关键字模式匹配
- │ 关键字:编码命令,
- │ Web 下载,
- │ 执行绕过
- │ 响应:证据捕获 + 告警
- │
- ├── 响应引擎
- │ ├── 账户禁用(立即)
- │ ├── 组成员身份移除(立即)
- │ ├── 证据捕获(取证保留)
- │ ├── 告警生成(通知)
- │ └── 事件日志创建(审计追踪)
- │
- ├── 证据存储
- │ └── C:\UzmaSOC-Logs\
- │ ├── incidents\
- │ │ └── [带时间戳的事件文件]
- │ ├── evidence\
- │ │ └── [PowerShell 脚本捕获]
- │ └── adsae-audit.log
- │
- ├── 仪表板生成器
- │ └── 动态 HTML 仪表板
- │ 每 5 分钟自动刷新
- │ 显示:活跃威胁,近期
- │ 事件,系统状态,
- │ 检测统计信息
- │
- └── AZURE SENTINEL 集成
└── 通过
Log Analytics Agent 转发事件
→ Sentinel 分析规则
引用 ADSAE 事件数据
## 为什么选择自建而不是购买
对于安全工具来说,自建与购买的问题确实很复杂,答案并不总是自建。商业 PAM 解决方案提供了需要数年时间才能在自定义工具中复制的功能 — 会话记录、凭据保险库、即时访问配置以及与企业工单系统的集成。对于具有商业许可预算的大规模组织来说,购买的答案通常是正确的。对于此环境而言,选择自建是正确的,原因有三个。
第一个原因是精准度。商业 PAM 工具旨在解决各种环境和用例中的一般性 PAM 问题。它们带有这种通用性所带来的复杂性和配置开销。ADSAE 旨在解决此特定环境面临的特定威胁模式。每个检测阈值、每个响应动作、每个白名单条目都针对此环境进行了校准。其结果是,与通用解决方案在相同范围内产生的结果相比,该工具的噪音更少,相关信号更多。
第二个原因是可见性。使用商业工具会产生一个黑盒 — 该工具通过操作员无法完全检查的机制来检测威胁并采取行动。ADSAE 是完全透明的 — 每个检测决策、每个响应动作、收集的每一份证据都是在可读的 PowerShell 中实现的,可以进行检查、修改和扩展。准确了解该工具做了什么以及为什么这样做,其本身就是一项安全属性。
第三个原因是学习。构建 ADSAE 需要对 Windows Security Event Log 结构、Active Directory API 操作、PowerShell 自动化模式、取证证据保留以及 Active Directory 攻击中使用的特定技术有深入的了解。这种了解是无法通过配置商业工具来获得的。只能通过从头开始构建检测和响应逻辑来获得。
## 检测逻辑
### 暴力破解检测
暴力破解和密码喷洒攻击在 Windows Security Event Log 中会留下特征性签名。每次身份验证尝试失败时都会生成 Event ID 4625 — 账户登录失败。合法用户忘记密码导致的单次登录失败会生成一两个事件。针对用户的撞库攻击会产生数十个事件。针对整个用户群体的密码喷洒攻击会从单个源 IP 跨越多个账户产生数百个事件。
ADSAE 暴力破解模块使用 5 分钟的滚动窗口监控 Event ID 4625。它分别按源 IP 地址和目标账户汇总失败次数 — 因为喷洒攻击会将失败分散到各个账户上,而撞库攻击则集中在单个账户上。
powershell
function Invoke-BruteForceDetection {
param(
[int]$ThresholdMinutes = 5,
[int]$ThresholdCount = 5
)
```
$startTime = (Get-Date).AddMinutes(
-$ThresholdMinutes
)
# 查询 Security Event Log
$failedLogons = Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 4625
StartTime = $startTime
} -ErrorAction SilentlyContinue
if (!$failedLogons) { return }
# 按 source IP 聚合
$bySourceIP = $failedLogons |
ForEach-Object {
$xml = \[xml\]$_.ToXml()
[PSCustomObject]@{
SourceIP = $xml.Event.EventData.Data |
Where-Object {$_.Name -eq 'IpAddress'} |
Select-Object -ExpandProperty '#text'
TargetUser = $xml.Event.EventData.Data |
Where-Object {$_.Name -eq 'TargetUserName'} |
Select-Object -ExpandProperty '#text'
TimeCreated = $_.TimeCreated
}
} |
Group-Object SourceIP |
Where-Object {$_.Count -ge $ThresholdCount}
foreach ($group in $bySourceIP) {
$affectedAccounts = $group.Group.TargetUser |
Sort-Object -Unique
# Execute response
Invoke-BruteForceResponse `
-SourceIP $group.Name `
-AffectedAccounts $affectedAccounts `
-FailureCount $group.Count
}
```
}
当跨越阈值时,响应模块会立即执行。不在受保护的白名单中的受影响账户将在 Active Directory 中被禁用。将创建一条包含源 IP、受影响账户、失败次数和时间戳的事件记录。该事件将被转发到 Sentinel。
白名单至关重要。如果没有白名单自动禁用账户,将会禁用服务账户、管理员账户以及任何由于应用程序配置错误而可能反复验证失败的账户。白名单包含无论失败模式如何都绝对不应被自动禁用的账户 — 特别是 Azure AD Connect 使用的服务账户、ADSAE 自身的服务账户以及指定的紧急情况账户。
### 权限提升检测
特权组成员身份更改记录在 Event ID 4728 中 — 成员被添加到启用安全性的全局组。每当任何账户被添加到任何安全组时,Active Directory 都会生成此事件。ADSAE 权限提升模块专门筛选那些其成员身份会赋予危险能力的组的添加操作。
powershell
function Invoke-PrivilegeEscalationDetection {
```
$privilegedGroups = @(
'Domain Admins',
'Enterprise Admins',
'Schema Admins',
'Administrators',
'Group Policy Creator Owners',
'Account Operators',
'Backup Operators'
)
# Protected accounts 从未被移除
$approvedAdmins = @(
'Administrator',
'uzma.admin',
'svc-adsae'
)
$startTime = (Get-Date).AddMinutes(-5)
$groupChanges = Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 4728
StartTime = $startTime
} -ErrorAction SilentlyContinue
foreach ($event in $groupChanges) {
$xml = \[xml\]$event.ToXml()
$memberAdded = $xml.Event.EventData.Data |
Where-Object {$_.Name -eq 'MemberName'} |
Select-Object -ExpandProperty '#text'
$targetGroup = $xml.Event.EventData.Data |
Where-Object {$_.Name -eq 'TargetUserName'} |
Select-Object -ExpandProperty '#text'
$subjectUser = $xml.Event.EventData.Data |
Where-Object {$_.Name -eq 'SubjectUserName'} |
Select-Object -ExpandProperty '#text'
# Only respond to privileged group changes
if ($targetGroup -notin $privilegedGroups) {
continue
}
# Extract account name from DN
$accountName = ($memberAdded -split ',')[0] `
-replace 'CN=', ''
# Check against whitelist
if ($accountName -in $approvedAdmins) {
Write-AdsaeLog -Level INFO `
-Message "Approved admin $accountName added to $targetGroup by $subjectUser — no action"
continue
}
# Unauthorised escalation — respond
Invoke-PrivEscResponse `
-AccountName $accountName `
-TargetGroup $targetGroup `
-SubjectUser $subjectUser `
-EventTime $event.TimeCreated
}
```
}
响应会立即将账户从特权组中移除。将创建一条事件记录,捕获被添加的账户、添加到的组、执行添加操作的账户以及时间。此事件记录是允许调查确定这是合法但未经批准的更改还是对抗性权限提升的取证证据。
被添加的账户与执行添加操作的账户之间的区别很重要。在对抗性场景中,主体(即执行添加操作的账户)本身可能已被攻陷。调查被添加的账户和主体账户是权限提升事件的标准做法。
### 可疑 PowerShell 检测
PowerShell 是 Windows 上可用的最强大的管理工具,因此也是被滥用最多的工具之一。它能够从互联网下载内容、在不写入磁盘的情况下从内存执行代码,以及绕过脚本执行策略,这使其成为很大一部分后渗透活动的首选工具。
Event ID 4104 — PowerShell 脚本块日志记录 — 在任何混淆被 PowerShell 引擎解码后,捕获 PowerShell 脚本执行时的内容。这是关键能力。如果攻击者对恶意命令进行 base64 编码以逃避检测,将会发现脚本块日志记录捕获了解码后的版本。这种对命令行日志记录有效的规避技术对脚本块日志记录却无效。
powershell
function Invoke-SuspiciousPowerShellDetection {
```
$suspiciousPatterns = @(
'Invoke-Expression',
'IEX\(',
'IEX \(',
'DownloadString',
'DownloadFile',
'WebClient',
'Net\.WebClient',
'EncodedCommand',
'enc ',
'FromBase64String',
'-ExecutionPolicy Bypass',
'-ep bypass',
'Hidden',
'WindowStyle Hidden',
'Start-Process.*-WindowStyle',
'Invoke-Shellcode',
'Invoke-Mimikatz',
'Invoke-BloodHound',
'PowerSploit',
'Empire'
)
$startTime = (Get-Date).AddMinutes(-5)
$psEvents = Get-WinEvent -FilterHashtable @{
LogName = 'Microsoft-Windows-PowerShell/Operational'
Id = 4104
StartTime = $startTime
} -ErrorAction SilentlyContinue
foreach ($event in $psEvents) {
$scriptContent = $event.Message
$detectedPatterns = $suspiciousPatterns |
Where-Object {
$scriptContent -match \[regex\]::Escape($_)
}
if ($detectedPatterns.Count -eq 0) {
continue
}
# Capture evidence
$evidencePath = "C:\UzmaSOC-Logs\evidence\" +
"ps-$(Get-Date -Format 'yyyyMMdd-HHmmss').txt"
@"
```
ADSAE POWERSHELL 证据捕获
时间: $(Get-Date)
检测到的模式: $($detectedPatterns -join ', ')
脚本内容:
$scriptContent
"@ | Out-File $evidencePath -Encoding UTF8
```
# Create incident
New-AdsaeIncident `
-Type 'SuspiciousPowerShell' `
-Severity 'Medium' `
-Details @{
PatternsDetected = $detectedPatterns
EvidencePath = $evidencePath
EventTime = $event.TimeCreated
}
}
```
}
PowerShell 的响应是捕获证据,而不是自动执行账户操作。这是一个有意的设计决定。匹配到可疑模式的 PowerShell 不一定就是恶意的 — 合法的管理工具也会使用编码命令和 Web 下载。自动禁用运行合法脚本的管理员账户会造成运营中断,却没有安全收益。
对可疑 PowerShell 的正确响应是保留证据并通知人工审查。收到告警的分析师可以立即获得完整的脚本内容 — 而不是一个需要他们在事件日志中搜索以查找相关条目的模糊警报。是否采取进一步行动(禁用账户、隔离机器、升级事件)的决定,是由掌握了完整上下文的分析师做出的,而不是由缺乏上下文的自动化系统做出的。
## 在生产环境中检测到的真实威胁
ADSAE 绝不是一个理论工具。它已经在生产环境的 Domain Controller 上检测并响应了真实的安全事件。
### 暴力破解事件
一系列失败的身份验证事件触发了暴力破解模块。对事件记录的分析显示了密码喷洒模式 — 每个账户的失败次数较少,来自单个源 IP 的失败次数较多,使用常见密码针对多个账户。
ADSAE 在 5 分钟的检测窗口内禁用了目标账户。根据 ADSAE 日志数据创建的 Sentinel 事件为事后审查提供了完整的时间线和来源归因。在源 IP 被在网络层阻止并强制执行密码重置后,这些账户被重新启用。
### 权限提升事件
权限提升模块在 Event ID 4728 上触发,显示一个账户被一个非已批准管理员的主体账户添加到了 Domain Admins。
ADSAE 在 5 分钟的检测窗口内将该账户从 Domain Admins 中移除。事件记录确定了被添加的账户和主体账户 — 引导调查发现该主体账户在此事件之前的暴力破解攻击中已被攻陷。攻击者获取了凭据,利用它们将一个账户添加到 Domain Admins,但在他们能够使用提升的访问权限之前就被自动撤销了。
### 可疑 PowerShell 事件
PowerShell 检测模块在一个包含编码命令和 Web 下载尝试的脚本上触发。证据文件捕获了解码后的完整脚本内容 — 一个试图从外部 URL 获取 payload 的下载器。
该证据被提交给威胁情报,确认该 URL 与已知的恶意软件基础设施有关联。会话被终止。该用户账户经过审查,发现是当天早些时候收到的一封钓鱼邮件而被攻陷的。
## 实时仪表板
ADSAE 生成动态 HTML 安全仪表板,提供对 Active Directory 环境安全状态的实时可见性。仪表板每五分钟自动刷新一次,与 ADSAE 检测周期保持一致。它显示当前系统状态 — ADSAE 是否正在运行、上次执行时间以及上次执行是否产生了任何事件。
近期事件面板显示最近的十起事件,包含类型、严重性、时间戳和状态。事件按严重性进行颜色编码 — Critical(严重)为红色,High(高)为橙色,Medium(中)为黄色 — 使分析师能够立即识别出优先处理项。
检测统计面板自 ADSAE 部署以来每种检测类型的累计计数 — 暴力破解检测、权限提升检测、PowerShell 检测。这种趋势数据比单独的事件计数更有意义,因为它显示了环境随着时间的推移是经历着增加还是减少的威胁活动。
受保护账户面板显示哪些账户在禁用白名单中,以及哪些特权组成员在已批准的管理员白名单中。这使得白名单配置在操作界面中可见,而不是隐藏在配置文件中。
## 与 Sentinel 集成
ADSAE 和 Sentinel 是互补的,而不是多余的。它们解决检测和响应问题的不同部分。
Sentinel 提供跨所有数据源(云事件、身份事件、网络事件以及通过 Log Analytics agent 获取的本地事件)的广泛可见性。其分析规则可以检测跨整个环境的模式,这是任何单一来源都无法揭示的。关联来自 Entra ID 日志的可疑登录与来自 Security Event 日志的异常进程执行是 Sentinel 能够检测到而 ADSAE 无法做到的。
ADSAE 提供对其设计检测的特定本地 Active Directory 威胁的快速响应。其 5 分钟的执行周期意味着对暴力破解和权限提升的响应比任何 Sentinel 从分析规则到 playbook 再到 API 调用的链路都要快。
它们之间的集成是通过 ADSAE 写入到 C:\UzmaSOC-Logs\ 的证据日志来实现的。这些日志由通过 Azure Arc 安装的 Log Analytics agent 收集,并在 Sentinel 中可用。Sentinel 中的分析规则可以引用 ADSAE 事件数据 — 将 ADSAE 暴力破解检测与 Entra ID 登录风险信号相关联,以生成比任何一个系统单独生成的更丰富的事件记录。
## 遇到的挑战
*Task Scheduler 可靠性*
ADSAE 引擎通过 Task Scheduler 运行。在部署初期,由于服务账户没有查询 Security Event Log 所需的权限,任务偶尔执行失败。Security Event Log 访问要求账户是 Event Log Readers 组的成员,或者对日志文件具有明确的读取权限。将服务账户添加到 Event Log Readers 解决了执行失败的问题。
在部署查询安全相关事件日志的计划任务时,这是一个常见的疏忽 — Security 日志对标准用户是不可读的,并且当权限被拒绝时,错误消息中并未明确提示权限要求。
*白名单管理*
在没有完整白名单的初始部署中,Azure AD Connect 服务账户因密码过期导致重复身份验证失败,被暴力破解模块禁用。其影响是立竿见影的 — 目录同步停止,仅限云的更改不再传播到本地目录。
恢复过程需要重新启用服务账户,在 Azure AD Connect 中更新其密码,并重启同步服务。更重要的是,它需要立即更新白名单以防止再次发生,并促使对所有可能生成匹配暴力破解阈值的身份验证模式的服务账户进行全面审计。
*证据日志大小管理*
PowerShell 脚本块事件可能很大。可疑 PowerShell 事件的证据捕获为每个检测到的事件生成多 KB 的文件。如果没有日志管理,证据目录将无限制地增长。我们实施了一项清理例程,删除超过 90 天的证据文件 — 这与 Log Analytics 的保留期保持一致,以便在调查窗口期间保留证据,然后将其移除以防止无限增长。
## 经验教训
从构建和操作 ADSAE 中获得的最重要教训是关于自动化与调查之间的关系。
自动化响应之所以有价值,正是因为它的运行速度比人类分析师快。它之所以危险,也正是由于它在没有人工判断的情况下运行。关于哪些响应应该自动化、哪些需要人工审查的设计决策,是任何自动化响应系统中最重要的设计决策。
对暴力破解受害者进行账户禁用是自动化的,因为不采取行动的风险(账户泄露)是直接且严重的。对可疑 PowerShell 执行进行账户禁用未被自动化,因为误报行动(禁用了正在运行合法脚本的管理员)的风险对运营影响重大,并且自动化系统无法可靠地区分这两种情况。
这种校准 — 决定哪些应该自动化,哪些应该呈现给人工审查 — 是一种安全工程判断,没有任何供应商工具能够为特定环境做出这种判断。它需要了解特定的威胁、特定的运营环境以及误报和漏报响应的具体后果。构建 ADSAE 需要明确做出这些判断,而不是接受商业工具的默认设置。
## 在规模扩展时的不同做法
在企业规模下,ADSAE 的架构将发生重大变化。核心检测逻辑(监控特定的事件 ID 并应用阈值)将保持有效,但执行模型将从计划 PowerShell 脚本更改为通过 Event Hub 近实时接收事件的 Azure Function。
响应操作将通过 Microsoft Graph API 和 Azure REST API 执行,而不是本地 AD PowerShell — 从而能够从单个响应平台响应云端和本地身份事件。
白名单管理将从脚本中的配置文件转移到由 Key Vault 支持的配置中 — 从而无需修改脚本即可更新白名单,并提供访问受控、有审计日志的白名单管理。
仪表板将被 Sentinel Workbook 取代 — 将 ADSAE 运营数据与更广泛的 Sentinel SOC 视图集成,而不是维护独立的运营界面。
## 系列导航
| # | 项目 | 链接 |
|---|---------|------|
| ← P8 | 合规与治理 | [查看](../azure-compliance-governance) |
| *P9* | *ADSAE 安全工具* | 你在这里 |
| → P10 | Landing Zone | [查看](../azure-landing-zone) |
| 🏛️ | 企业毕业项目 | [查看](../enterprise-hybrid-security-architecture) |
Uzma Shabbir
Azure 安全工程师 | AZ-104 | AZ-500
[GitHub](https://github.com/UzmaSami) •
[LinkedIn](https://linkedin.com/in/uzma-shabbir-034361128)
标签:Active Directory, AI合规, IPv6, Libemu, Plaso, PowerShell, Terraform 安全, 多模态安全, 安全运营, 扫描框架, 特权访问管理, 红队行动, 自动化响应, 运维监控