天天看點

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

作者:Loong716@Amulab

0x00 前言

在之前的文章中,分别向大家介紹了Windows通路控制模型中的SID和Access Token,本篇文章中将為大家介紹最後一個概念——特權

Windows作業系統中許多操作都需要有對應的特權,特權也是一種非常隐蔽的留後門的方式。在AD域中,一些特權在Default Domain Controller Policy組政策中被授予給一些特殊的組,這些組的成員雖然不是域管,但如果被攻ji者控制同樣能給AD域帶來巨大的風險

是以對防禦者來講,排查使用者的特權配置也是重中之重,本文将對一些比較敏感的特權進行介紹,便于防禦者更好的了解特權的概念以及進行排查

0x01 令牌中的Privilege

特權是一個使用者或組在本地計算機執行各種系統相關操作(關閉系統、裝載裝置驅動程式、改變系統時間)的權限,特權與通路權限的差別如下:

  • 特權控制賬戶對系統資源和系統相關任務的通路,而通路權限控制對安全對象(可以具有安全描述符的對象)的通路
  • 系統管理者為使用者或組指派特權,而系統根據對象的DACL中的ACE授予或拒絕對安全對象的通路,有時擁有特權可以忽略ACL的檢查

在之前介紹Access Token的文章中我們已經了解過了token的基本結構,其中有一部分表示了該使用者及該使用者所屬組所擁有的特權,如下圖所示:

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

通常我們會使用

whoami /priv

指令檢視目前使用者所擁有的特權,預設情況下大部分特權是禁用狀态,在使用時需要啟用

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

0x02 mimikatz的privilege子產品

mimikatz中的privilege子產品主要有以下功能,下圖中第一個紅框中的部分是為目前程序啟用一些指定的特權,第二個紅框中的

id

name

分别支援指定特權的id和名稱,并為目前程序啟用id和名稱對應的特權

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

通常我們比較通用的啟用程序特權的方法是這樣的,代碼如下:

BOOL GetDebugPrivilege()
{
    BOOL status = FALSE;
    HANDLE hToken;

    if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
    {
        TOKEN_PRIVILEGES tokenPrivs;
        tokenPrivs.PrivilegeCount = 1;
        if (LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &tokenPrivs.Privileges[0].Luid))
        {
            tokenPrivs.Privileges[0].Attributes = TRUE ? SE_PRIVILEGE_ENABLED : 0;
            if (AdjustTokenPrivileges(hToken, FALSE, &tokenPrivs, sizeof(tokenPrivs), NULL, NULL))
            {
                status = TRUE;
            }
        }
        else wprintf(L"[!] LookupPrivilegeValueW error: %u when get debug privilege.\n", GetLastError());

        CloseHandle(hToken);
    }
    else wprintf(L"[!] OpenProcessToken error: %u when get debug privilege.\n", GetLastError());

    return status;
}           

而mimikatz是通過調用一個未文檔化的API

RtlAdjustPrivilege()

,該API的功能是對目前程序或線程啟用/禁用指定的特權,共有四個參數:

  • ULONG Privilege:需要操作的特權的ID
  • BOOLEAN Enable:啟用或禁用的标志,1為啟用,0為禁用
  • BOOLEAN CurrentThread:指定是否為目前線程,1則設定線程令牌,0則設定程序令牌
  • PBOOLEAN Enabled:該特權修改之前是禁用的還是啟用的
NTSTATUS RtlAdjustPrivilege
(
    ULONG    Privilege, // [In] 
    BOOLEAN  Enable,  // [In]   
    BOOLEAN  CurrentThread,  // [In]    
    PBOOLEAN Enabled  // [Out]  
)           

如果參數指定的是特權的名稱,則會先調用

LookupPrivilegeValue()

拿到特權名稱對應的特權ID,然後再調用

RtlAdjustPrivilege()

來啟用特權

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

前面提到的是将禁用的特權啟用,而如果想給一個賬戶賦予特權,則可以通過本地政策/組政策來設定,也可以通過

LsaAddAccountRights()

這個API,這裡不再贅述

0x03 危險的特權

這裡主要介紹11個危險的特權,在檢查域内安全時要格外注意

1. SeDebugPrivilege

