【安全研究】從mimikatz學習Windows安全之訪問控制模型(三)
0x00 前言
在之前的文章中,分別向大家介紹了Windows訪問控制模型中的SID和Access Token,本篇文章中將為大家介紹最后一個概念——特權(quán)
Windows操作系統(tǒng)中許多操作都需要有對應的特權(quán),特權(quán)也是一種非常隱蔽的留后門的方式。在AD域中,一些特權(quán)在Default Domain Controller Policy組策略中被授予給一些特殊的組,這些組的成員雖然不是域管,但如果被攻擊者控制同樣能給AD域帶來巨大的風險
因此對防御者來講,排查用戶的特權(quán)配置也是重中之重,本文將對一些比較敏感的特權(quán)進行介紹,便于防御者更好的理解特權(quán)的概念以及進行排查
0x01 令牌中的Privilege
特權(quán)是一個用戶或組在本地計算機執(zhí)行各種系統(tǒng)相關操作(關閉系統(tǒng)、裝載設備驅(qū)動程序、改變系統(tǒng)時間)的權(quán)限,特權(quán)與訪問權(quán)限的區(qū)別如下:
特權(quán)控制賬戶對系統(tǒng)資源和系統(tǒng)相關任務的訪問,而訪問權(quán)限控制對安全對象(可以具有安全描述符的對象)的訪問
系統(tǒng)管理員為用戶或組指派特權(quán),而系統(tǒng)根據(jù)對象的DACL中的ACE授予或拒絕對安全對象的訪問,有時擁有特權(quán)可以忽略ACL的檢查
在之前介紹Access Token的文章中我們已經(jīng)了解過了token的基本結(jié)構(gòu),其中有一部分表示了該用戶及該用戶所屬組所擁有的特權(quán),如下圖所示:

通常我們會使用whoami /priv
命令查看當前用戶所擁有的特權(quán),默認情況下大部分特權(quán)是禁用狀態(tài),在使用時需要啟用

0x02 mimikatz的privilege模塊
mimikatz中的privilege模塊主要有以下功能,下圖中第一個紅框中的部分是為當前進程啟用一些指定的特權(quán),第二個紅框中的id
和name
分別支持指定特權(quán)的id和名稱,并為當前進程啟用id和名稱對應的特權(quán)

通常我們比較通用的啟用進程特權(quán)的方法是這樣的,代碼如下:

而mimikatz是通過調(diào)用一個未文檔化的APIRtlAdjustPrivilege()
,該API的功能是對當前進程或線程啟用/禁用指定的特權(quán),共有四個參數(shù):
ULONG Privilege:需要操作的特權(quán)的ID
BOOLEAN Enable:啟用或禁用的標志,1為啟用,0為禁用
BOOLEAN CurrentThread:指定是否為當前線程,1則設置線程令牌,0則設置進程令牌
PBOOLEAN Enabled:該特權(quán)修改之前是禁用的還是啟用的

如果參數(shù)指定的是特權(quán)的名稱,則會先調(diào)用LookupPrivilegeValue()
拿到特權(quán)名稱對應的特權(quán)ID,然后再調(diào)用RtlAdjustPrivilege()
來啟用特權(quán)

前面提到的是將禁用的特權(quán)啟用,而如果想給一個賬戶賦予特權(quán),則可以通過本地策略/組策略來設置,也可以通過LsaAddAccountRights()
這個API,這里不再贅述
0x03 危險的特權(quán)
這里主要介紹11個危險的特權(quán),在檢查域內(nèi)安全時要格外注意
1. SeDebugPrivilege
通常情況下,用戶只對屬于自己的進程有調(diào)試的權(quán)限,但如果該用戶Token中被賦予SeDebugPrivilege
并啟用時,該用戶就擁有了調(diào)試其他用戶進程的權(quán)限,此時就可以對一些高權(quán)限進程執(zhí)行操作以獲取對應的權(quán)限,以進程注入為例:

