Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Username is showing up as SYSTEM on Remote Desktop Server #34

Open
greatquux opened this issue Oct 29, 2020 · 17 comments
Open

Username is showing up as SYSTEM on Remote Desktop Server #34

greatquux opened this issue Oct 29, 2020 · 17 comments

Comments

@greatquux
Copy link

For some reason, all usernames (except Administrator where I'm running ntop) show up as SYSTEM when I try to run it on a remote desktop server. The processes are there, just USER is showing as SYSTEM. Any idea why or how to fix?

image

@greatquux
Copy link
Author

BTW this is ntop 0.3.4, the latest release binary. I haven't compiled the latest code, but I don't think any of the recent commits seem to relate to this.

@gsass1
Copy link
Owner

gsass1 commented Oct 29, 2020

It seems that either GetTokenInformation or OpenProcessToken fails probably due to missing permissions. Could you try running as administrator? For now it only says "SYSTEM" because that's just the default user name I set.

@greatquux
Copy link
Author

greatquux commented Oct 29, 2020

I am running it as a local machine (and domain) Administrator, and UAC is completely disabled (EnableLUA set to 0). That's why in my screenshot I included Task Manager also to show I can see the usernames in there.

@dd86k
Copy link
Contributor

dd86k commented Oct 30, 2020

Unfortunately I have no TS setup and there seems to be no error code shown nor any kind of logging/tracing going on. Process.UserName is set to SYSTEM (_tcsncpy_s(Process.UserName, UNLEN, _T("SYSTEM"), UNLEN);) by default before attempting to open the process (OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, Entry.th32ProcessID);).

And my knowledge of Active Directory is rather limited. The doc for LookupAccountSid declares that the first parameter (lpSystemName), if NULL, looks on the local system first, then on trusted domain controllers (relative to the local computer), and if the machine is on an untrusted domain, that the parameter should be set.

But then I have not much of an idea for a trusted computer (joined?) on a domain. I feel like NULL is the same as "." and the name of the computer, but that could be tested out with a snapshot build could be done to show the error code (e.g. e00000000) to get a better clue.

List of possible failures:

  • OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION... returned NULL
    • Seems like UsedMemory is unset, either this or GetProcessMemoryInfo failed
    • Disk metrics are unset as well, NULL handle?
  • OpenProcessToken returned FALSE
  • The first GetTokenInformation didn't set its error code to ERROR_INSUFFICIENT_BUFFER
  • The second GetTokenInformation returned FALSE
  • LookupAccountSid failed

One thing I noticed is that the handle is never closed after the OpenProcess call. Microsoft recommends closing it when done.

My best guess is probably that the processes are protected as noted in https://docs.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights#protected-processes due to the handle being NULL (Io counters are unset as well).

Next question would be, is it a local Administrator account or one from the domain, if it's joined a domain?

@greatquux
Copy link
Author

The server is joined to a domain, and it's a domain Administrator account (that is a domain admin and local machine admin) that I'm logging into. Task Manager (and also Process Explorer) must be doing something different to get the user names as they show up there. I'll see if I am able to do a build myself and show any error codes.

@greatquux
Copy link
Author

