How do I get the caller SID in kernel mode hook? (windows) - windows

I'm developing a driver that hooks some functions in windows (hardening driver that will block some actions). The problem is, that I want to log which was the user who attempted to run those actions.
For example, I've put an hook on ZwSetValueKey in order to filter registry writing.
The hook works perfectly, But I don't know how to get the caller SID. I've found out that I can determine whether the mode of the caller(i.e. user mode or kernel mode) using ExGetPreviousMode. But I'm not really sure how to determine the SID if the caller was in user mode.
Thanks.

If this were user mode, you'd start with GetCurrentProcess or GetCurrentThread, and then call GetProcessToken or GetThreadToken. This would get you an access token, from which the SID can be extracted directly. In kernel model, there's PsGetCurrentProcess and ZwOpenProcessTokenEx, and the like for threads.
Here's the equivalent question for user space: How to get Calling-Process Windows User Access Token.
I haven't tested this, but I hope it gets you started.

VOID SeCaptureSubjectContext(Out PSECURITY_SUBJECT_CONTEXT) is probably the kernel-mode API you're looking for, at least if you have ntifs.h available.

Related

How to call usermode from Windows kernel?

I'd like to call my app from my driver when an interesting event happens in the Windows kernel. I need to be able to pass at least 4 bytes of data back to user mode. How to achieve this? These events might happen quite, but not too, often, so I don't want to build a queue system and use IOCTLs.
I was thinking of something like the driver gets loaded, the user mode app registers its callback using IOCTL and kernel keeps calling that callback when events happen and finally the user mode client unregisters the callback and no more data is send to user mode. Is this possible?
I'm new to kernel programming, so after a day of googling I decided to ask here. I've noticed that there isn't much discussion about the kernel and drivers. And even less proper docs.

Intercepting process execution in a NT driver

I have developed a driver for Windows XP which is able to monitor the execution of processes.
A callback function receives the notifications using standard WDK API (PsSetCreateProcessNotifyRoutine).
The driver then decides if the process should be authorized or not; if not, it must block its execution/kill it.
What is the cleanest way to intercept execution that way? I do not mind if it is not documented, but I would rather not resort to hooking, if possible.
Ok, according to this document:
http://download.microsoft.com/download/4/4/b/44bb7147-f058-4002-9ab2-ed22870e3fe9/Kernal%20Data%20and%20Filtering%20Support%20for%20Windows%20Server%202008.doc
I need to install a minifilter for IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION and check for PageProtection == PAGE_EXECUTE.
PsSetCreateProcessNotifyRoutineEx (Vista+) will allow you to cause the process-creation operation to fail by changing the CreateInfo->CreationStatus member to an NTSTATUS error code.

Is passing a windows security token between processes permitted

Imagine I have an existing process running under windows as a particular user. Would it be permitted for that process to take its current token (with something like OpenThreadToken and DuplicateTokenEx), pass it to another process on the same machine (perhaps through a network socket or some other IPC), and then expect that process to be able to use it to call CreateProcessAsUser?
From the documentation I have read (http://msdn.microsoft.com/en-us/library/ms682429%28VS.85%29.aspx), I've seen nothing which prohibits this but perhaps the token can only be used by the thread or process which created it.
(Why would you? I want to has a web request come to IIS, be authenticated, have IIS arrange the impersonation of the remote user and then pass the impersonation token to another server process (on the same machine) so that the server process can perform some security checks in the context of the remote user)
Yes, that is possible. You can use DuplicateHandle to get a handle that is valid for the target process (send the new handle value to the target process, so it knows it.).
However, the target process must still have the privileges to use the token accordingly. E.g. SE_IMPERSONATE to impersonate the user and SE_ASSIGN_PRIMARY to be used by CPAU. Of course there are some exceptions that you can read in MSDN for ImpersonateLoggedOnUser and CPAU.
I haven't tried it, but it seems that this is the same question asked here. The description seems to make sense. Pass the process ID via whatever mechanism you choose (e.g., IPC), then call OpenProcess, OpenProcessToken, and finally ImpersonateLoggedOnUser. The resulting handle could be passed to CreateProcessAsUser. Well ... I know it could be passed to that function but whether it would have the desired result I do not know. Interesting question, though.
Why not just use named pipes, and then call ImpersonateNamedPipeUser() - it's safe and secure and easy! Note that the process doing the impersonation MUST have the Impersonation privilege.

Blocking mouse input from a service in Vista

I maintain a variety of managed userlabs on a university campus. These machines all currently run Windows XP and we have a windows service that is used to "lock" a machine by blocking any keyboard or mouse input. The locking happens during our scripted OS installation so that users aren't able to accidentally halt or break the process. It is also used to prevent users from logging into machines until they are checked out at the front desk of a given lab. Ctrl+Alt+Del is blocked via a keyboard filter driver and the rest of the keys and mouse are currently blocked using the BlockInput() function from user32.dll.
In XP, the service runs as Local System and the checkbox for "Allow service to interact with desktop" must be enabled from the BlockInput() call to succeed. Under Vista, this no longer works I'm guessing because of the Session 0 isolation changes. The call succeeds, but input is not actually blocked.
The keyboard filter driver still works just fine and we can use that to block the whole keyboard instead of just Ctrl+Alt+Del. But I'm at a loss as to how we're going to block the mouse now. I'm not even entirely sure the Session 0 isolation is to blame.
Can anyone recommend a fix or a workaround to allow us to block mouse input from a service in Vista and beyond? I've looked for alternative win32 API's without luck. Assuming Session 0 isolation is to blame, is there a legitimate way to call the function from Session 1 or would that sort of defeat the purpose of the isolation? Will I have to rely on an elevated companion exe that runs on user login and communicates with the service?
From a service, you can use WTSEnumerateSessions to get all logged on user sessions, WTSQueryUserToken to get the logged on user's token, and then use CreateProcessAsUser with that token to get code running on the user's desktop. This has the disadvantage that the code will run as the logged on user. Since all input is disabled, this is probably safe enough and is at least as safe as the existing XP solution.]
EDIT: BlockInput requires a high mandatory integrity level. You could try adding this group to the token, but then you have code with higher privileges running on the desktop and potentially open to attacks.
An alternative might be to use your service just to disable all HID class devices on the machine.

