1

I'm curious from a security standpoint, how bad is it to do what I describe below?

I need to launch an elevated process in an interactive logon user session from my local service. This process merely exists as a message-only GUI window, which is never visible to the user, and it's class name is randomized every time the process starts.

It speeds things up if I run this process with the user token of the local service as such:

//Pseudo-code, error checks are omitted for brevity
//This code is run from a local-service with SYSTEM credentials

PSID gpSidMIL_High;
ConvertStringSidToSid(L"S-1-16-12288", &gpSidMIL_High);

HANDLE hToken, hToken2;

OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken);
DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hToken2);

SetTokenInformation(hToken2, TokenSessionId, &userSessionID, sizeof(userSessionID));

DWORD dwUIAccess = 1;
SetTokenInformation(hToken2, TokenUIAccess, &dwUIAccess, sizeof(dwUIAccess));

//Set "high" mandatory integrity level
TOKEN_MANDATORY_LABEL tml = {0};
tml.Label.Attributes = SE_GROUP_INTEGRITY;
tml.Label.Sid = gpSidMIL_High;

SetTokenInformation(hToken2, TokenIntegrityLevel, &tml, sizeof(TOKEN_MANDATORY_LABEL) + ::GetSidLengthRequired(1));

CreateEnvironmentBlock(&pEnvBlock, hToken2, FALSE);

ImpersonateLoggedOnUser(hToken2);
CreateProcessAsUser(hToken2,,,,,,,pEnvBlock,,);
RevertToSelf();

