Detection rules › Kusto
Identify SysAid Server web shell creation
This query looks for potential webshell creation by the threat actor Mercury after the sucessful exploitation of SysAid server. Reference: https://www.microsoft.com/security/blog/2022/08/25/mercury-leveraging-log4j-2-vulnerabilities-in-unpatched-systems-to-target-israeli-organizations/
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Telemetry coverage
Rule body
id: 50eb4cbd-188f-44f4-b964-bab84dcdec10
name: Identify SysAid Server web shell creation
description: |
'This query looks for potential webshell creation by the threat actor Mercury after the sucessful exploitation of SysAid server.
Reference: https://www.microsoft.com/security/blog/2022/08/25/mercury-leveraging-log4j-2-vulnerabilities-in-unpatched-systems-to-target-israeli-organizations/'
severity: High
requiredDataConnectors:
- connectorId: SecurityEvents
dataTypes:
- SecurityEvent
- connectorId: WindowsSecurityEvents
dataTypes:
- SecurityEvent
- connectorId: MicrosoftThreatProtection
dataTypes:
- DeviceFileEvents
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1190
tags:
- Mercury
- Schema: ASIMFileEvent
SchemaVersion: 0.1.0
query: |
let timeframe = 1d;
let time_window = 5m;
(union isfuzzy=true
(SecurityEvent
| where TimeGenerated > ago(timeframe)
| where EventID == 4688
| where Process has_any ("java.exe", "javaw.exe") and CommandLine has "SysAidServer"
| summarize by ParentProcessName,Process, Account, Computer, CommandLine, timekey= bin(TimeGenerated, time_window), TimeGenerated, SubjectLogonId
| join kind=inner(
SecurityEvent
| where TimeGenerated > ago(timeframe)
| where EventID == 4663
| where Process has_any ("java.exe", "javaw.exe")
| where AccessMask in ('0x2','0x100', '0x10', '0x4')
| where ObjectName endswith ".jsp"
| summarize by ParentProcessName, Account, Computer, ObjectName, ProcessName, timekey= bin(TimeGenerated, time_window), TimeGenerated, SubjectLogonId)
on timekey, Computer, SubjectLogonId
),
(DeviceFileEvents
| where InitiatingProcessFileName has_any ("java.exe", "javaw.exe")
| where InitiatingProcessCommandLine has "SysAidServer"
| where FileName endswith ".jsp"
| extend Account = strcat(InitiatingProcessAccountDomain, @'\', InitiatingProcessAccountName), Computer = DeviceName
),
(imFileEvent
| where TimeGenerated > ago(timeframe)
| where EventType == "FileCreated"
| where ActingProcessName has_any ("java.exe", "javaw.exe")
| where ActingProcessCommandLine has "SysAidServer"
| where FilePath endswith ".jsp"
| extend Account = ActorUsername, Computer = DvcHostname
)
)
| extend AccountName = tostring(split(Account, @'\')[1]), AccountNTDomain = tostring(split(Account, @'\')[0])
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: Account
- identifier: Name
columnName: AccountName
- identifier: NTDomain
columnName: AccountNTDomain
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: Computer
- identifier: HostName
columnName: HostName
- identifier: DnsDomain
columnName: HostNameDomain
version: 1.0.3
kind: Scheduled
metadata:
source:
kind: Scheduled
author:
name: Microsoft Security Research
support:
tier: Community
categories:
domains: [ "Security - Others" ]
Stages and Predicates
Parameters
let timeframe = 1d;
let time_window = 5m;
union isfuzzy=true (3 sources)
Each leg below queries one source; the rule matches if any leg does. Sources: SecurityEvent, DeviceFileEvents, imFileEvent
Leg 1: SecurityEvent
SecurityEvent
| where TimeGenerated > ago(timeframe)
| where EventID == 4688
| where Process has_any ("java.exe", "javaw.exe") and CommandLine has "SysAidServer"
| summarize by ParentProcessName,Process, Account, Computer, CommandLine, timekey= bin(TimeGenerated, time_window), TimeGenerated, SubjectLogonId
| join kind=inner(
SecurityEvent
| where TimeGenerated > ago(timeframe)
| where EventID == 4663
| where Process has_any ("java.exe", "javaw.exe")
| where AccessMask in ('0x2','0x100', '0x10', '0x4')
| where ObjectName endswith ".jsp"
| summarize by ParentProcessName, Account, Computer, ObjectName, ProcessName, timekey= bin(TimeGenerated, time_window), TimeGenerated, SubjectLogonId)
on timekey, Computer, SubjectLogonId
Leg 2: DeviceFileEvents
DeviceFileEvents
| where InitiatingProcessFileName has_any ("java.exe", "javaw.exe")
| where InitiatingProcessCommandLine has "SysAidServer"
| where FileName endswith ".jsp"
| extend Account = strcat(InitiatingProcessAccountDomain, @'\', InitiatingProcessAccountName), Computer = DeviceName
Leg 3: imFileEvent
imFileEvent
| where TimeGenerated > ago(timeframe)
| where EventType == "FileCreated"
| where ActingProcessName has_any ("java.exe", "javaw.exe")
| where ActingProcessCommandLine has "SysAidServer"
| where FilePath endswith ".jsp"
| extend Account = ActorUsername, Computer = DvcHostname
Applied to the combined result
| extend AccountName = tostring(split(Account, @'\')[1]), AccountNTDomain = tostring(split(Account, @'\')[0])
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
AccessMask | in |
| field:"AccessMask" kind:in |
ActingProcessCommandLine | match |
| field:"ParentCommandLine" kind:match value:"SysAidServer" |
ActingProcessName | match |
| field:"ParentImage" kind:match |
CommandLine | match |
| field:"CommandLine" kind:match value:"SysAidServer" |
EventID | eq |
| field:"EventID" kind:eq |
EventType | eq |
| field:"EventType" kind:eq value:"FileCreated" |
FileName | ends_with |
| field:"file_name" kind:ends_with value:".jsp" |
FilePath | ends_with |
| field:"FilePath" kind:ends_with value:".jsp" |
InitiatingProcessCommandLine | match |
| field:"CommandLine" kind:match value:"SysAidServer" |
InitiatingProcessFileName | match |
| field:"parent_process_name" kind:match |
ObjectName | ends_with |
| field:"ObjectName" kind:ends_with value:".jsp" |
Process | match |
| field:"Process" kind:match |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Account | summarize |
Computer | summarize |
ObjectName | summarize |
ParentProcessName | summarize |
ProcessName | summarize |
SubjectLogonId | summarize |
TimeGenerated | summarize |
timekey | summarize |