最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

從mimikatz學(xué)習(xí)Windows安全之訪問(wèn)控制模型(一)

2021-08-24 17:21 作者:北京中安網(wǎng)星  | 我要投稿

作者:Loong716@Amulab

0x00 前言

Mimikatz是法國(guó)安全研究員Benjamin Delpy開(kāi)發(fā)的一款安全工具。滲透測(cè)試人員對(duì)mimikatz印象最深的肯定就是抓取Windows憑證,但作者對(duì)它的描述是“a tool I’ve made to learn C and make somes experiments with Windows security.”,其實(shí)它的功能不僅僅是抓取憑證,還包含了很多Windows安全相關(guān)的技術(shù)和知識(shí)

這里借用@daiker師傅的思維導(dǎo)圖,mimikatz的模塊大致可分為幾個(gè)部分:

因此文章也會(huì)大致分為windows 訪問(wèn)控制模型,windows 憑據(jù)以及加解密,windows AD 安全,windows 進(jìn)程以及服務(wù),mimikatz 其他模塊五個(gè)小系列。之前自己一直想分析mimikatz的相關(guān)功能,主要是出于以下原因:

  • mimikatz中有許多功能利用了Windows的一些機(jī)制和特性,以changentlm為例,其利用MS-SAMR協(xié)議修改用戶的密碼,我們?cè)俑鶕?jù)MS-SAMR或RPC進(jìn)行知識(shí)延伸,肯定也有不少收獲

  • mimikatz中涉及大量?jī)?nèi)存的操作,其中運(yùn)用的內(nèi)存Patch技術(shù)也被經(jīng)常應(yīng)用于一些安全機(jī)制的繞過(guò)(如繞過(guò)AMSI、Credential Guard等),于是自己想在分析過(guò)程中通過(guò)windbg學(xué)到一些調(diào)試的技巧

  • mimikatz在實(shí)戰(zhàn)中被殺的很厲害,了解相應(yīng)原理可以自己實(shí)現(xiàn)相應(yīng)功能

  • 學(xué)習(xí)/練習(xí)C語(yǔ)言 ??

mimikatz中與Windows訪問(wèn)控制模型相關(guān)的有privilege、token、sid三個(gè)模塊,其分別對(duì)應(yīng)特權(quán)、訪問(wèn)令牌、安全標(biāo)識(shí)符三個(gè)知識(shí),本文主要分析token模塊,并簡(jiǎn)要介紹Windows訪問(wèn)控制模型

由于mimikatz代碼邏輯較為復(fù)雜,涉及大量回調(diào),因此文中代碼都是經(jīng)過(guò)簡(jiǎn)化的。文章可能也會(huì)有一些技術(shù)上或者邏輯上的錯(cuò)誤,還請(qǐng)師傅們指正

?

0x01 訪問(wèn)控制模型簡(jiǎn)介

Windows訪問(wèn)控制模型有兩個(gè)基本組成部分:

  • 訪問(wèn)令牌(Access Token):包含有關(guān)登錄用戶的信息

  • 安全描述符(Security Descriptor):包含用于保護(hù)安全對(duì)象的安全信息

1. 訪問(wèn)令牌(Access Token)

訪問(wèn)令牌(Access Token)被用來(lái)描述一個(gè)進(jìn)程或線程的安全上下文,用戶每次登錄成功后,系統(tǒng)會(huì)為其創(chuàng)建訪問(wèn)令牌,該用戶的所有進(jìn)程也將擁有此訪問(wèn)令牌的副本

當(dāng)線程與安全對(duì)象進(jìn)行交互或嘗試執(zhí)行需要特權(quán)的系統(tǒng)任務(wù)時(shí),系統(tǒng)使用訪問(wèn)令牌來(lái)標(biāo)識(shí)用戶。使用windbg查看進(jìn)程的token,其包含信息如下圖所示:

2. 安全描述符(Security Descriptor)