CreateProcessAsUser vs ShellExecute

I need to ShellExecute something as another user, currently I start a helper process with CreateProcessAsUser that calls ShellExecute, but that seems like too much of a hack (Wrong parent process etc.) Is there a better way to do this?
#PabloG: ImpersonateLoggedOnUser does not work:
HANDLE hTok;
VERIFY(LogonUser("otheruser",0,"password",LOGON32_LOGON_INTERACTIVE,LOGON32_PROVIDER_DEFAULT,&hTok));
VERIFY(ImpersonateLoggedOnUser(hTok));
ShellExecute(0,0,"calc.exe",0,0,SW_SHOW);
RevertToSelf();
CloseHandle(hTok);
will just start calc as the logged in user, not "otheruser"
#1800 INFORMATION: CreateProcess/CreateProcessAsUser is not the same as ShellExecute, with UAC on Vista, CreateProcess is useless when you don't have control over what program the user is executing (CreateProcess will return with a error if you give it a exe file with a manifest marked as requireAdmin)
#Brian R. Bondy: I already know this info (And don't get me wrong, its good stuff), but it is off topic (IMHO) I am asking for a ShellExecuteAsUser, not about starting processes as another user, I already know how to do that.
The solution really depends on what your needs are, and can be pretty complex (Thanks fully to Windows Vista). This is probably going to be beyond your need, but this will help others that find this page via search.
If you do not need the process to run with a GUI and you do not require elevation
If the user you want to run as is already logged into a session
If you need to run the process with a GUI, and the user may, or may not be logged in
If you need to run the process with elevation
Regarding 1:
In windows Vista there exists something called session 0 isolation. All services run as session 0 and you are not supposed to have a GUI in session 0. The first logged on user is logged into session 1. In previous versions of windows (pre Vista), the first logged on user was also ran fully in session 0.
You can run several different processes with different usernames in the same session. You can find a good document about session 0 isolation here.
Since we're dealing with option 1), you don't need a GUI. Therefore you can start your process in session 0.
You'll want a call sequence something like this:
LogonUser, ExpandEnvironmentStringsForUser, GetLogonSID, LoadUserProfile, CreateEnvironmentBlock, CreateProcessAsUser.
Example code for this can be found via any search engine, or via Google code search
Regarding 2: If the user you'd like to run the process as is already logged in, you can simply use: WTSEnumerateSessions, and WTSQuerySessionInformation to get the session ID, and then WTSQueryUserToken to get the user token. From there you can just use the user token in the CreateProcessAsUser Win32 API.
This is a great method because you don't even need to login as the user nor know the user's username/password. I believe this is only possible via a service though running as local system account.
You can get the current session via WTSGetActiveConsoleSessionId.
Regarding 3:
You would follow the same steps as #1, but in addition you would use the STARTUPINFO's lpDesktop field. Set this to winsta0\Default. You will also need to try to use the OpenDesktop Win32 API and if this fails you can CreateDesktop. Before using the station and desktop handles you should use SetSecurityInfo on each of them with SE_WINDOW_OBJECT, and GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION.
If the user in question later tries to login, he will actually see the running process.
Regarding 4:
This can be done as well, but it requires you to already be running an elevated process. A service running as local system account does run as elevated. I could also only get it to work by having an authenticode signed process that I wanted to start. The process you want to start also must have a manifest file associated with it with the requestedExecutionLevel level="requireAdministrator"
Other notes:
You can set a token's session via SetTokenInformation and TokenSessionId
You cannot change the session ID of an already running process.
This whole process would be drastically more simple if Vista was not in the equation.
If you need ShellExecute semantics you can feed following:
C:\windwos\system32\cmd.exe /k" start <your_target_to_be_ShellExecuted>"
to CreateProcessAsUser and you are done.
You can wrap the ShellExecute between ImpersonateLoggedOnUser / RevertToSelf
links:
ImpersonateLoggedOnUser: http://msdn.microsoft.com/en-us/library/aa378612(VS.85).aspx
RevertToSelf: http://msdn.microsoft.com/en-us/library/aa379317.aspx
sorry, cannot hyperlink URLs with "()"
Why don't you just do CreateProcessAsUser specifying the process you want to run?
You may also be able to use SHCreateProcessAsUserW.

Resources