Detection rules › Kusto

Powershell Empire Cmdlets Executed in Command Line

Status
available
Severity
medium
Time window
12h
Source
github.com/Azure/Azure-Sentinel

This query identifies use of PowerShell Empire's cmdlets within the command line data of the PowerShell process, indicating potential use of the post-exploitation tool.

MITRE ATT&CK coverage

TacticTechniques
ExecutionT1047 Windows Management Instrumentation, T1053.005 Scheduled Task/Job: Scheduled Task, T1059.001 Command and Scripting Interpreter: PowerShell, T1059.003 Command and Scripting Interpreter: Windows Command Shell, T1106 Native API, T1127.001 Trusted Developer Utilities Proxy Execution: MSBuild, T1569.002 System Services: Service Execution, T1574.001 Hijack Execution Flow: DLL, T1574.004 Hijack Execution Flow: Dylib Hijacking, T1574.007 Hijack Execution Flow: Path Interception by PATH Environment Variable, T1574.008 Hijack Execution Flow: Path Interception by Search Order Hijacking, T1574.009 Hijack Execution Flow: Path Interception by Unquoted Path
PersistenceT1053.005 Scheduled Task/Job: Scheduled Task, T1136.001 Create Account: Local Account, T1136.002 Create Account: Domain Account, T1543.003 Create or Modify System Process: Windows Service, T1546.008 Event Triggered Execution: Accessibility Features, T1547.001 Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder, T1547.005 Boot or Logon Autostart Execution: Security Support Provider, T1547.009 Boot or Logon Autostart Execution: Shortcut Modification
Privilege EscalationT1053.005 Scheduled Task/Job: Scheduled Task, T1055 Process Injection, T1068 Exploitation for Privilege Escalation, T1134.002 Access Token Manipulation: Create Process with Token, T1134.005 Access Token Manipulation: SID-History Injection, T1484.001 Domain or Tenant Policy Modification: Group Policy Modification, T1543.003 Create or Modify System Process: Windows Service, T1546.008 Event Triggered Execution: Accessibility Features, T1547.001 Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder, T1547.005 Boot or Logon Autostart Execution: Security Support Provider, T1547.009 Boot or Logon Autostart Execution: Shortcut Modification, T1548.002 Abuse Elevation Control Mechanism: Bypass User Account Control
StealthT1027 Obfuscated Files or Information, T1055 Process Injection, T1070.006 Indicator Removal: Timestomp, T1127.001 Trusted Developer Utilities Proxy Execution: MSBuild, T1134.002 Access Token Manipulation: Create Process with Token, T1134.005 Access Token Manipulation: SID-History Injection, T1574.001 Hijack Execution Flow: DLL, T1574.004 Hijack Execution Flow: Dylib Hijacking, T1574.007 Hijack Execution Flow: Path Interception by PATH Environment Variable, T1574.008 Hijack Execution Flow: Path Interception by Search Order Hijacking, T1574.009 Hijack Execution Flow: Path Interception by Unquoted Path
Credential AccessT1003.001 OS Credential Dumping: LSASS Memory, T1040 Network Sniffing, T1056.001 Input Capture: Keylogging, T1056.004 Input Capture: Credential API Hooking, T1552.001 Unsecured Credentials: Credentials In Files, T1552.004 Unsecured Credentials: Private Keys, T1555.003 Credentials from Password Stores: Credentials from Web Browsers, T1557.001 Adversary-in-the-Middle: Name Resolution Poisoning and SMB Relay, T1558.002 Steal or Forge Kerberos Tickets: Silver Ticket, T1558.003 Steal or Forge Kerberos Tickets: Kerberoasting
DiscoveryT1016 System Network Configuration Discovery, T1040 Network Sniffing, T1046 Network Service Discovery, T1049 System Network Connections Discovery, T1057 Process Discovery, T1082 System Information Discovery, T1083 File and Directory Discovery, T1087.001 Account Discovery: Local Account, T1087.002 Account Discovery: Domain Account, T1135 Network Share Discovery, T1217 Browser Information Discovery, T1482 Domain Trust Discovery, T1518.001 Software Discovery: Security Software Discovery, T1615 Group Policy Discovery
Lateral MovementT1021.003 Remote Services: Distributed Component Object Model, T1021.004 Remote Services: SSH, T1210 Exploitation of Remote Services, T1550.002 Use Alternate Authentication Material: Pass the Hash
CollectionT1056.001 Input Capture: Keylogging, T1056.004 Input Capture: Credential API Hooking, T1113 Screen Capture, T1114.001 Email Collection: Local Email Collection, T1115 Clipboard Data, T1125 Video Capture, T1557.001 Adversary-in-the-Middle: Name Resolution Poisoning and SMB Relay, T1560 Archive Collected Data
Command & ControlT1071.001 Application Layer Protocol: Web Protocols, T1102.002 Web Service: Bidirectional Communication, T1105 Ingress Tool Transfer, T1573.002 Encrypted Channel: Asymmetric Cryptography
ExfiltrationT1041 Exfiltration Over C2 Channel, T1567.001 Exfiltration Over Web Service: Exfiltration to Code Repository, T1567.002 Exfiltration Over Web Service: Exfiltration to Cloud Storage

