1

Somewhat unconventional question, but I want to know if it is possible/am trying to create a process in session 0 using a user's token duplicated from their logon session. There are ample examples of having a service/localSystem create a process in the user's session, however I am trying to use localSystem to create a process in session 0 running in the context of a normal user.

Assumptions are as follows:

  1. Code execution as system, full availability of requisite permissions (SeTcbPrivilige, SeAssignPrimaryTokenPrivilige, SeIncreaseQuotaPrivilege, etc)

  2. A user is logged into a console session

I have a working code snippet using

WTSGetActiveConsoleSessionId
WTSQueryUsertoken
DuplicateTokenEx
//SetTokenInformation
CreateProcessAsUser

Which allows me to, from a system shell, spawn a notepad.exe in the terminal user's session. However when I uncomment the SetTokenInformation() call, while it succeeds and calling GetTokenInformation reflects that the tokenSession has been set to 0, CreateProcessAsUser() now fails with error 5: Access Denied. Notepad is of course not the end desired process for this project, and a gui is not necessary.

I have played with various different parts of CreateProcessAsUser, including specifying an environment by using CreateEnvironmentBlock and several process creation flags in the CPAU() call, but to no avail.

I recently saw a process running in session 0 in a user's context, having been spawn via a wmic process call create command. This leads me to believe it is possible; is it?

A code snippet (incomplete but showing major pieces) is below:

DWORD sessId = WTSGetActiveConsoleSessionId();
printf("SessionID is: %d\n", sessId);
HANDLE explorerToken;
WTSQueryUserToken(sessId, &explorerToken);

DuplicateTokenEx(explorerToken, 0, NULL, SecurityImpersonation, TokenPrimary, &NewToken);

STARTUPINFOW si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi;
//memset(&si, 0, sizeof(si));
//memset(&pi, 0, sizeof(pi));
si.cb = sizeof(si);
//si.lpDesktop = L"winsta0\\default";
//si.wShowWindow = SW_HIDE;

/*
LPVOID lpEnvironment = NULL;
CreateEnvironmentBlock(&lpEnvironment, explorerToken, TRUE);
*/

DWORD SessionId, l;
printf("GetTokenInformation %d\n", GetTokenInformation(NewToken, TokenSessionId, &SessionId, sizeof(SessionId), &l));
printf("SessionId %d\n", SessionId);

SessionId = 0;
printf("SetTokenInformation %d\n", SetTokenInformation(NewToken, TokenSessionId, &SessionId, sizeof(SessionId)));
printf("SessionId %d\n", SessionId);

printf("CreateProcessAsUser %d\n", CreateProcessAsUserW(NewToken, L"C:\\windows\\system32\\notepad.exe", NULL, NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi));
printf("Error is: %u\n", GetLastError());
printf("Process Id: %d\n", pi.dwProcessId);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(NewToken);

Any insight or suggestions? Thanks for your time.

  • That is unconventional, indeed. What services typically do is, upon a user's request, create a new thread, impersonate the client, and service the client's request from there. Is there a specific reason you cannot go with this approach? – IInspectable Aug 25 '22 at 07:23
  • 1
    this code must not return access denied error and new process started. however it fail (if use user32) in initialization phase - the `ZwGdiInit` will return error – RbMm Aug 25 '22 at 10:01
  • Confirm RbMms hypothesis by creating a simple .exe that only uses kernel32... – Anders Aug 25 '22 at 12:29
  • @RbMm Could you please clarify? I am compiling the above as a simple exe at this point, not a service or anything fancy. SetTokenInformation is from Advapi32, so I don't think I can use "only kernel32". Are you referring to removing the WTS calls? I have a process in session 0 running as system that can run the above code. Also, strangely, while the above code works (with SetTokenInformation commented out, so spawning in the users' original session) on windows 10, it fails on windows 11. A whole lot of strangeness. Please clarify your suggestions as I want to try and fix this! – Octoberfest7 Aug 25 '22 at 13:20
  • @Anders tagging you here as well too – Octoberfest7 Aug 25 '22 at 13:20
  • @RbMm sorry, to clarify, when I said I have a process in session 0 that can run the above code I mean I have a process with which i am system and in session 0 so from a permissions issue I wouldn't think there is a problem- the code posted above is still failing when ran as system from session 0, but that is where/from the context I am attempting to run the above code. – Octoberfest7 Aug 25 '22 at 13:36
  • 2
    this code - https://pastebin.com/x82CHH1y work with no eny errors in all windows versions . if you get error - so make something wrong. but new process usually will fail to initialize. when call to `ZwGdiInit` return false. interesting that on win11 it not fail – RbMm Aug 25 '22 at 13:52
  • I copied your code into visual studio (and had to add a few things- #include , pragma comment Wtsapi32.lib, etc) in order to compile for C++. Still doesn't work. Running it as nt/system. – Octoberfest7 Aug 25 '22 at 14:27
  • my code 100% work. may be you not run it from localsystem – RbMm Aug 25 '22 at 14:52
  • How are you running yours from local system? I wrote an exe that will steal the token of winlogon and spawn a new cmd.exe as system; I can also test through a RAT running as system in session 0. In both cases whoami /all returns nt authority\system SID S-1-5-18. Might you be able to edit the pastebin and add any required includes? As I said, your code did not compile right away for me I had to add various headeres for VS to compile it. I attempted to add print statements for dwError and CreateprocessAsUser returned 2147942405 when printed with printf(error is: %lu", dwError) – Octoberfest7 Aug 25 '22 at 14:57
  • use this [tool](https://github.com/rbmm/run-as-pro/blob/master/X64/run%20as%20pro.exe) - run your exe better from lsass that from winlogon (because lsass in 0 session and winlogon not) and select session 0 - where run exe. probably you use bad tool for run exe in 0 session as system – RbMm Aug 25 '22 at 15:53
  • @RbMm I think I just needed sleep. You were right in that the access denied error I was getting was because the program I was using to impersonate system was stealing Winlogon's token, which while it runs as system it is actually a session 1 process and owned by Administrators, compared to things like spoolsv or smss.exe or lsass that are truly owned by LogonSessionId_0_4299944. I think there might have also been a wrinkle in trying to spawn notepad.exe because it is a gui app compared to what I actually needed to spawn. If you leave an answer I'd be happy to mark it as correct! Thank again – Octoberfest7 Aug 26 '22 at 01:08
  • your error based on *I wrote an exe that will steal the token of winlogon and spawn a new cmd.exe as system*. test with tool from my link. even if use token from winlogon - all must be ok. this tool also show token of process in all details. so compare your token, after you create process with tool and your exe – RbMm Aug 26 '22 at 07:06

0 Answers0