通常情況下,使用者隻對屬于自己的程序有調試的權限,但如果該使用者Token中被賦予

SeDebugPrivilege

并啟用時,該使用者就擁有了調試其他使用者程序的權限,此時就可以對一些高權限程序執行操作以擷取對應的權限,以程序注入為例:

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

2. SeBackupPrivilege

該特權代表需要執行備份操作的權限,授予目前使用者對所有檔案的讀取權限,不受檔案原本的ACL限制,主要有以下利用思路:

  1. 備份SAM資料庫
  2. 備份磁盤上高權限使用者的敏感檔案
  3. 域内在域控上備份ntds.dit

下圖以導出系統資料庫中的SAM和SYSTEM為例

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

觀察上圖可能有師傅會問:為什麼前面顯示

SeBackupPrivilege

是Disable狀态,卻能成功執行reg save呢?一開始我猜測可能是reg.exe在執行操作前預設會啟用一些特權,随後通過對reg.exe的逆向也印證了這點:

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

在域環境中,Backup Operators和Server Operators組成員允許在域控進行本地登入,并在域控上擁有

SeBackupPrivilege

特權,是以也可以對ntds.dit進行備份操作,再備份系統資料庫中的SYSTEM和SECURITY,進而解密ntds.dit

需要注意的是在調用

CreateFile()

時,需要指定

FILE_FLAG_BACKUP_SEMANTICS

标志來表示正在為備份或恢複操作打開或建立檔案,進而覆寫檔案的ACL檢查

HANDLE hFile = CreateFileW(
    L"C:\\Windows\\System32\\1.txt", 
    GENERIC_READ, 
    0, 
    NULL, 
    OPEN_EXISTING, 
    FILE_FLAG_BACKUP_SEMANTICS, 
    NULL);           

3. SeRestorePrivilege

該特權是執行還原操作所需的權限,擁有此特權的使用者對所有檔案擁有寫權限,不受檔案原本的ACL限制,主要利用思路如下:

  1. 修改系統資料庫,實作修改服務、修改啟動項等操作
  2. 寫檔案進行DLL劫持
【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

域環境中,Backup Operators和Server Operators組成員同樣在域控上也有

SeRestorePrivilege

,是以也可以利用上述操作在域控上完成提權和維權等操作

需要注意的仍是調用API時,需要指定對應的标志,如

CreateFile()

需要指定

FILE_FLAG_BACKUP_SEMANTICS

RegCreateKeyEx()

REG_OPTION_BACKUP_RESTORE

4. SeTakeOwnershipPrivilege

該特權用來修改目标對象的所有權,也就是說擁有該特權的使用者可以修改任意對象的所有者(Owner),而所有者對該對象是有WriteDACL的權限的,可以任意修改對象的ACL

是以如果擁有了

SeTakeOwnershipPrivilege

,就相當于對任意對象有讀寫的權限,利用方式和

SeRestorePrivilege

SeBackupPrivilege

基本相同

GetTakeOwnershipPriv();
...
status = SetNamedSecurityInfo(
    L"C:\\Windows\\System32\\localspl.dll",
    SE_FILE_OBJECT,
    OWNER_SECURITY_INFORMATION,
    user->User.Sid,
    NULL,
    NULL,
    NULL);           

如下圖所示,可以将對象的Owner從TrustedInstaller修改為目前使用者:

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

5. SeImpersonatePrivilege

SeImpersonatePrivilege

特權配置設定給使用者時,表示允許該使用者運作的程式模拟用戶端,預設Service賬戶(如MSSQL、IIS的服務賬戶)和管理者賬戶會擁有該權限

該權限也是一些potato提權的重要條件,可以通過printbug+

ImpersonateNamedPipeClient()

等等許多方式擷取到高權限令牌,進而執行模拟,此處以pipepotato為例:

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

6. SeAssignPrimaryTokenPrivilege

該特權表示可以為程序配置設定主令牌,經常與

SeImpersonatePrivilege

特權配合使用在potato的提權中。擁有該特權時,我們可以使用非受限的令牌調用

CreateProcessAsUser()

;或者先建立挂起的程序,再通過

NtSetInformationProcess()

來替換程序的token

順便提一嘴,之前文章中提到的mimikatz的token::run子產品在使用時可能會出現0x00000522錯誤,如下圖所示

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