Event coverage

Rule body kusto

id: ef88eb96-861c-43a0-ab16-f3835a97c928
name: Powershell Empire Cmdlets Executed in Command Line
description: |
  'This query identifies use of PowerShell Empire's cmdlets within the command line data of the PowerShell process, indicating potential use of the post-exploitation tool.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: SecurityEvents
    dataTypes:
      - SecurityEvent
  - connectorId: WindowsSecurityEvents
    dataTypes:
      - SecurityEvent
  - connectorId: WindowsSecurityEvents
    dataTypes:
      - SecurityEvents
  - connectorId: WindowsForwardedEvents
    dataTypes:
      - WindowsEvent
queryFrequency: 12h
queryPeriod: 12h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Collection
  - CommandAndControl
  - CredentialAccess
  - DefenseEvasion
  - Discovery
  - Execution
  - Exfiltration
  - LateralMovement
  - Persistence
  - PrivilegeEscalation
relevantTechniques:
  - T1548.002
  - T1134
  - T1134.002
  - T1134.005
  - T1087.001
  - T1087.002
  - T1557.001
  - T1071.001
  - T1560
  - T1547.001
  - T1547.005
  - T1547.009
  - T1217
  - T1115
  - T1059
  - T1059.001
  - T1059.003
  - T1136.001
  - T1136.002
  - T1543.003
  - T1555.003
  - T1484.001
  - T1482
  - T1114.001
  - T1573.002
  - T1546.008
  - T1041
  - T1567.001
  - T1567.002
  - T1068
  - T1210
  - T1083
  - T1615
  - T1574.001
  - T1574.004
  - T1574.007
  - T1574.008
  - T1574.009
  - T1070.006
  - T1105
  - T1056.001
  - T1056.004
  - T1106
  - T1046
  - T1135
  - T1040
  - T1027
  - T1003.001
  - T1057
  - T1055
  - T1021.003
  - T1021.004
  - T1053.005
  - T1113
  - T1518.001
  - T1558.002
  - T1558.003
  - T1082
  - T1016
  - T1049
  - T1569.002
  - T1127.001
  - T1552.001
  - T1552.004
  - T1550.002
  - T1125
  - T1102.002
  - T1047