安全描述符(Security Descriptor)包含與安全對(duì)象有關(guān)的安全信息,這些信息規(guī)定了哪些用戶/組可以對(duì)這個(gè)對(duì)象執(zhí)行哪些操作,安全描述符主要由以下部分構(gòu)成:

  • 所有者的SID

  • 組SID

  • 自主訪問(wèn)控制列表(DACL),規(guī)定哪些用戶/組可以對(duì)這個(gè)對(duì)象執(zhí)行哪些操作

  • 系統(tǒng)訪問(wèn)控制列表(SACL),規(guī)定哪些用戶/組的哪些操作將被記錄到安全審計(jì)日志中

在windbg中查看一個(gè)安全對(duì)象的安全描述符,可以清晰的看到安全描述符的組成:

可以看到該安全描述符的DACL中有三條ACE,ACE的類型都是ACCESS_ALLOWED_ACE_TYPEMask是權(quán)限掩碼,用來(lái)指定對(duì)應(yīng)的權(quán)限。以第一條ACE為例,其表示允許SID為S-1-5-32-544的對(duì)象能夠?qū)υ摪踩珜?duì)象做0x001fffff對(duì)應(yīng)的操作

3. 權(quán)限檢查的過(guò)程

當(dāng)某個(gè)線程嘗試訪問(wèn)一個(gè)安全對(duì)象時(shí),系統(tǒng)根據(jù)安全對(duì)象的ACE對(duì)照線程的訪問(wèn)令牌來(lái)判斷該線程是否能夠?qū)υ摪踩珜?duì)象進(jìn)行訪問(wèn)。通常,系統(tǒng)使用請(qǐng)求訪問(wèn)的線程的主訪問(wèn)令牌。但是,如果線程正在模擬其他用戶,則系統(tǒng)會(huì)使用線程的模擬令牌

此時(shí)將在該安全對(duì)象的DACL中按順序檢查ACE,直到發(fā)生以下事件:

  • 某一條拒絕類型的ACE顯式拒絕令牌中某個(gè)受信者的所有訪問(wèn)權(quán)限

  • 一條或多條允許類型的ACE允許令牌中列出的受信者的所有訪問(wèn)權(quán)限

  • 檢查完所有ACE但沒(méi)有一個(gè)權(quán)限顯式允許,那么系統(tǒng)會(huì)隱式拒絕該訪問(wèn)

我們以微軟文檔中的圖片為例,描述一下整個(gè)過(guò)程:

  1. 線程A請(qǐng)求訪問(wèn)安全對(duì)象,系統(tǒng)讀取ACE1,發(fā)現(xiàn)拒絕Andrew用戶的所有訪問(wèn)權(quán)限,而線程A的訪問(wèn)令牌是Andrew,因此拒絕訪問(wèn),并不再檢查ACE2、ACE3

  2. 線程A請(qǐng)求訪問(wèn),系統(tǒng)按順序讀取ACE,ACE1不適用,讀取到ACE2發(fā)現(xiàn)適用,再讀取到ACE3也適用,因此最終該用戶擁有對(duì)該安全對(duì)象的讀、寫(xiě)、執(zhí)行權(quán)限

?

0x02 Mimikatz的Token模塊

Mimikatz的token模塊共有5個(gè)功能:

  • token::whoami:列出當(dāng)前進(jìn)程/線程的token信息

  • token::list:列出當(dāng)前系統(tǒng)中存在的token

  • token::elevate:竊取其他用戶的token

  • token::run:利用某用戶權(quán)限運(yùn)行指定程序

  • token::revert:恢復(fù)為原來(lái)的token

1. token::whoami

該功能用于列出當(dāng)前進(jìn)程/線程的token信息

只有一個(gè)可選參數(shù)/full,當(dāng)指定該參數(shù)時(shí)會(huì)打印出當(dāng)前token的組信息和特權(quán)信息:

該功能的原理大致如下:

  1. 通過(guò)OpenProcess()獲取當(dāng)前進(jìn)程/線程的句柄

  2. 調(diào)用GetTokenInformation()獲取token的各種信息并輸出

其核心為調(diào)用GetTokenInformation()來(lái)獲取token的各種信息,我們先來(lái)看這個(gè)API定義

BOOL GetTokenInformation( ?HANDLE ? ? ? ? ? ? ? ? ?TokenHandle, ?TOKEN_INFORMATION_CLASS TokenInformationClass, ?LPVOID ? ? ? ? ? ? ? ? ?TokenInformation, ?DWORD ? ? ? ? ? ? ? ? ? TokenInformationLength, ?PDWORD ? ? ? ? ? ? ? ? ?ReturnLength );