這是因為在調用

CreateProcessAsUser()

時,如果傳入的是非受限令牌,那麼則需要

SeAssignPrimaryTokenPrivilege

特權,有關受限令牌的概念可閱讀微軟文檔:https://docs.microsoft.com/en-us/windows/win32/secauthz/restricted-tokens

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

是以該功能應該是用來從SYSTEM權限竊取其他使用者的Access Token(因為預設SYSTEM才有

SeAssignPrimaryTokenPrivilege

),如果想要非SYSTEM使用者調用的話可以考慮改為用

CreateProcessWithToken()

建立程序

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

7. SeLoadDriverPrivilege

該權限用來加載或解除安裝裝置的驅動,在windows中使用者可以通過

NTLoadDriver()

進行驅動的加載,其DriverServiceName參數需要傳入驅動配置的系統資料庫項

NTSTATUS NTLoadDriver(
    _In_ PUNICODE_STRING DriverServiceName // \Registry\Machine\System\CurrentControlSet\Services\DriverName
);           

其中DriverName表示啟動名稱,該鍵下至少應有兩個值:

  • ImagePath:REG_EXPAND_SZ類型,“??\C:\path\to\driver.sys” 格式
  • Type:REG_WORD類型,其值需要被設定為1,表示KENERL_DRIVER

如果是非管理者權限,預設無法操作HKLM系統資料庫項,則可以在HKEY_CURRENT_USER (HKCU) 下建立系統資料庫項并設定驅動程式配置設定,再調用

NTLoadDriver()

指定之前建立的系統資料庫項來注冊驅動,代碼可參考:https://github.com/TarlogicSecurity/EoPLoadDriver/

此時可以利用一些有漏洞的驅動程式來實作LPE等操作,以Capcom.sys為例:

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

除此之外,在AD域中

SeLoadDriverPrivilege

權限在域控上預設授予Print Operators組,使得該組使用者可以遠端在域控加載列印機驅動程式,前一段時間的Printnightmare便是繞過了該權限的檢查

8. SeCreateTokenPrivilege

該特權表示:允許擁有此特權的程序可以通過

ZwCreateToken()

建立Access Token

NTSATUS ZwCreateToken(
     OUT PHANDLE             TokenHandle,
     IN ACCESS_MASK          DesiredAccess,
     IN POBJECT_ATTRIBUTES   ObjectAttributes,
     IN TOKEN_TYPE           TokenType,
     IN PLUID                AuthenticationId,
     IN PLARGE_INTEGER       ExpirationTime,
     IN PTOKEN_USER          TokenUser,
     IN PTOKEN_GROUPS        TokenGroups,
     IN PTOKEN_PRIVILEGES    TokenPrivileges,
     IN PTOKEN_OWNER         TokenOwner,
     IN PTOKEN_PRIMARY_GROUP TokenPrimaryGroup,
     IN PTOKEN_DEFAULT_DACL  TokenDefaultDacl,
     IN PTOKEN_SOURCE        TokenSource 
);           

那麼我們肯定會想:能不能直接利用該API建立一個SYSTEM的token,然後起程序?很遺憾,該權限不允許使用者使用他們剛建立的令牌

但我們可以利用模拟,建立一個目前使用者的、包含特權組SID的token,因為隻要令牌是針對同一個使用者的,并且完整性級别小于或等于目前程序完整性級别(完整性級别可以通過構造令牌時來設定),就可以不需要

SeImpersonatePrivilege

特權,對線程設定模拟令牌

以建立Group List中包含administrators組SID的token為例,在建立token前修改了組SID、特權清單,最初成功利用模拟令牌建立線程,在system32下寫入檔案:

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

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

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

幸運的是已經有大牛發現了繞過的方法,就是把Token的AuthenticationID從

SYSTEM_LUID

(0x3e7)修改為

ANONYMOUS_LOGON_LUID

(0x3e6),最終成功使用模拟令牌向system32目錄寫入了檔案:

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

9. SeTcbPrivilege

該特權标志着其擁有者是作業系統的一部分,擁有該特權的程序可利用

LsaLogonUser()

執行建立登入令牌等操作,是以可以充當任意使用者