It looks like LookupAccountSid is getting error 122, ERROR_INSUFFICIENT_BUFFER. That's the only error code I ever see, I just put a little GetLastError !=0 check after LookupAccountSid and printed it, but I'm not advanced enough in Win32 C programming to get much farther. :( I found a forum thread https://social.msdn.microsoft.com/Forums/en-US/b0c6d946-92a7-4f52-8809-4b8f72010219/lookupaccountsid-fails-with-strange-errors-in-a-thread-that-is-impersonating-a-pipe-client?forum=windowssecurity that seems to indicate you can just reallocate the buffer to make it a bit larger and try again?

@dd86k
Copy link
Contributor

dd86k commented Nov 4, 2020

ERROR_INSUFFICIENT_BUFFER directly from LookupAccountSid? That's surprising, since the account username is typically smaller than 256 (UNLEN) characters and the domain name is typically smaller than 260 (MAX_PATH) characters.

My main guess remains that OpenProcess returns NULL because it either has no permission or is simply incapable of processing the query for TS user processes since no other process information is filled out in your screenshot (e.g. used memory, which is processed before username, but only if it has a handle from OpenProcess).

It's possible that Task Manager (and other clones alike) use GetSecurityInfo (https://social.msdn.microsoft.com/Forums/en-US/b0c6d946-92a7-4f52-8809-4b8f72010219/lookupaccountsid-fails-with-strange-errors-in-a-thread-that-is-impersonating-a-pipe-client?forum=windowssecurity)... But then I'm not seeing the function being imported in taskmgr.exe.

Unfortunately my knowledge of Win32 is pretty limited too. I know no foss task managers

@gsass1
Copy link
Owner

gsass1 commented Nov 5, 2020

This is how ReactOS' taskmgr does it btw: https://doxygen.reactos.org/d7/dd5/perfdata_8c_source.html

@greatquux
Copy link
Author

greatquux commented Nov 5, 2020 via email

@dd86k
Copy link
Contributor

dd86k commented Nov 5, 2020

Interesting. Although seeing your snippet: I just remembered that the error code is only set when an error occurs, otherwise I think a successful call doesn't set the errorlevel for the thread (from the first GetTokenInformation). So it's normal you also see 122 on Windows with the provided snippet.

A better thing to print would be the result of LookupAccountSID (if it returns 0 then it failed).

@gsass1 That's interesting. Would you have a quick idea why the other fields (e.g. UsedMem, CPU time) are unset? I could try checking but I doubt I'd have anymore clue.

@greatquux
Copy link
Author

I saved the result from LookupAccountSID in a BOOL and it always came out 1, I put an if() around it and will only print it if's not true but I haven't gotten anything out of it. Interestingly, I tried it on another RD server that is not on a domain, just workgroup with local accounts, and even there we see that it can't get CPU, memory, or username values properly. Task Manager is included to show that it has them:

image

@dd86k
Copy link
Contributor

dd86k commented Nov 5, 2020

Looking at the ReactOS code: Curious that ReactOS does OpenProcessToken(hProcess, TOKEN_QUERY, &hProcessToken) betwen instead of TOKEN_READ as used in ntop. Want to try with TOKEN_QUERY instead? (Note: TOKEN_READ = TOKEN_QUERY | TOKEN_READ)

Otherwise curious if TokenUserStruct->User.Sid is set to NULL by the later GetTokenInformation.

@greatquux
Copy link
Author

Ugh. Still a mystery. Changing to TOKEN_QUERY had no effect. User.Sid is not NULL (and it seems to have valid values when I print it out). If I change the default SYSTEM to something like "default" in most cases it does come back as "default" so it's definitely not writing anything in there.

@dd86k
Copy link
Contributor

dd86k commented Nov 9, 2020

Checked around a bit (Well-known SIDs) and there values that have special meaning (e.g. S-1-1-0 for 'null' and S-1-5-32-555 for DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS (thanks Microsoft)). Since it's non-null, do you mind printing/checking a few SID values as examples? From there I'll have a better clue.

The ReactOS code is nice but it does not even support logging via Active Directory (see LDAP/ActiveDirectory at Missing ReactOS Functionality) so I doubt their Task Manager would be able to translate anything. Curses.

Sorry if I'm taking too long. Tonight I'll try getting 2008 R2 up and running and try something out.

@greatquux
Copy link
Author

I think I have finally figured things out. Once I got SIDs to print properly, and found I needed to use printf to properly redirect output to a file, and remembered my C pointer lessons from 25 years ago, I finally saw that the process loop was skipping over anything it couldn't get the info for on my RD server. The OpenProcess() call right after setting the default ExeName and UserName was failing but not because the Handle was NULL, because it did not have sufficient rights. On my workstation this happens to csrss.exe and the Idle process only, but on the RD server it was for everyone else.
If I run ntop.exe as SYSTEM, I can see all the usernames properly (and presumably the other stats). It looks like you need to give ntop.exe the SeDebugPrivilege privilege (or at least do it with a command line option) so that it can read stats on everything. It took a while to figure it all out, but as always, it was good to learn!

@dd86k
Copy link
Contributor

dd86k commented Nov 10, 2020

That's particular. Maybe I should add a command-line option for SeDebugPrivilege? (Or maybe PROCESS_ALL_ACCESS)

@greatquux
Copy link
Author

Maybe, but definitely experiment first on your computer to see if you are able to access the information about the csrss.exe process first. Right now I am having trouble even giving myself the SE_DEBUG_NAME privilege (even though I'm a local machine admin with UAC turned off) and I should really get back to "real work". :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants