使用c++中的命名管道进行权限提升



我有这个代码:

#include <Windows.h>
#include <namedpipeapi.h>
#include <processthreadsapi.h>
#include <iostream>
int main() {
LPCWSTR pipeName = L"\\.\pipe\TestSV";
HANDLE serverPipe;
int err = 0;
BOOL isPipeConnected;
BOOL isPipeOpen;
DWORD bytesWritten = 0;
std::wcout << "Creating named pipe " << pipeName << std::endl;
serverPipe = CreateNamedPipe(pipeName, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE, 1, 2048, 2048, 0, NULL);
isPipeConnected = ConnectNamedPipe(serverPipe, NULL);
if (isPipeConnected) {
std::wcout << "Incoming connection to " << pipeName << std::endl;
}
std::wcout << "Impersonating the client..." << std::endl;
ImpersonateNamedPipeClient(serverPipe);
err = GetLastError();
std::wcout << "Impersonating status..." << err << std::endl;
STARTUPINFO si = {};
wchar_t command[] = L"C:\Windows\System32\notepad.exe";
std::wcout << command << std::endl;
PROCESS_INFORMATION pi = {};
HANDLE threadToken = GetCurrentThreadToken();
std::wcout << "Thread token " << threadToken << std::endl;
CreateProcessWithTokenW(threadToken, LOGON_WITH_PROFILE, command, NULL, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
err = GetLastError();
std::wcout << "Elv status..." << err << std::endl;
return 0;
}

我创建了一个服务器管道并侦听传入的连接。在我的情况下,我运行:

cmd.exe /c echo hello > //./pipe/TestSV

我应该能够模拟cmd.exe的线程令牌,并以SYSTEM用户而不是本地用户的身份启动notepad.exe,但是有些事情无法正常工作。

我查看了Microsoft文档,其中指出成功调用CreateProcessWithTokenW()ImpersonateNamedPipeClient()应该返回一个非零值。在这两种情况下,我都得到了大量的回报,所以我有点困惑为什么它不起作用。我是不是错过了什么?


UPDATE:我按照建议更新了代码,但它仍然不能正常工作,现在我得到了一个不同的错误:

#include <Windows.h>
#include <namedpipeapi.h>
#include <processthreadsapi.h>
#include <iostream>
int main() {
LPCWSTR pipeName = L"\\.\pipe\TestSV";
LPVOID pipeBuffer = NULL;
HANDLE serverPipe;
HANDLE threadToken = NULL;
DWORD readBytes = 0;
DWORD readBuffer = 0;
int err = 0;
BOOL isPipeConnected;
BOOL isPipeOpen;
BYTE bMessage[128] = { 0 };
DWORD bytesWritten = 0;
std::wcout << "Creating named pipe " << pipeName << std::endl;
serverPipe = CreateNamedPipe(pipeName, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE, 1, 2048, 2048, 0, NULL);
isPipeConnected = ConnectNamedPipe(serverPipe, NULL);
if (isPipeConnected) {
std::wcout << "Incoming connection to " << pipeName << std::endl;
}
if (!ReadFile(serverPipe, &bMessage, 1, &bytesWritten, NULL)) {
std::wcout << "Failed to READ" << std::endl;
}


std::wcout << "Impersonating the client..." << std::endl;
if (!ImpersonateNamedPipeClient(serverPipe)) {
err = GetLastError();
std::wcout << "Impersonating error..." << err << std::endl;
}
// get a handle to this threads token
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &threadToken)) {
err = GetLastError();
std::wcout << "Token error..." << err << std::endl;
}

STARTUPINFO si = {};
PROCESS_INFORMATION pi = {};
wchar_t command[] = L"C:\Windows\System32\notepad.exe";

int process_status = CreateProcessWithTokenW(&threadToken, LOGON_WITH_PROFILE, command, NULL, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
err = GetLastError();
std::wcout << "Elv error..." << process_status << std::endl;
std::wcout << "Elv error..." << err << std::endl;
return 0;
}

首先,您根本没有检查ImpersonateNamedPipeClient()CreateProcessWithTokenW()的返回值(就像检查ConnectNamedPipe()一样(。您正在检查GetLastError()的返回值。不是一回事。如果这些函数在失败时不返回CCD_ 11,则CCD_。因此,请使用以下内容:

if (!ImpersonateNamedPipeClient(serverPipe))
{
err = GetLastError();
std::wcout << "Impersonating failed..." << err << std::endl;
}
if (!CreateProcessWithTokenW(threadToken, LOGON_WITH_PROFILE, command, NULL, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
{
err = GetLastError();
std::wcout << "Elv failed..." << err << std::endl;
}

也就是说,一旦您修复了这个问题,您就会注意到ImpersonateNamedPipeClient()失败,并出现错误1368(ERROR_CANNOT_IMPERSONATE(:

在从命名管道读取数据之前,无法使用该管道进行模拟。

ImpersonateNamedPipeClient()文档说明:

ImpersonateNamedPipeClient函数允许命名管道的服务器端模拟客户端。调用此函数时,命名管道文件系统会更改调用进程的线程,以开始模拟从管道读取的最后一条消息的安全上下文。只有管道的服务器端可以调用此函数。

通常,在客户端首次向您发送访问需要客户端安全上下文的内容的请求之后,您才会模拟客户端。读取请求,然后在需要时进行模拟,然后访问所需的内容,然后恢复模拟并重复,直到客户端断开连接。

因此,在您的情况下,首先读取hello输入,然后模拟,然后启动cmd.exe

最新更新