Get SID from IO_SECURITY_CONTEXT in PreCreate

Hello,

I am developing a Windows Minifilter driver and I am trying to get the user’s SID from the IO_SECURITY_CONTEXT structure in the PreCreate operation. I am aware that there is no way to directly get the SID from the IO_SECURITY_CONTEXT in other operations as the SID is only checked by the system on create operations.

I have tried multiple solutions in order to extract the SID_AND_ATTRIBUTES structure from the IO_SECURITY_CONTEXT structure. As for now I am trying the following:

  1. Get the token from SECURITY_SUBJECT_CONTEXT inside PACCESS_STATE inside IO_SECURITY_CONTEXT (SecurityContext->AccessState.SecuritySubjectContext). If the ClientToken is NULL, then I take the PrimaryToken.
  2. Call ObOpenObjectByPointer(AccessToken, OBJ_CASE_INSENSITIVE, NULL, TOKEN_QUERY, NULL, KernelMode, &TokenHandle); Where TokenHandle is a HANDLE.
  3. Call ZwQueryInformationToken to query for TokenUser with a NULL buffer in order to get the return length size.
  4. Allocate the buffer with the given size.
  5. Call ZwQueryInformationToken again with the newly allocated buffer. This should fill the buffer with a SID_AND_ATTRIBUTES structure.
  6. Call ZwClose on the TokenHandle.

The problem is that on step 2, calling ObOpenObjectByPointer generates a 00000000c0000005 access violation.

SYSTEM_SERVICE_EXCEPTION (3b)
An exception happened while executing a system service routine.
Arguments:
Arg1: 00000000c0000005, Exception code that caused the bugcheck
Arg2: fffff8047d518d62, Address of the instruction which caused the bugcheck
Arg3: fffffe87a08ad8a0, Address of the context record for the exception that caused the bugcheck
Arg4: 0000000000000000, zero.

I have checked the contents of the SECURITY_SUBJECT_CONTEXT using the command kp and I can see the following token pointers inside this structure:

(*((<REDACTED>!_SECURITY_SUBJECT_CONTEXT *)0xffffb30e4656b900))                 [Type: _SECURITY_SUBJECT_CONTEXT]
    [+0x000] ClientToken      : 0x3066744e03030000 [Type: void *]
    [+0x008] ImpersonationLevel : SecurityAnonymous (0) [Type: _SECURITY_IMPERSONATION_LEVEL]
    [+0x010] PrimaryToken     : 0xffffb30e458aa460 [Type: void *]
    [+0x018] ProcessAuditId   : 0xffffb30e466cd448 [Type: void *]

Now I check the data on both of the memory addresses (ClientToken and PrimaryToken) using the db command and I get lots of question marks, I guess that means that memory is not accessible by the driver?

3066744e`03030000  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
3066744e`03030010  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
...

Sometimes the PrimaryToken pointer will point to access data, but sometimes both (Client and Primary) will point to inaccessible data.

I basically want to get the SID in order to pass it as a string representation to one of my user mode modules. Despite following all kinds of posts on this and other forums I have been unable to get the SID_AND_ATTRIBUTES from the SECURITY_CONTEXT in PreCreate. I have now been stuck for several weeks with this problem.

How may I solve this problem? What am I doing wrong? Any help is really appreciated.

During create processing you are guaranteed to be in the correct security context, so you don’t need to look at the IRP, just interrogate the current thread.

That client token address is bogus. Looks like the start of a pool block instead of a valid pointer:

0: kd> .formats 0x3066744e03030000 
Evaluate expression:
..
  Chars:   0ftN....
..

So, you’re grabbing the wrong pointer somehow (or you’re looking at freed memory). I recently posted a working example here if you want to try that.

1 Like

@rod_widdowson said:
During create processing you are guaranteed to be in the correct security context, so you don’t need to look at the IRP, just interrogate the current thread.

A minifilter above you could post the create to another thread before sending it down. Not common but it works (the file systems use the token in the IRP so they “just work”)

A minifilter above you could post the create to another thread before sending it down

Yes, but they are obliged to handle the security by impersonating (otherwise the FSD would complain when it did security checks).

Thanks for your responses! I will try out the working example provided by Scott and will let you know if it worked.

Of course as I my comment becomes uneditable I realise that the FSD should be looking at the SecurityContext as well (not the thread context) - in my experience this isn’t always the case… So whenever I post a create I also impersonate - but I’d agree that the architecture means you shouldn’t have to.

Scott’s code worked like a charm! It was very similar to one of the first I tried to use. The only difference was that I was not calling SeLockSubjectContext before using the SeQuerySubjectContextToken macro.

1 Like