NTSTATUS LsaLogonUser(
    HANDLE              LsaHandle,
    PLSA_STRING         OriginName,
    SECURITY_LOGON_TYPE LogonType,
    ULONG               AuthenticationPackage,
    PVOID               AuthenticationInformation,
    ULONG               AuthenticationInformationLength,
    PTOKEN_GROUPS       LocalGroups,
    PTOKEN_SOURCE       SourceContext,
    PVOID               *ProfileBuffer,
    PULONG              ProfileBufferLength,
    PLUID               LogonId,
    PHANDLE             Token,
    PQUOTA_LIMITS       Quotas,
    PNTSTATUS           SubStatus
);           

根據微軟官方文檔,當以下一項獲多項為真時,

LsaLogonUser()

調用者需要

SeTcbPrivilege

特權:

  • 使用了 Subauthentication 包
  • 使用 KERB_S4U_LOGON,調用者請求模拟令牌
  • LocalGroups

    參數不為NULL

我們主要關注第二點和第三點,從文檔的描述來看,如果使用KERB_S4U_LOGON來登入(也可以使用MSV1_0_S4U_LOGON,但文檔中未展現),我們就可以拿到一張模拟令牌,并且可以在

LocalGroups

參數給該令牌添加附加組:

WCHAR systemSID[] = L"S-1-5-18";
ConvertStringSidToSid(systemSID, &pExtraSid);

pGroups->Groups[pGroups->GroupCount].Attributes = SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
pGroups->Groups[pGroups->GroupCount].Sid = pExtraSid;
pGroups->GroupCount++;           

此時我們就可以拿到一張擁有SYSTEM的SID的令牌,如何在沒有

SeImpersonatePrivilege

特權的情況下使用模拟令牌在

SeCreateTokenPrivilege

的利用中已經提到過了

如下圖所示,成功在system32下寫入檔案:

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

當然,如果在域内,也可以嘗試KERB_S4U_LOGON來擷取域内使用者的模拟令牌

10. SeTrustedCredmanAccessPrivilege

該特權用來通路憑據管理器,備份憑據管理器中的憑據需要使用

CredBackupCredentials()

這一API,而調用該API需要擁有

SeTrustedCredmanAccessPrivilege

特權,該特權預設授予winlogon.exe和lsass.exe這兩個程序

BOOL WINAPI CredBackupCredentials(  HANDLE Token,     LPCWSTR Path,     PVOID Password,     DWORD PasswordSize,     DWORD Flags);           

為了測試我在憑據管理器中手動新增了一條憑據,用于通路192.168.47.20,使用者名和密碼為admin/adminpass

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

利用方式即竊取winlogon.exe的token,并調用

CredBackupCredentials()

對憑據管理器中的憑據進行備份(指定加密密碼為NULL),最終再調用

CryptUnprotectData()

對備份的檔案進行解密。此處代碼參考:https://github.com/BL0odz/POSTS/blob/main/DumpCred\_TrustedTokenPriv/main.cpp

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

11. SeEnableDelegationPrivilege

在域内配置無限制委派和限制委派時(這裡特指傳統的限制委派,不包括基于資源的限制委派),都是修改的LDAP中的

userAccountControl

屬性來配置(當然限制委派還要修改

msDS-AllowedToDelegateTo

來配置委派可以通路的服務),而想要配置無限制委派或限制委派,不僅需要對屬性有寫權限,還需要在域控有

SeEnableDelegationPrivilege

特權

【安全研究】從mimikatz學習Windows安全之通路控制模型(三)

雖然該利用對攻ji者來說較為苛刻,但如果發現域内組政策給普通賬戶配置了

SeEnableDelegationPrivilege

特權,就需要檢查是否是正常的業務需求

0x04 檢測與緩解

檢測思路:

  • 檢視域内Server Operators、Backup Operators、Print Operators等特權組内是否有不應出現的使用者
  • 檢視域内組政策配置檔案,是否有将特權授予不常見的SID
  • 檢測“4672: 配置設定給新登入的特殊權限”日志

緩解思路:

  • 非業務必需情況下不為普通賬戶賦予特權
  • 不影響業務的情況下,可以取消部分管理者賬戶的

    SeDebugPrivilege

    等特權

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

繼續閱讀