其中第二個(gè)參數(shù)是一個(gè)TOKEN_INFORMATION_CLASS枚舉類型,我們可以通過(guò)指定它的值來(lái)獲取token指定的信息

typedef enum _TOKEN_INFORMATION_CLASS { ?TokenUser, ?TokenGroups, ?TokenPrivileges, ?TokenOwner, ?TokenPrimaryGroup, ?TokenDefaultDacl, ?TokenSource, ?... } TOKEN_INFORMATION_CLASS, *PTOKEN_INFORMATION_CLASS;

例如獲取token的SessionID并輸出,可以使用以下代碼:

if (!GetTokenInformation(hToken, TokenSessionId, &sessionId, sizeof(TokenSessionId), &dwSize)) { ? ?wprintf(L"[!] GetTokenInformation error: %u\n", GetLastError()); } wprintf(L"\t%-21s: %u\n", L"Session ID", sessionId);

2. token::list

該功能是獲取當(dāng)前系統(tǒng)中所有的token,注意使用前需要先獲取SeDebugPrivilege,否則列出的token不全

該功能原理大致如下:

  1. 調(diào)用NtQuerySystemInformation()獲取系統(tǒng)進(jìn)程信息(如進(jìn)程PID等)

  2. 循環(huán)遍歷所有進(jìn)程的PID,使用token::whoami功能中的方法對(duì)指定token信息進(jìn)行輸出

NtQuerySystemInformation()用來(lái)檢索指定的系統(tǒng)信息:

__kernel_entry NTSTATUS NtQuerySystemInformation( ?SYSTEM_INFORMATION_CLASS SystemInformationClass, ?PVOID ? ? ? ? ? ? ? ? ? ?SystemInformation, ?ULONG ? ? ? ? ? ? ? ? ? ?SystemInformationLength, ?PULONG ? ? ? ? ? ? ? ? ? ReturnLength );

其第一個(gè)參數(shù)是一個(gè)SYSTEM_INFORMATION_CLASS枚舉類型,我們同樣可以指定不同參數(shù)來(lái)獲取不同的系統(tǒng)信息

以獲取系統(tǒng)進(jìn)程名和PID為例,代碼如下:

PSYSTEM_PROCESS_INFORMATION pProcessInfo = NULL; DWORD flag = TRUE; pProcessInfo = (PSYSTEM_PROCESS_INFORMATION)malloc(dwSize); ntReturn = NtQuerySystemInformation(SystemProcessInformation, pProcessInfo, dwSize, &dwSize);while (ntReturn == STATUS_INFO_LENGTH_MISMATCH) { ? ?free(pProcessInfo); ? ?pProcessInfo = (PSYSTEM_PROCESS_INFORMATION)malloc(dwSize); ? ?ntReturn = NtQuerySystemInformation(SystemProcessInformation, pProcessInfo, dwSize, &dwSize); }while (flag) { ? ?if (pProcessInfo->NextEntryOffset == 0) ? ? ? ?flag = FALSE; ? ?wprintf(L"%-15d", (DWORD)pProcessInfo->UniqueProcessId); ? ?wprintf(L"%-50s", (wchar_t*)pProcessInfo->ImageName.Buffer); ? ?pProcessInfo = (PSYSTEM_PROCESS_INFORMATION)((BYTE*)pProcessInfo + pProcessInfo->NextEntryOffset); }

PS:按照該思路,理論上利用CreateToolhelp32Snapshot()?+?Process32First()遍歷進(jìn)程PID也可以實(shí)現(xiàn)該功能

3. token::elevate

該模塊用于竊取指定用戶的token,共有7個(gè)可選參數(shù),這些參數(shù)主要用來(lái)指定要竊取的token,如果不指定參數(shù)則默認(rèn)竊取NT AUTHORITY\SYSTEM的token

  • /id:指定目標(biāo)token的TokenID

  • /domainadmin:竊取域管的token

  • /enterpriseadmin:竊取企業(yè)管理員的token

  • /admin:竊取本地管理員的token

  • /localservice:竊取Local Service權(quán)限的token

  • /networkservice:竊取Network Service權(quán)限的token

  • /system:竊取SYSTEM權(quán)限的token