query: |
  let regexEmpire = tostring(toscalar(externaldata(cmdlets:string)[@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/EmpireCommandString.txt"] with (format="txt")));
  (union isfuzzy=true
   (SecurityEvent
  | where EventID == 4688
  //consider filtering on filename if perf issues occur
  //where FileName in~ ("powershell.exe","powershell_ise.exe","pwsh.exe")
  | where not(ParentProcessName has_any ('gc_worker.exe', 'gc_service.exe'))
  | where CommandLine has "-encodedCommand"
  | parse kind=regex flags=i CommandLine with * "-EncodedCommand " encodedCommand
  | extend encodedCommand = iff(encodedCommand has " ", tostring(split(encodedCommand, " ")[0]), encodedCommand)
  // Note: currently the base64_decode_tostring function is limited to supporting UTF8
  | extend decodedCommand = translate('\0','', base64_decode_tostring(substring(encodedCommand, 0, strlen(encodedCommand) -  (strlen(encodedCommand) %8)))), encodedCommand, CommandLine , strlen(encodedCommand)
  | extend EfectiveCommand = iff(isnotempty(encodedCommand), decodedCommand, CommandLine)
  | where EfectiveCommand matches regex regexEmpire
  | project timestamp = TimeGenerated, Computer, SubjectUserName, SubjectDomainName, FileName = Process, EfectiveCommand, decodedCommand, encodedCommand, CommandLine, ParentProcessName
  | extend HostName = split(Computer, '.', 0)[0], DnsDomain = strcat_array(array_slice(split(Computer, '.'), 1, -1), '.')
  ),
  (WindowsEvent
  | where EventID == 4688
  | where EventData has_any ("-encodedCommand", "powershell.exe","powershell_ise.exe","pwsh.exe")
  | where not(EventData has_any ('gc_worker.exe', 'gc_service.exe'))
  //consider filtering on filename if perf issues occur
  //extend NewProcessName = tostring(EventData.NewProcessName)
  //extend Process=tostring(split(NewProcessName, '\\')[-1])
  //FileName = Process
  //where FileName in~ ("powershell.exe","powershell_ise.exe","pwsh.exe")
  | extend ParentProcessName = tostring(EventData.ParentProcessName)
  | where not(ParentProcessName has_any ('gc_worker.exe', 'gc_service.exe'))
  | extend CommandLine = tostring(EventData.CommandLine)
  | where CommandLine has "-encodedCommand"
  | parse kind=regex flags=i CommandLine with * "-EncodedCommand " encodedCommand
  | extend encodedCommand = iff(encodedCommand has " ", tostring(split(encodedCommand, " ")[0]), encodedCommand)
  // Note: currently the base64_decode_tostring function is limited to supporting UTF8
  | extend decodedCommand = translate('\0','', base64_decode_tostring(substring(encodedCommand, 0, strlen(encodedCommand) -  (strlen(encodedCommand) %8)))), encodedCommand, CommandLine , strlen(encodedCommand)
  | extend EfectiveCommand = iff(isnotempty(encodedCommand), decodedCommand, CommandLine)
  | where EfectiveCommand matches regex regexEmpire
  | extend SubjectUserName = tostring(EventData.SubjectUserName)
  | extend SubjectDomainName = tostring(EventData.SubjectDomainName)
  | extend NewProcessName = tostring(EventData.NewProcessName)
  | extend Process=tostring(split(NewProcessName, '\\')[-1])
  | project timestamp = TimeGenerated, Computer, SubjectUserName, SubjectDomainName, FileName = Process, EfectiveCommand, decodedCommand, encodedCommand, CommandLine, ParentProcessName
  | extend HostName = split(Computer, '.', 0)[0], DnsDomain = strcat_array(array_slice(split(Computer, '.'), 1, -1), '.')
  ))
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: SubjectUserName
      - identifier: NTDomain
        columnName: SubjectDomainName
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: HostName
      - identifier: DnsDomain
        columnName: DnsDomain
version: 1.3.1
kind: Scheduled

Stages and Predicates

Let binding: regexEmpire

let regexEmpire = tostring(toscalar(externaldata(cmdlets:string)[@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/EmpireCommandString.txt"] with (format="txt")));

union isfuzzy=true (2 sources)

Each leg below queries one source; the rule matches if any leg does. Sources: SecurityEvent, WindowsEvent

Leg 1: SecurityEvent

SecurityEvent
| where EventID == 4688
| where not(ParentProcessName has_any ('gc_worker.exe', 'gc_service.exe'))
| where CommandLine has "-encodedCommand"
| parse kind=regex flags=i CommandLine with * "-EncodedCommand " encodedCommand
| extend encodedCommand = iff(encodedCommand has " ", tostring(split(encodedCommand, " ")[0]), encodedCommand)
| extend decodedCommand = translate('\0','', base64_decode_tostring(substring(encodedCommand, 0, strlen(encodedCommand) -  (strlen(encodedCommand) %8)))), encodedCommand, CommandLine , strlen(encodedCommand)
| extend EfectiveCommand = iff(isnotempty(encodedCommand), decodedCommand, CommandLine)
| where EfectiveCommand matches regex regexEmpire
| project timestamp = TimeGenerated, Computer, SubjectUserName, SubjectDomainName, FileName = Process, EfectiveCommand, decodedCommand, encodedCommand, CommandLine, ParentProcessName
| extend HostName = split(Computer, '.', 0)[0], DnsDomain = strcat_array(array_slice(split(Computer, '.'), 1, -1), '.')

Leg 2: WindowsEvent

WindowsEvent
| where EventID == 4688
| where EventData has_any ("-encodedCommand", "powershell.exe","powershell_ise.exe","pwsh.exe")
| where not(EventData has_any ('gc_worker.exe', 'gc_service.exe'))
| extend ParentProcessName = tostring(EventData.ParentProcessName)
| where not(ParentProcessName has_any ('gc_worker.exe', 'gc_service.exe'))
| extend CommandLine = tostring(EventData.CommandLine)
| where CommandLine has "-encodedCommand"
| parse kind=regex flags=i CommandLine with * "-EncodedCommand " encodedCommand
| extend encodedCommand = iff(encodedCommand has " ", tostring(split(encodedCommand, " ")[0]), encodedCommand)
| extend decodedCommand = translate('\0','', base64_decode_tostring(substring(encodedCommand, 0, strlen(encodedCommand) -  (strlen(encodedCommand) %8)))), encodedCommand, CommandLine , strlen(encodedCommand)
| extend EfectiveCommand = iff(isnotempty(encodedCommand), decodedCommand, CommandLine)
| where EfectiveCommand matches regex regexEmpire
| extend SubjectUserName = tostring(EventData.SubjectUserName)
| extend SubjectDomainName = tostring(EventData.SubjectDomainName)
| extend NewProcessName = tostring(EventData.NewProcessName)
| extend Process=tostring(split(NewProcessName, '\\')[-1])
| project timestamp = TimeGenerated, Computer, SubjectUserName, SubjectDomainName, FileName = Process, EfectiveCommand, decodedCommand, encodedCommand, CommandLine, ParentProcessName
| extend HostName = split(Computer, '.', 0)[0], DnsDomain = strcat_array(array_slice(split(Computer, '.'), 1, -1), '.')

Exclusions

Top-level NOT(...) conjuncts: predicates this rule actively suppresses.

FieldKindExcluded values
ParentProcessNamematchgc_worker.exe, gc_service.exe
EventDatamatchgc_worker.exe, gc_service.exe
ParentProcessNamematchgc_worker.exe, gc_service.exe

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.

FieldKindValues
CommandLinematch
  • -encodedCommand transforms: term corpus 3 (sigma 1, elastic 1, kusto 1)
EfectiveCommandregex_match
  • regexEmpire
EventDatamatch
  • -encodedCommand
  • powershell.exe
  • powershell_ise.exe
  • pwsh.exe
EventIDeq
  • 4688 transforms: cased corpus 313 (splunk 283, kusto 30)

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.

FieldSource
CommandLineproject
Computerproject
EfectiveCommandproject
FileNameproject
ParentProcessNameproject
SubjectDomainNameproject
SubjectUserNameproject
decodedCommandproject
encodedCommandproject
timestampproject
DnsDomainextend
HostNameextend