← Back to Explore
kqlHunting
Incidents to Mitre ATTACK navigator
This query takes incidents from Defender, checks MITRE technique and then creates attack navigator format for upload to https://mitre-attack.github.io/attack-navigator/
Detection Query
//This query takes incidents from Defender, checks MITRE technique and then creates attack navigator format for upload to https://mitre-attack.github.io/attack-navigator/
//Query Based on work from https://gokhansobay.medium.com/how-can-you-quickly-review-your-defender-rules-mitre-coverage-with-the-att-ck-navigator-map-6dbc84e73b63
let dynamicAttributes_first = dynamic({
"name": "layer",
"versions": {
"attack": "17",
"navigator": "5.0.1",
"layer": "4.5"
},
"domain": "enterprise-attack",
"description": "",
"filters": {
"platforms": [
"Windows",
"Linux",
"macOS",
"Network",
"PRE",
"Containers",
"Office 365",
"SaaS",
"Google Workspace",
"IaaS",
"Azure AD"
]
}
});
let dynamicAttributes_last = dynamic({
"gradient": {
"colors": [
"#ff6666ff",
"#ffe766ff",
"#8ec843ff"
],
"minValue": 0,
"maxValue": 100
},
"legendItems": [],
"metadata": [],
"links": [],
"showTacticRowBackground": false,
"tacticRowBackground": "#dddddd",
"selectTechniquesAcrossTactics": true,
"selectSubtechniquesWithParent": false,
"selectVisibleTechniques": false
});
let TechniqueID =SecurityIncident
| where TimeGenerated > ago(90d)
| summarize arg_max(TimeGenerated,AdditionalData) by IncidentNumber
| mv-expand AdditionalData
| where tostring(AdditionalData) contains "techniques"
| where parse_json(tostring(AdditionalData.techniques)) <> "[]" //Remove Empty
| distinct tostring(AdditionalData.techniques);
AlertInfo
| where TimeGenerated > ago(90d)
//| where DetectionSource == "Custom detection" //you can filter your source detection method
| extend ParsedAttack = parse_json(AttackTechniques)
| mv-expand ParsedAttack
| extend techniqueID = extract("T[0-9]+(?:\\.[0-9]+)?", 0, tostring(ParsedAttack))
| extend tactic = Category
| extend color = "#e60d0d" //red background
| extend comment = ""
| extend enabled = true
//| extend metadata = dynamic([])
//| extend links = dynamic([])
| extend showSubtechniques = true
| project-away ParsedAttack
| distinct techniqueID, tactic, color, comment, enabled, showSubtechniques //tostring(metadata), tostring(links)
| summarize techniques = make_list(pack(
'techniqueID', techniqueID, //the important point here is that this ID value highlights what we have as coverage in our custom map.
// 'tactic', tactic,
'color', color,
'comment', comment,
'enabled', enabled,
// 'metadata', metadata,
// 'links', links,
'showSubtechniques', showSubtechniques
))
| extend jsonOutput = bag_merge(dynamicAttributes_first, pack('techniques', techniques))
| extend finalOutput = bag_merge(jsonOutput, dynamicAttributes_last)
| project ourjsonOutput = tostring(finalOutput)Data Sources
AlertInfo
Platforms
microsoft-defender
Tags
defenderdetection
Raw Content
//This query takes incidents from Defender, checks MITRE technique and then creates attack navigator format for upload to https://mitre-attack.github.io/attack-navigator/
//Query Based on work from https://gokhansobay.medium.com/how-can-you-quickly-review-your-defender-rules-mitre-coverage-with-the-att-ck-navigator-map-6dbc84e73b63
let dynamicAttributes_first = dynamic({
"name": "layer",
"versions": {
"attack": "17",
"navigator": "5.0.1",
"layer": "4.5"
},
"domain": "enterprise-attack",
"description": "",
"filters": {
"platforms": [
"Windows",
"Linux",
"macOS",
"Network",
"PRE",
"Containers",
"Office 365",
"SaaS",
"Google Workspace",
"IaaS",
"Azure AD"
]
}
});
let dynamicAttributes_last = dynamic({
"gradient": {
"colors": [
"#ff6666ff",
"#ffe766ff",
"#8ec843ff"
],
"minValue": 0,
"maxValue": 100
},
"legendItems": [],
"metadata": [],
"links": [],
"showTacticRowBackground": false,
"tacticRowBackground": "#dddddd",
"selectTechniquesAcrossTactics": true,
"selectSubtechniquesWithParent": false,
"selectVisibleTechniques": false
});
let TechniqueID =SecurityIncident
| where TimeGenerated > ago(90d)
| summarize arg_max(TimeGenerated,AdditionalData) by IncidentNumber
| mv-expand AdditionalData
| where tostring(AdditionalData) contains "techniques"
| where parse_json(tostring(AdditionalData.techniques)) <> "[]" //Remove Empty
| distinct tostring(AdditionalData.techniques);
AlertInfo
| where TimeGenerated > ago(90d)
//| where DetectionSource == "Custom detection" //you can filter your source detection method
| extend ParsedAttack = parse_json(AttackTechniques)
| mv-expand ParsedAttack
| extend techniqueID = extract("T[0-9]+(?:\\.[0-9]+)?", 0, tostring(ParsedAttack))
| extend tactic = Category
| extend color = "#e60d0d" //red background
| extend comment = ""
| extend enabled = true
//| extend metadata = dynamic([])
//| extend links = dynamic([])
| extend showSubtechniques = true
| project-away ParsedAttack
| distinct techniqueID, tactic, color, comment, enabled, showSubtechniques //tostring(metadata), tostring(links)
| summarize techniques = make_list(pack(
'techniqueID', techniqueID, //the important point here is that this ID value highlights what we have as coverage in our custom map.
// 'tactic', tactic,
'color', color,
'comment', comment,
'enabled', enabled,
// 'metadata', metadata,
// 'links', links,
'showSubtechniques', showSubtechniques
))
| extend jsonOutput = bag_merge(dynamicAttributes_first, pack('techniques', techniques))
| extend finalOutput = bag_merge(jsonOutput, dynamicAttributes_last)
| project ourjsonOutput = tostring(finalOutput)