假設(shè)我們現(xiàn)在在目標(biāo)機(jī)器上發(fā)現(xiàn)的域管權(quán)限的token

我們可以指定目標(biāo)TokenID,或者使用/domainadmin來(lái)竊取域管的token,執(zhí)行成功后可以看到當(dāng)前線程已經(jīng)擁有域管的模擬令牌:

然后我們就可以在當(dāng)前mimikatz上下文中使用域管身份執(zhí)行操作了,如DCSync

該功能大致過(guò)程如下:

  1. 通過(guò)OpenProcess()獲取當(dāng)前進(jìn)程/線程的句柄

  2. 調(diào)用OpenProcessToken()打開(kāi)與進(jìn)程相關(guān)的token句柄

  3. 使用DuplicateTokenEx()使用目標(biāo)進(jìn)程token創(chuàng)建一個(gè)新的模擬token

  4. 調(diào)用SetThreadToken()設(shè)置當(dāng)前線程的token為上一步創(chuàng)建的新的模擬token

由于竊取token是Access Token利用的重點(diǎn),該過(guò)程放在本文后面分析

4. token::run

該功能是使用指定的token來(lái)運(yùn)行程序,也可以使用token::elevate中的幾個(gè)參數(shù)來(lái)指定運(yùn)行程序的token,除此之外還有一個(gè)參數(shù):

  • /process:指定要運(yùn)行的程序,默認(rèn)值為whoami.exe

其原理前三步與token::elevate大致相同,區(qū)別在于使用DuplicateTokenEx()竊取token后,該功能使用CreateProcessAsUser()來(lái)使用新的primary token創(chuàng)建一個(gè)進(jìn)程

BOOL CreateProcessAsUserA( ?HANDLE ? ? ? ? ? ? ? ?hToken, ?LPCSTR ? ? ? ? ? ? ? ?lpApplicationName, ?LPSTR ? ? ? ? ? ? ? ? lpCommandLine, ?LPSECURITY_ATTRIBUTES lpProcessAttributes, ?LPSECURITY_ATTRIBUTES lpThreadAttributes, ?BOOL ? ? ? ? ? ? ? ? ?bInheritHandles, ?DWORD ? ? ? ? ? ? ? ? dwCreationFlags, ?LPVOID ? ? ? ? ? ? ? ?lpEnvironment, ?LPCSTR ? ? ? ? ? ? ? ?lpCurrentDirectory, ?LPSTARTUPINFOA ? ? ? ?lpStartupInfo, ?LPPROCESS_INFORMATION lpProcessInformation );

創(chuàng)建進(jìn)程后,利用匿名管道做進(jìn)程間通信,將新創(chuàng)建進(jìn)程的標(biāo)準(zhǔn)輸出寫(xiě)入到匿名管道的write端,從管道read端讀取數(shù)據(jù)進(jìn)行回顯(在webshell等非交互場(chǎng)景下很有用)

if (CreatePipe(&hStdoutR, &hStdoutW, &saAttr, 0)) { ? ?SetHandleInformation(hStdoutR, HANDLE_FLAG_INHERIT, 0); ? ?si.cb = sizeof(STARTUPINFO); ? ?si.hStdOutput = hStdoutW; ? ?si.hStdError = si.hStdOutput; ? ?si.dwFlags |= STARTF_USESTDHANDLES; ? ?if (CreateProcessWithTokenW(hDupToken, LOGON_WITH_PROFILE, NULL, cmd, CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, NULL, NULL, &si, &pi)) ? ?{ ? ? ? ?CloseHandle(si.hStdOutput); ? ? ? ?si.hStdOutput = si.hStdError = NULL; ? ? ? ?while (ReadFile(hStdoutR, resultBuf, sizeof(resultBuf), &dwRead, NULL) && dwRead) ? ? ? ?{ ? ? ? ? ? ?for (i = 0; i < dwRead; i++) ? ? ? ? ? ? ? ?wprintf(L"%c", resultBuf[i]); ? ? ? ?} ? ? ? ?WaitForSingleObject(pi.hProcess, INFINITE); ? ? ? ?CloseHandle(pi.hThread); ? ? ? ?CloseHandle(pi.hProcess); ? ?} ? ?else wprintf(L"CreateProcessWithTokenW error 0x%08X\n", GetLastError()); }else wprintf(L"CreatePipe error! 0x%08X\n", GetLastError());

5. token::revert

該模塊用來(lái)清除線程的模擬令牌:

原理很簡(jiǎn)單,直接使用SetThreadToken(NULL, NULL)即可將當(dāng)前線程的token清除

?

0x03 令牌竊取

在滲透測(cè)試中,竊取token是administrator -> system的常見(jiàn)手法之一,還經(jīng)常被用于降權(quán)等用戶切換操作

1. 原理

竊取token主要涉及以下幾個(gè)API:

  1. OpenProcess

HANDLE OpenProcess( ?DWORD dwDesiredAccess, ?BOOL ?bInheritHandle, ?DWORD dwProcessId );

該函數(shù)打開(kāi)指定PID的進(jìn)程的句柄,需要注意的是第一個(gè)參數(shù)dwDesiredAccess,主要會(huì)用到的是以下三個(gè)權(quán)限

  • PROCESS_ALL_ACCESS

  • PROCESS_QUERY_INFORMATION (0x0400)

  • PROCESS_QUERY_LIMITED_INFORMATION (0x1000)

我在編寫(xiě)竊取Token的代碼時(shí),發(fā)現(xiàn)對(duì)部分進(jìn)程(如smss.exe、csrss.exe等)調(diào)用OpenProcess會(huì)出現(xiàn)拒絕訪問(wèn)的情況,查閱網(wǎng)上資料后發(fā)現(xiàn)這些進(jìn)程存在保護(hù),需要使用PROCESS_QUERY_LIMITED_INFORMATION權(quán)限打開(kāi)句柄,詳情請(qǐng)參考這篇文章

  1. OpenProcessToken

BOOL OpenProcessToken( ?HANDLE ?ProcessHandle, ?DWORD ? DesiredAccess, ?PHANDLE TokenHandle );

該函數(shù)打開(kāi)與進(jìn)程相關(guān)聯(lián)的令牌的句柄,其中第二個(gè)參數(shù)DesiredAccess同樣用來(lái)指定令牌的訪問(wèn)權(quán)限,需要以下幾個(gè):

  • TOKEN_DUPLICATE:復(fù)制令牌需要的權(quán)限

  • TOKEN_QUERY:查詢令牌需要的權(quán)限

如果要調(diào)用DuplicateTokenEx需要指定TOKEN_DUPLICATE,如果調(diào)用ImpersonatedLoggedOnUser則需要指定TOKEN_DUPLICATE和TOKEN_QUERY

  1. DuplicateTokenEx

BOOL DuplicateTokenEx( ?HANDLE ? ? ? ? ? ? ? ? ? ? ? hExistingToken, ?DWORD ? ? ? ? ? ? ? ? ? ? ? ?dwDesiredAccess, ?LPSECURITY_ATTRIBUTES ? ? ? ?lpTokenAttributes, ?SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, ?TOKEN_TYPE ? ? ? ? ? ? ? ? ? TokenType, ?PHANDLE ? ? ? ? ? ? ? ? ? ? ?phNewToken );