2. SeBackupPrivilege
該特權(quán)代表需要執(zhí)行備份操作的權(quán)限,授予當前用戶對所有文件的讀取權(quán)限,不受文件原本的ACL限制,主要有以下利用思路:
備份SAM數(shù)據(jù)庫
備份磁盤上高權(quán)限用戶的敏感文件
域內(nèi)在域控上備份ntds.dit
下圖以導出注冊表中的SAM和SYSTEM為例

觀察上圖可能有師傅會問:為什么前面顯示SeBackupPrivilege
是Disable狀態(tài),卻能成功執(zhí)行reg save呢?一開始我猜測可能是reg.exe在執(zhí)行操作前默認會啟用一些特權(quán),隨后通過對reg.exe的逆向也印證了這點:

在域環(huán)境中,Backup Operators和Server Operators組成員允許在域控進行本地登錄,并在域控上擁有SeBackupPrivilege
特權(quán),所以也可以對ntds.dit進行備份操作,再備份注冊表中的SYSTEM和SECURITY,進而解密ntds.dit
需要注意的是在調(diào)用CreateFile()
時,需要指定FILE_FLAG_BACKUP_SEMANTICS
標志來表示正在為備份或恢復操作打開或創(chuàng)建文件,從而覆蓋文件的ACL檢查

3. SeRestorePrivilege
該特權(quán)是執(zhí)行還原操作所需的權(quán)限,擁有此特權(quán)的用戶對所有文件擁有寫權(quán)限,不受文件原本的ACL限制,主要利用思路如下:
修改注冊表,實現(xiàn)修改服務、修改啟動項等操作
寫文件進行DLL劫持

域環(huán)境中,Backup Operators和Server Operators組成員同樣在域控上也有SeRestorePrivilege
,因此也可以利用上述操作在域控上完成提權(quán)和維quan等操作
需要注意的仍是調(diào)用API時,需要指定對應的標志,如CreateFile()
需要指定FILE_FLAG_BACKUP_SEMANTICS
,RegCreateKeyEx()
需要指定REG_OPTION_BACKUP_RESTORE
4. SeTakeOwnershipPrivilege
該特權(quán)用來修改目標對象的所有權(quán),也就是說擁有該特權(quán)的用戶可以修改任意對象的所有者(Owner),而所有者對該對象是有WriteDACL的權(quán)限的,可以任意修改對象的ACL
所以如果擁有了SeTakeOwnershipPrivilege
,就相當于對任意對象有讀寫的權(quán)限,利用方式和SeRestorePrivilege
、SeBackupPrivilege
基本相同

如下圖所示,可以將對象的Owner從TrustedInstaller修改為當前用戶:

5. SeImpersonatePrivilege
當SeImpersonatePrivilege
特權(quán)分配給用戶時,表示允許該用戶運行的程序模擬客戶端,默認Service賬戶(如MSSQL、IIS的服務賬戶)和管理員賬戶會擁有該權(quán)限
該權(quán)限也是一些potato提權(quán)的重要條件,可以通過printbug+ImpersonateNamedPipeClient()
等等許多方式獲取到高權(quán)限令牌,進而執(zhí)行模擬,此處以pipepotato為例:

6. SeAssignPrimaryTokenPrivilege
該特權(quán)表示可以為進程分配主令牌,經(jīng)常與SeImpersonatePrivilege
特權(quán)配合使用在potato的提權(quán)中。擁有該特權(quán)時,我們可以使用非受限的令牌調(diào)用CreateProcessAsUser()
;或者先創(chuàng)建掛起的進程,再通過NtSetInformationProcess()
來替換進程的token
順便提一嘴,之前文章中提到的mimikatz的token::run模塊在使用時可能會出現(xiàn)0x00000522錯誤,如下圖所示

這是因為在調(diào)用CreateProcessAsUser()
時,如果傳入的是非受限令牌,那么則需要SeAssignPrimaryTokenPrivilege
特權(quán),有關受限令牌的概念可閱讀微軟文檔:https://docs.microsoft.com/en-us/windows/win32/secauthz/restricted-tokens

