Hello everyone,
I'm currently working on an Alert/workflow that aims to proactively trigger when a ransomware pattern is detected. Our SOC uses Elastic Security as both the SIEM and EDR.
To build it, I started from real ransomware incidents we've handled in our SOC, along with the MITRE ATT&CK Top 10 ransomware techniques:
Rather than manually reviewing and correlating multiple alerts to determine whether a ransomware attack is actually in progress, I wanted to estimate a confidence score based on the observed MITRE ATT&CK techniques.
So far, this is the best approach I've come up with, but I'm not sure it's the right one. One concern is that some ransomware attacks can unfold over several days or even weeks, making it difficult to determine the most appropriate correlation window and query strategy.
I'd really appreciate your feedback. Has anyone implemented something similar ? How do you approach ransomware detection in your environment ? If you see any weaknesses or blind spots in this correlation approach, I'd really appreciate your feedback.
Here is the ES|QL query I'm currently using:
FROM
.alerts-security.alerts-*
METADATA
_id
|
WHERE
`@timestamp` > NOW() - 1 HOURS
|
WHERE
`kibana.alert.workflow_status` != "closed"
AND `host.id` IS NOT NULL
|
EVAL
technique_str = CONCAT(
COALESCE(MV_CONCAT(`kibana.alert.rule.threat.technique.id`, ","), ""),
",",
COALESCE(MV_CONCAT(`kibana.alert.rule.threat.technique.subtechnique.id`, ","), "")
)
|
EVAL
score_T1059 = CASE(technique_str LIKE "*T1059*", 5, 0)
|
EVAL
score_T1078 = CASE(technique_str LIKE "*T1078*", 25, 0)
|
EVAL
score_T1021_001 = CASE(technique_str LIKE "*T1021.001*", 40, 0)
|
EVAL
score_T1047 = CASE(technique_str LIKE "*T1047*", 15, 0)
|
EVAL
score_T1490 = CASE(technique_str LIKE "*T1490*", 50, 0)
|
EVAL
score_T1105 = CASE(technique_str LIKE "*T1105*", 30, 0)
|
EVAL
score_T1083 = CASE(technique_str LIKE "*T1083*", 5, 0)
|
EVAL
score_T1486 = CASE(technique_str LIKE "*T1486*", 100, 0)
|
EVAL
score_T1190 = CASE(technique_str LIKE "*T1190*", 50, 0)
|
EVAL
score_T1489 = CASE(technique_str LIKE "*T1489*", 15, 0)
|
STATS
score_T1059 = MAX(score_T1059),
score_T1078 = MAX(score_T1078),
score_T1021_001 = MAX(score_T1021_001),
score_T1047 = MAX(score_T1047),
score_T1490 = MAX(score_T1490),
score_T1105 = MAX(score_T1105),
score_T1083 = MAX(score_T1083),
score_T1486 = MAX(score_T1486),
score_T1190 = MAX(score_T1190),
score_T1489 = MAX(score_T1489),
techniques = VALUES(technique_str),
rules = VALUES(`kibana.alert.rule.name`),
source_alert_ids = VALUES(_id),
users = VALUES(`user.name`),
alert_count = COUNT()
BY
`host.id`, `host.name`
|
EVAL
ransomware_score =
score_T1059 +
score_T1078 +
score_T1021_001 +
score_T1047 +
score_T1490 +
score_T1105 +
score_T1083 +
score_T1486 +
score_T1190 +
score_T1489
|
WHERE
ransomware_score >= 60
|
SORT
ransomware_score DESC
And here is an example of the output produced for a ransomware test:
{
"score_T1059": 5,
"score_T1078": 0,
"score_T1021_001": 0,
"score_T1047": 0,
"score_T1490": 50,
"score_T1105": 30,
"score_T1083": 0,
"score_T1486": 0,
"score_T1190": 0,
"score_T1489": 0,
"techniques": [
"T1112,T1562,T1562.001",
"T1112,T1562,T1562.001,T1562.006",
"T1204,T1204.002",
"T1490",
"T1070,T1070.001",
"T1027,T1059,T1105,T1140,T1027.010,T1059.001"
],
"rules": [
"Malicious Behavior Detection Alert: Suspicious PowerShell Base64 Decoding",
"Malicious Behavior Detection Alert: Potential Privilege Escalation via Token Impersonation",
"Malicious Behavior Detection Alert: Privilege Escalation via EXTENDED STARTUPINFO",
"Malware Detection Alert",
"Microsoft Windows Defender Tampering",
"Windows Defender Disabled via Registry Modification",
"Volume Shadow Copy Deleted or Resized via VssAdmin",
"Windows Event Logs Cleared",
"Suspicious Windows Powershell Arguments"
],
"source_alert_ids": [
"alert-id-redacted-001",
"alert-id-redacted-002",
"alert-id-redacted-003",
"..."
],
"users": [
"Administrator",
"SYSTEM"
],
"alert_count": 90,
"host.id": "endpoint-id-redacted",
"host.name": "example-server-01",
"ransomware_score": 85
}