DuplicateTokenEx用來(lái)復(fù)制現(xiàn)有的令牌來(lái)生成一張新令牌,該函數(shù)可以選擇生成主令牌還是模擬令牌

  • hExistingToken:指定現(xiàn)有的令牌句柄,可以使用OpenProcessToken獲得

  • dwDesiredAccess:用來(lái)指定令牌訪問(wèn)權(quán)限,需要指定以下幾個(gè)來(lái)支持后面調(diào)用CreateProcessWithToken

    • TOKEN_DUPLICATE:需要復(fù)制訪問(wèn)令牌

    • TOKEN_QUERY:需要查詢?cè)L問(wèn)令牌

    • TOKEN_ASSIGN_PRIMARY:將令牌附加到主進(jìn)程的權(quán)限

    • TOKEN_ADJUST_DEFAULT:需要更改訪問(wèn)令牌的默認(rèn)所有者、主要組或 DACL

    • TOKEN_ADJUST_SESSIONID:需要調(diào)整訪問(wèn)令牌的會(huì)話 ID,需要 SE_TCB_NAME 權(quán)限

  • lpTokenAttributes:指向SECURITY_ATTRIBUTES結(jié)構(gòu)的指針,該 結(jié)構(gòu)指定新令牌的安全描述符并確定子進(jìn)程是否可以繼承該令牌

  • ImpersonationLevel:指定令牌的模擬級(jí)別,當(dāng)進(jìn)行復(fù)制令牌時(shí),主令牌被復(fù)制為模擬令牌是始終被允許的,而模擬令牌復(fù)制為主令牌則需要模擬級(jí)別 >= Impersonate

  • TokenType:指定新令牌的類型,是主令牌(Primary Token)還是模擬令牌(Impersonate Token)

  • phNewToken:返回令牌句柄的地址

復(fù)制完一張新令牌后,我們就可以利用這張新令牌來(lái)運(yùn)行我們指定的進(jìn)程了

  1. CreateProcessWithTokenW

BOOL CreateProcessWithTokenW( ?HANDLE ? ? ? ? ? ? ? ?hToken, ?DWORD ? ? ? ? ? ? ? ? dwLogonFlags, ?LPCWSTR ? ? ? ? ? ? ? lpApplicationName, ?LPWSTR ? ? ? ? ? ? ? ?lpCommandLine, ?DWORD ? ? ? ? ? ? ? ? dwCreationFlags, ?LPVOID ? ? ? ? ? ? ? ?lpEnvironment, ?LPCWSTR ? ? ? ? ? ? ? lpCurrentDirectory, ?LPSTARTUPINFOW ? ? ? ?lpStartupInfo, ?LPPROCESS_INFORMATION lpProcessInformation );

該函數(shù)創(chuàng)建一個(gè)新進(jìn)程及其主線程,新進(jìn)程在指定令牌的安全上下文中運(yùn)行。我們直接指定前面復(fù)制出來(lái)的新令牌,使用該令牌創(chuàng)建我們指定的進(jìn)程即可

2. 利用

根據(jù)mimikatz的token模塊的原理,簡(jiǎn)單實(shí)現(xiàn)了一個(gè)demo,也有許多token相關(guān)的工具如incognito等

當(dāng)獲取管理員權(quán)限后,我們可以列出系統(tǒng)中進(jìn)程對(duì)應(yīng)的token:

然后竊取指定進(jìn)程的token來(lái)運(yùn)行我們的程序,如直接運(yùn)行上線馬

如果想要拿回程序輸出的話,則可以通過(guò)管道等進(jìn)程間通信的方法來(lái)回顯輸出

如果拿到一臺(tái)機(jī)器有域管的進(jìn)程,那么我們可以直接竊取域管進(jìn)程的token來(lái)進(jìn)行DCSync攻擊

?

0x04 參考鏈接

https://docs.microsoft.com/

https://github.com/gentilkiwi/mimikatz/

https://www.ired.team/offensive-security/privilege-escalation/t1134-access-token-manipulation

https://www.slideshare.net/JustinBui5/understanding-windows-access-token-manipulation

https://posts.specterops.io/understanding-and-defending-against-access-token-theft-finding-alternatives-to-winlogon-exe-80696c8a73b


從mimikatz學(xué)習(xí)Windows安全之訪問(wèn)控制模型(一)的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
阳新县| 竹山县| 青川县| 沁源县| 宜川县| 汉阴县| 道真| 文登市| 武冈市| 屏边| 永泰县| 龙江县| 博兴县| 绵竹市| 泉州市| 莱阳市| 黄冈市| 虞城县| 红河县| 抚松县| 龙里县| 洮南市| 仙居县| 临潭县| 治县。| 嘉定区| 大新县| 普安县| 麻江县| 淮安市| 望奎县| 扬中市| 阳东县| 衡阳市| 邳州市| 常熟市| 镇原县| 大名县| 成都市| 湖口县| 娱乐|