//Clean-up
DestroyEnvironmentBlock(pEnvBlock);
CloseHandle(hToken2);
CloseHandle(hToken);
LocalFree(gpSidMIL_High);
c00000fd
  • 20,994
  • 29
  • 177
  • 400
  • 1
    I'm not expert in this area so I'll refrain from attempting to answer the question, but I believe that in order to get a meaningful answer you would need to provide a better description of what the elevated process does, and in particular the way window messages are handled. – Harry Johnston Jul 18 '16 at 06:38
  • @HarryJohnston: It's used to process messages for [WH_KEYBOARD_LL](https://msdn.microsoft.com/en-us/library/windows/desktop/ms644985(v=vs.85).aspx) hook. – c00000fd Jul 18 '16 at 06:43
  • 1
    An all powerful hidden keylogger. What could possibly go wrong? – David Heffernan Jul 18 '16 at 08:20
  • @DavidHeffernan: I wouldn't be concerned about security of the user's system if I was writing an _"all powerful hidden keylogger"_, would I? – c00000fd Jul 18 '16 at 08:35
  • @DavidHeffernan: Considering the process runs as `SYSTEM`, that's pretty irrelevant. A process with the right to do everything can do everything. Security is about preventing unauthorized privilege _increases_. – MSalters Jul 18 '16 at 10:03
  • @MSalters What about shatter attacks? Doesn't putting a `SYSTEM` account into an interactive session increase the surface area for such attacks? – David Heffernan Jul 18 '16 at 10:16
  • @DavidHeffernan: That is a real concern. In fact, any kind of permission and privilege is a risk. That's unrelated to the "hidden" and keylogger" part, though."I would argue that the "hidden" part in fact makes it safer, because it means the process gets less messages which decreases the attack surface. – MSalters Jul 18 '16 at 10:51
  • 2
    Doing this essentially grants `SYSTEM` privileges to the user. This is called *privilege escalation*. The system really is just one [CreateRemoteThread](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682437.aspx) away from being pwned. The fact that there is no visible GUI, and the window class name being randomized is no protection whatsoever. The protection happens at session boundaries. That's why services run isolated in session 0. Your code basically loosens security back to what it was in Windows XP and before. – IInspectable Jul 18 '16 at 12:47
  • @IInspectable: it isn't quite that easy, `CreateRemoteThread` would be blocked by the process ACL. Shatter attacks should be blocked by the integrity mechanism. What I'm not sure of is what other vectors there are. – Harry Johnston Jul 18 '16 at 22:54
  • You might try asking this on Security SE? (I'm not sure offhand whether it would be on-topic, you should check first.) More likely to attract the relevant experts. – Harry Johnston Jul 18 '16 at 22:55
  • @IInspectable: First off, thank you everyone. To IInspectable's comments, how will my process be different than, say, "winlogon.exe" that also runs as a SYSTEM in a user session? – c00000fd Jul 19 '16 at 00:10
  • @HarryJohnston: Also how would you suggest "prepping up" this user process ACL? Like I showed it's already running with high `mandatory integrity level`, so most messages to it will be blocked by UIPI from a process running in a normal user session. The only way to highjack it is to `OpenProcess` and then get its token and then inject `CreateRemoreThread` into it, but in that case why would my process be different than `winlogon.exe` like I mentioned above? – c00000fd Jul 19 '16 at 00:15
  • I think the default ACL will be fine as far as that goes, but you'd better check it. Make sure unprivileged users don't have any rights (Except perhaps `PROCESS_QUERY_INFORMATION`, `PROCESS_QUERY_LIMITED_INFORMATION`, and `SYNCHRONIZE`.) As for `winlogon.exe`, I believe it runs on the secure desktop, whereas your process is on the default desktop. Quite different from a security perspective. – Harry Johnston Jul 19 '16 at 00:24
  • @HarryJohnston: Yes, good point. `winlogon.exe` does run in a secure desktop. Although from a perspective of the malware coder it won't make any difference. As long as they can inject into it, it's game over. They can write into a secure file system location and launch their process from there at the next boot. So to inject into `winlogon.exe` they need to get its process ID and then open its process and get its token. All of which would be prevented by the `SYSTEM` account's ACL... which is the same for my process. So that is why I was questioning it... – c00000fd Jul 19 '16 at 01:54
  • *Although from a perspective of the malware coder it won't make any difference.* - not necessarily. Shatter attacks, for example, only work if you can run code in the same desktop as the target process. – Harry Johnston Jul 19 '16 at 01:59
  • @HarryJohnston: Well, first off Shatter attacks go back to pre-Vista OS. But still, as I showed above, I'm using `UIPI` and [MIL](https://msdn.microsoft.com/en-us/library/bb625963.aspx) to prevent any user process from being able to send messages to my process. Heck, instead of using `high` MIL I can go with `system` MIL since I have that token. Plus, say even if some process manages to send messages to my user process, they need to know its window handle. How would they get that? – c00000fd Jul 19 '16 at 02:07
  • I think you could find a window handle by brute force, aren't they assigned pretty much sequentially? Integrity level should stop shatter attacks, yes. But there may be other attack vectors that depend on being on the same desktop. If nothing else, any vulnerability in the integrity level system would expose your process, even one that might otherwise be harmless. (Hence my suggestion to ask at Security SE, they're probably more up-to-date with the latest attacks.) – Harry Johnston Jul 19 '16 at 02:58
  • @HarryJohnston: You mean [this one](http://security.stackexchange.com/)? They usually deal w/encryption & passwords but not programming like SO. But I'll try, thanks. Let's see how fast they can close it :) – c00000fd Jul 19 '16 at 03:02
  • Also, just an afterthought. I can technically launch my user process elevated (as I was [originally asking here](http://stackoverflow.com/q/38429078/843732)) but then we're kinda going back to the same issue -- if someone hijacks it, they can install their own service and start it. Thus have a full `SYSTEM` user token for their disposal. So what is the purpose then? And I do need to run that user process elevated for my app to work. – c00000fd Jul 19 '16 at 03:02
  • True, if the user has admin privilege, your SYSTEM process is (presumably) no more dangerous than any other elevated process the user might start, or have started on their behalf. But the best practice is for the user to *not* have admin privilege, and that's the scenario where running the process as SYSTEM exposes the system in ways that running it as the user doesn't. (You'll note that most of the concerns being expressed are about a malicious user, which is moot if the user is an admin anyway.) – Harry Johnston Jul 19 '16 at 03:11
  • winlogon is a trusted part of the system. Your software is not. MS have put their software through huge auditing processes and still there are vulnerabilities. Will you have security experts audit your software? – David Heffernan Jul 19 '16 at 06:16

1 Answers1

0

Looks pretty bad. The process has way too much rights. The process is at the risk of being hijacked by the user in whose session you run, which would give him SYSTEM rights that he generally does not own.

The proper design is to have the hook process be capable of doing nothing. Communicate the keyboard events back to the service. Your hook doesn't need to be SYSTEM for this. It's probably wise to call AdjustTokenPrivileges to irrevocably drop all privileges (which you don't need). Even if your hook process was hijacked, it can't regain those privileges.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • As it turns out, it [was the hooking itself that the OP needed admin privilege for](http://stackoverflow.com/q/38429078/886887), but only in the case where the interactive user has administrator privilege already. I am curious though, are there any *known* attack vectors against a high-integrity process with a sensible ACL? Or is it just a case of defense-in-depth? – Harry Johnston Jul 18 '16 at 23:02
  • Hmm. Yep, although I'm not sure if `AdjustTokenPrivileges` can drop privileges. Can it? Although just the `SYSTEM` user token gives that process membership in the admin group and `local system` group which by itself opens up doors for many other "nasty" things an injected code can do. – c00000fd Jul 19 '16 at 00:17
  • @c00000fd: [It can](http://stackoverflow.com/questions/1533017/dropping-privileges-in-c-on-windows). – MSalters Jul 19 '16 at 07:05