Detection rules › Kusto
Access Token Manipulation - Create Process with Token
This query detects the use of the 'runas' command and checks whether the account used to elevate privileges isn't the user's own admin account. Additionally, it will match this event to the logon events - to check whether it has been successful as well as augment the event with the new SID.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Privilege Escalation | T1134.002 Access Token Manipulation: Create Process with Token |
| Stealth | T1134.002 Access Token Manipulation: Create Process with Token |
Event coverage
| Provider | Event/ActionType | Title |
|---|---|---|
| Sysmon | Event ID 1 | Process creation |
| Security-Auditing | Event ID 4688 | A new process has been created. |
| Defender-DeviceProcessEvents | any | Process activity (any) |
Rule body kusto
id: 8df80270-b4fa-4a7a-931e-8d17c0b321ae
name: Access Token Manipulation - Create Process with Token
description: |
This query detects the use of the 'runas' command and checks whether the account used to elevate privileges isn't the user's own admin account.
Additionally, it will match this event to the logon events - to check whether it has been successful as well as augment the event with the new SID.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- DeviceProcessEvents
- DeviceLogonEvents
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- PrivilegeEscalation
- DefenseEvasion
relevantTechniques:
- T1134.002
query: |
let RunAsProcess=DeviceProcessEvents
| where FileName =~ "runas.exe"
// You can choose to filter out the local admin account. This is based on convention. Here, we assume that localadmin accounts
// end with _ladmin (RID 500 / LAPS).
| where not(AccountName has_any("_ladmin"))
// De-obfuscate the commandline used.
| extend CleanProcessCommandLine=parse_command_line(tostring(ProcessCommandLine), "windows")
// Exclude a user running something on their system through their admin account.
| where CleanProcessCommandLine !contains strcat(AccountName, "_adm") // Replace this with your admin account naming convention.
// Exclude local admin account activities by, for instance, the servicedesk that uses the LAPS provisioned account. This is optional.
// Disable the line below if the number of false positives is acceptable.
| where not(CleanProcessCommandLine has_any (":_ladmin")) // Replace this with your local RID500/LAPS account.
// Extract the username for the elevation action.
| extend ElevatedAccountName=extract("user:([a-zA-Z0-9\\\\]+)",1,tostring(CleanProcessCommandLine))
// Strip the domain suffix.
| extend CleanElevatedAccountName= trim("(.*\\\\)",ElevatedAccountName);
RunAsProcess
| join kind=leftouter (
DeviceLogonEvents
| project-rename CleanElevatedAccountName = AccountName
) on CleanElevatedAccountName,DeviceId
| project-rename ElevatedActionType=ActionType1,ElevatedAccountSid=AccountSid1
| project TimeGenerated,DeviceId,DeviceName,FileName,FolderPath,ProcessCommandLine,SHA256,ProcessIntegrityLevel,AccountDomain,AccountName,AccountSid, LogonId, InitiatingProcessFileName,InitiatingProcessFolderPath,InitiatingProcessCommandLine,CleanProcessCommandLine,ElevatedAccountName,CleanElevatedAccountName,ElevatedActionType,LogonType,ElevatedAccountSid
entityMappings:
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: DeviceName
- entityType: Account
fieldMappings:
- identifier: Sid
columnName: AccountSid
- identifier: Name
columnName: AccountName
- identifier: NTDomain
columnName: AccountDomain
- entityType: Process
fieldMappings:
- identifier: CommandLine
columnName: ProcessCommandLine
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 0: let
let RunAsProcess = DeviceProcessEvents <inlined as stages below>;
The stages below define let RunAsProcess (the rule's main pipeline source).
Stage 1: source
DeviceProcessEvents
Stage 2: where
| where FileName =~ "runas.exe"
Stage 3: where
| where not(AccountName has_any("_ladmin"))
Stage 4: extend
| extend CleanProcessCommandLine=parse_command_line(tostring(ProcessCommandLine), "windows")
Stage 5: where
| where CleanProcessCommandLine !contains strcat(AccountName, "_adm")
Stage 6: where
| where not(CleanProcessCommandLine has_any (":_ladmin"))
Stage 7: extend
| extend ElevatedAccountName=extract("user:([a-zA-Z0-9\\\\]+)",1,tostring(CleanProcessCommandLine))
Stage 8: extend
| extend CleanElevatedAccountName= trim("(.*\\\\)",ElevatedAccountName)
The stages below run on RunAsProcess (the outer pipeline).
Stage 9: join
RunAsProcess
| join kind=leftouter (
DeviceLogonEvents
| project-rename CleanElevatedAccountName = AccountName
) on CleanElevatedAccountName,DeviceId
Stage 10: project-rename
| project-rename ElevatedActionType=ActionType1,ElevatedAccountSid=AccountSid1
Stage 11: project
| project TimeGenerated,DeviceId,DeviceName,FileName,FolderPath,ProcessCommandLine,SHA256,ProcessIntegrityLevel,AccountDomain,AccountName,AccountSid, LogonId, InitiatingProcessFileName,InitiatingProcessFolderPath,InitiatingProcessCommandLine,CleanProcessCommandLine,ElevatedAccountName,CleanElevatedAccountName,ElevatedActionType,LogonType,ElevatedAccountSid
Exclusions
Top-level NOT(...) conjuncts: predicates this rule actively suppresses.
| Field | Kind | Excluded values |
|---|---|---|
AccountName | match | _ladmin |
CleanProcessCommandLine | match | :_ladmin |
Indicators
Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.
| Field | Kind | Values |
|---|---|---|
CleanProcessCommandLine | cross_field_compare |
|
FileName | eq |
|
Output fields
Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.
| Field | Source |
|---|---|
AccountDomain | project |
AccountName | project |
AccountSid | project |
CleanElevatedAccountName | project |
CleanProcessCommandLine | project |
DeviceId | project |
DeviceName | project |
ElevatedAccountName | project |
ElevatedAccountSid | project |
ElevatedActionType | project |
FileName | project |
FolderPath | project |
InitiatingProcessCommandLine | project |
InitiatingProcessFileName | project |
InitiatingProcessFolderPath | project |
LogonId | project |
LogonType | project |
ProcessCommandLine | project |
ProcessIntegrityLevel | project |
SHA256 | project |
TimeGenerated | project |