因此該功能應該是用來從SYSTEM權(quán)限竊取其他用戶的Access Token(因為默認SYSTEM才有SeAssignPrimaryTokenPrivilege
),如果想要非SYSTEM用戶調(diào)用的話可以考慮改為用CreateProcessWithToken()
創(chuàng)建進程

7. SeLoadDriverPrivilege
該權(quán)限用來加載或卸載設備的驅(qū)動,在windows中用戶可以通過NTLoadDriver()
進行驅(qū)動的加載,其DriverServiceName參數(shù)需要傳入驅(qū)動配置的注冊表項

其中DriverName表示啟動名稱,該鍵下至少應有兩個值:
ImagePath:REG_EXPAND_SZ類型,“??\C:\path\to\driver.sys” 格式
Type:REG_WORD類型,其值需要被設置為1,表示KENERL_DRIVER
如果是非管理員權(quán)限,默認無法操作HKLM注冊表項,則可以在HKEY_CURRENT_USER (HKCU) 下創(chuàng)建注冊表項并設置驅(qū)動程序配置設置,再調(diào)用NTLoadDriver()
指定之前創(chuàng)建的注冊表項來注冊驅(qū)動,代碼可參考:https://github.com/TarlogicSecurity/EoPLoadDriver/
此時可以利用一些有漏洞的驅(qū)動程序來實現(xiàn)LPE等操作,以Capcom.sys為例:

除此之外,在AD域中SeLoadDriverPrivilege
權(quán)限在域控上默認授予Print Operators組,使得該組用戶可以遠程在域控加載打印機驅(qū)動程序,前一段時間的Printnightmare便是繞過了該權(quán)限的檢查
8. SeCreateTokenPrivilege
該特權(quán)表示:允許擁有此特權(quán)的進程可以通過ZwCreateToken()
創(chuàng)建Access Token

那么我們肯定會想:能不能直接利用該API創(chuàng)建一個SYSTEM的token,然后起進程?很遺憾,該權(quán)限不允許用戶使用他們剛創(chuàng)建的令牌
但我們可以利用模擬,創(chuàng)建一個當前用戶的、包含特權(quán)組SID的token,因為只要令牌是針對同一個用戶的,并且完整性級別小于或等于當前進程完整性級別(完整性級別可以通過構(gòu)造令牌時來設置),就可以不需要SeImpersonatePrivilege
特權(quán),對線程設置模擬令牌
以創(chuàng)建Group List中包含administrators組SID的token為例,在創(chuàng)建token前修改了組SID、特權(quán)列表,最初成功利用模擬令牌創(chuàng)建線程,在system32下寫入文件:

需要注意的是在Win10 >= 1809和Windows Server 2019,以及安裝了KB4507459的Win10和2016上,我們不能使用生成的模擬令牌,會爆“1346:未提供所需的模擬級別,或提供的模擬級別無效”錯誤

幸運的是已經(jīng)有大牛發(fā)現(xiàn)了繞過的方法,就是把Token的AuthenticationID從SYSTEM_LUID
(0x3e7)修改為ANONYMOUS_LOGON_LUID
(0x3e6),最終成功使用模擬令牌向system32目錄寫入了文件:

9. SeTcbPrivilege
該特權(quán)標志著其擁有者是操作系統(tǒng)的一部分,擁有該特權(quán)的進程可利用LsaLogonUser()
執(zhí)行創(chuàng)建登錄令牌等操作,因此可以充當任意用戶

根據(jù)微軟官方文檔,當以下一項獲多項為真時,LsaLogonUser()
調(diào)用者需要SeTcbPrivilege
特權(quán):
使用了 Subauthentication 包
使用 KERB_S4U_LOGON,調(diào)用者請求模擬令牌
LocalGroups
參數(shù)不為NULL
我們主要關注第二點和第三點,從文檔的描述來看,如果使用KERB_S4U_LOGON來登錄(也可以使用MSV1_0_S4U_LOGON,但文檔中未體現(xiàn)),我們就可以拿到一張模擬令牌,并且可以在LocalGroups
參數(shù)給該令牌添加附加組:

