Friday, 10 December 2021

Detecting Token Stealing using Sysmon v13.30 and EQL


Access token manipulation is a well known technique often used to elevate privileges or to execute in the context of a different identity.  There are different implementations of this technique but the most observed one seen in malwares as well as in common offensive frameworks (i.e. metasploit incognito, cobalt srike steal_token) is often referred to as Token Stealing and aims to elevate privileges from high integrity to System integrity.

If you are interested to know more about the implementation part of this technique I would recommend the following reading :

The classic implementation invole those steps / APIs: 
  1. Enable SeDebugPrivilege (needed for Step 2 and require high integrity)
  2. Obtain a handle to a process running as System via OpenProcess (victim)
  3. Obtain Token handle of the System process via OpenProcessToken 
  4. Duplicate stolen token via ImpersonateLoggedOnUser and DuplicateTokenEx
  5. Create a SYSTEM child process with the token duplicate via CreateProcessWithTokenW

For step 2 (critical step) usually the source process (Malware) will be running as High integrity and won't be able to obtain Full access rights to all System processes (i.e. PPL). 

The minimum needed Access rights are enough to obtain a valid access handle that allow to proceed to step 3:

0x1400 - PROCESS_QUERY_INFORMATION : High to System, fails on PPL protected processes such as the following: 

0x1000 - PROCESS_QUERY_LIMITED_INFORMATION (High to system, works on PPL protected processes)

Also something worth noting is that winlogon.exe is one of the most targeted processes (not PPL and runs as system).


For detection there are some opportunities such as the one described in this blog using custom SACLs to audit a list of selected processes object access via event 4656 (very noisy, often not logged in prod and captures step 2 only) or baselining processes enabling the SeDebugPrivlege using event 4703 (captures step 1 only). 

In this post we will be using Sysmon v.13.30 that added recently some cool enrichment (SourceUser,  TargetUser for process Access events and ParentUser for process creation events) and that we can play with to create a more resilient detection. Before going to the detection logic let's breakdown the key steps/artifacts:

Step 1 - Windows security 4703

Step 2 - Sysmon  Process Access - 10 (Target is a System process and source is not)

Step 3 and 4 - No Events

Step 5 - System Process Creation  

From the above events we can create a correlation (using Elastic EQL) to link artifact from Step2 and Step 5 :

  1. Process Access event from Process A running as normal user to Process B running as SYSTEM (Sysmon 13.30 - Source User and Target User) 
  2. Process A running as normal user (Sysmon 13.30 ParentUser) spawns a child process running as SYSTEM.

sequence with maxspan=1m
  [process where event.code : "10" and
  GrantedAccess values in scope
  winlog.event_data.GrantedAccess :

("0x1000", "0x1400", "0x1F3FFF") and
    winlog.event_data.TargetUser : "NT AUTHORITY\\SYSTEM" and not
    winlog.event_data.SourceUser : "NT AUTHORITY\\*" and
    winlog.event_data.TargetImage : "?:\\Windows\\*.exe"] by process.entity_id
[process where event.code : "1" and
    winlog.event_data.LogonId : "0x3e7" and
    winlog.event_data.TerminalSessionId : "1" and
    not winlog.event_data.ParentUser : "NT AUTHORITY\\*"] by process.parent.entity_id

Testing our detection logic

Same logic triggers on malwares such as Glupteba and Zenpack implementation:

For Sysmon config I would recommend to limit it to commonly targeted System processes like winlogon.exe, lsass.exe and TrustedInstaller.exe if you want to limit sysmon 10 eventing volume.