今天要講的是 Windows 中常見的 Inter Process Communication (IPC) 機制之一,Pipe。
Named Pipe File System 負責管理 Pipes, Pipe 實際上是 FILE_OBJECT。
Pipes 也分為2種: Anonmous Pipe 和 Named Pipe。
Anonymous Pipe 不能指定 Pipe 名稱,Pipe 名稱會是系統指定,並且是單向的,意思是 read 和 write 會需要透過不同的 handle 操作。
Anonymous Pipe 只能作為 Parent Process 和 Child Process 溝通的管道,並且僅限於 Local 端的操作。
MSDN 的範例 中透過 CreateProcess 時建立指定 Read 和 Write 的 Handle 就可以將 child process 的 stdin 和 stdout 重新導向至 parent process。
BOOL CreatePipe(
[out] PHANDLE hReadPipe,
[out] PHANDLE hWritePipe,
[in, optional] LPSECURITY_ATTRIBUTES lpPipeAttributes,
[in] DWORD nSize
);
CreatePipe 會回傳 ReadPipe Handle 和 WritePipe Handle,就可以分別對 Anonymous Pipe 執行 read 或 write。
其中 lpPipeAttributes
會決定 Anonymous Pipe 的 DACL。
typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength;
LPVOID lpSecurityDescriptor;
BOOL bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
如果 lpSecurityDescriptor
是 NULL,那麼會繼承 access token 的 Security Descriptor。
在預設的 ACLs 中,Local System account, administrators, creator owner 是 full control access,而 Everyone group 和 anonymous account 是 read access。
如果 bInheritHandle
為 False,Handle 會無法被繼承。
如果 lpPipeAttributes
是 NULL,也會繼承 access token 的 Security Descriptor,並且 Handle 無法被繼承。
沒有管理好的 SecuirtyDescriptor 和 InheritHandle 都有可能導致 Pipe 被濫用。
Named Pipe 有指定的 Pipe 名稱,並且可以在 Local 端和 Remote 端使用。
Server 端可以使用 CreateNamedPipe 建立 Named Pipe 提供 Client 端在 Local 或 Remote 連接。
HANDLE CreateNamedPipeA(
[in] LPCSTR lpName,
[in] DWORD dwOpenMode,
[in] DWORD dwPipeMode,
[in] DWORD nMaxInstances,
[in] DWORD nOutBufferSize,
[in] DWORD nInBufferSize,
[in] DWORD nDefaultTimeOut,
[in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes
);
根據 lpName
會建立 \\.\pipe\{lpName}
。
dwOpenMode
又分為:
lpSecurityAttributes
的設定和 Anonymous Pipe 一樣。
在 dwPipeMode
可以指定 Data Transfer Mode:
以下是一些可能指向同個 Named Pipe 的路徑:
\\.\pipe\foo
\\127.0.0.1\pipe\foo
\\192.168.8.130\pipe\foo
\\localhost\pipe\foo
\\DESKTOP-9QSUT1F\pipe\foo
根據不同的連線方式,有可能會遇到不同的檢查機制。
其中 remote 端的 pipe 是通過 SMB,所以會需要通過 SMB authentication。
根據 csandker 的文章,IP 通常是用 NTLM 驗證,而 hostname 是用 Kerberos 驗證。
Server 可以使用 ImpersonateNamedPipeClient 取得 Client 的 access token。
BOOL ImpersonateNamedPipeClient(
[in] HANDLE hNamedPipe
);
這個也是 Windows Potatoes 很常用的技術,如果知道哪個 Named Pipe 會被 Local System 連接,那麼就有機會迫使 Local System 連接至攻擊者建立的 Named Pipe ,攻擊者便能 impersonate 該 process 的 access token。