此時我們就可以拿到一張擁有SYSTEM的SID的令牌,如何在沒有SeImpersonatePrivilege
特權(quán)的情況下使用模擬令牌在SeCreateTokenPrivilege
的利用中已經(jīng)提到過了
如下圖所示,成功在system32下寫入文件:

當然,如果在域內(nèi),也可以嘗試KERB_S4U_LOGON來獲取域內(nèi)用戶的模擬令牌
10. SeTrustedCredmanAccessPrivilege
該特權(quán)用來訪問憑據(jù)管理器,備份憑據(jù)管理器中的憑據(jù)需要使用CredBackupCredentials()
這一API,而調(diào)用該API需要擁有SeTrustedCredmanAccessPrivilege
特權(quán),該特權(quán)默認授予winlogon.exe和lsass.exe這兩個進程

為了測試我在憑據(jù)管理器中手動新增了一條憑據(jù),用于訪問192.168.47.20,用戶名和密碼為admin/adminpass

利用方式即竊取winlogon.exe的token,并調(diào)用CredBackupCredentials()
對憑據(jù)管理器中的憑據(jù)進行備份(指定加密密碼為NULL),最終再調(diào)用CryptUnprotectData()
對備份的文件進行解密。此處代碼參考:https://github.com/BL0odz/POSTS/blob/main/DumpCred_TrustedTokenPriv/main.cpp
11. SeEnableDelegationPrivilege
在域內(nèi)配置無約束委派和約束委派時(這里特指傳統(tǒng)的約束委派,不包括基于資源的約束委派),都是修改的LDAP中的userAccountControl
屬性來配置(當然約束委派還要修改msDS-AllowedToDelegateTo
來配置委派可以訪問的服務),而想要配置無約束委派或約束委派,不僅需要對屬性有寫權(quán)限,還需要在域控有SeEnableDelegationPrivilege
特權(quán)
雖然該利用對攻擊者來說較為苛刻,但如果發(fā)現(xiàn)域內(nèi)組策略給普通賬戶配置了SeEnableDelegationPrivilege
特權(quán),就需要檢查是否是正常的業(yè)務需求
0x04 檢測與緩解
檢測思路:
查看域內(nèi)Server Operators、Backup Operators、Print Operators等特權(quán)組內(nèi)是否有不應出現(xiàn)的用戶
查看域內(nèi)組策略配置文件,是否有將特權(quán)授予不常見的SID
檢測“4672: 分配給新登錄的特殊權(quán)限”日志
緩解思路:
非業(yè)務必需情況下不為普通賬戶賦予特權(quán)
不影響業(yè)務的情況下,可以取消部分管理員賬戶的
SeDebugPrivilege
等特權(quán)
0x05 參考
https://docs.microsoft.com/
https://github.com/gentilkiwi/mimikatz
https://bbs.pediy.com/thread-76552.htm
https://3gstudent.github.io/%E6%B8%97%E9%80%8F%E6%8A%80%E5%B7%A7-Windows%E4%B9%9D%E7%A7%8D%E6%9D%83%E9%99%90%E7%9A%84%E5%88%A9%E7%94%A8
https://github.com/hatRiot/token-priv/blob/master/abusing_token_eop_1.0.txt
https://hackinparis.com/data/slides/2019/talks/HIP2019-Andrea_Pierini-Whoami_Priv_Show_Me_Your_Privileges_And_I_Will_Lead_You_To_System.pdf
https://www.tiraniddo.dev/2021/05/dumping-stored-credentials-with.html
https://www.tarlogic.com/blog/abusing-seloaddriverprivilege-for-privilege-escalation/
https://decoder.cloud/2019/07/04/creating-windows-access-tokens/