@@ -56,8 +56,9 @@ The graph on the **Phish / Malware Efficacy** card visually represents the prote
5656
5757- ** Pre-delivery** : Items detected before they reach the recipient's mailbox.
5858- ** Post-delivery** : Items removed after the item was delivered to the recipient's mailbox via [ zero-hour auto purge (ZAP)] ( zero-hour-auto-purge.md ) .
59- - ** Uncaught** : Delivered items that ZAP identified but didn't remove due to them already being remediated . For example:
59+ - ** Uncaught** : Delivered items that ZAP identified but failed to remove . For example:
6060 - Admin deletions or remediations.
61+ - ZAP being disabled for the specific mailboxes.
6162 - [ Admin submissions] ( submissions-admin.md ) to Microsoft identifying the message as malware or phishing.
6263 - User deletions.
6364 - Non-Microsoft security provider deletions.
@@ -256,87 +257,47 @@ Organizations with Defender for Office 365 Plan 2 can use the following query in
256257> The numbers might differ slightly due to the different refresh rates for advanced hunting vs. reporting data.
257258
258259``` kusto
259- // This query by default will take the last 30 days of data.
260- // The query and calculation can be tweaked to meet individual needs, and will update over time to get incrementally more accurate.
261- // Ben Harris - Microsoft Defender for Office 365 PM.
262260let _startTime = ago(30d);
263261let _endTime = now();
264- // Get all mailflow detected as clean at time of delivery
265- let EmailEventsClean = materialize(
262+ let PreDelivery = toscalar(
266263 EmailEvents
267- | where Timestamp between (_startTime .. _endTime) and EmailDirection == "Inbound"
268- | where ThreatTypes !contains "Phish" and ThreatTypes !contains "Malware"
269- | project NetworkMessageId,ThreatTypes
270- );
271- // Get all mailflow detected as phish or malware at time of delivery
272- let EmailEventsThreats = materialize(
273- EmailEvents
274- | where Timestamp between (_startTime .. _endTime) and EmailDirection == "Inbound"
275- | where ThreatTypes contains "Phish" or ThreatTypes contains "Malware"
264+ | where Timestamp between (_startTime .. _endTime)
265+ and EmailDirection == "Inbound"
266+ and DeliveryLocation in ("Junk folder", "Quarantine")
267+ and (ThreatTypes contains "Phish" or ThreatTypes contains "Malware")
276268 | extend MDO_detection = parse_json(DetectionMethods)
277269 | extend FirstDetection = iif(isempty(MDO_detection), "Clean", tostring(bag_keys(MDO_detection)[0]))
278270 | extend FirstSubcategory = iif(FirstDetection != "Clean" and array_length(MDO_detection[FirstDetection]) > 0, strcat(FirstDetection, ": ", tostring(MDO_detection[FirstDetection][0])), "No Detection (clean)")
279- | project NetworkMessageId,FirstDetection,FirstSubcategory,MDO_detection,ThreatTypes
271+ | summarize PreDelivery = count()
280272);
281- // Get all post delivery ZAP / Redelivery events, and arg_max them to ensure we have the latest verdict to work with for each
282- let EmailPostDeliveryFiltered = materialize(
273+ let PostDelivery = toscalar(
283274 EmailPostDeliveryEvents
284- | where Timestamp between (_startTime .. datetime_add('day', 7, _endTime))
285- | where ActionType in ("Malware ZAP","Phish ZAP","Redelivery")
286- | extend Key = strcat(NetworkMessageId , "-", RecipientEmailAddress)
287- | summarize arg_max(Timestamp, *) by Key
288- | project Action,ActionType,ActionResult,ThreatTypes,NetworkMessageId
289- );
290- // Optional - get all admin submissions for malware or phish, so we can also count these in the miss bucket.
291- let CloudAppEventsFiltered = materialize(
292- CloudAppEvents
293- | where Timestamp between (_startTime .. datetime_add('day', 7, _endTime))
294- | where ActionType == "AdminSubmissionSubmitted"
295- | extend SubmissionType = tostring(parse_json(RawEventData).SubmissionType)
296- | extend NetworkMessageId = tostring(parse_json(RawEventData).ObjectId)
297- | where SubmissionType in ("1", "2")
298- | project SubmissionType,NetworkMessageId
299- );
300- // get the number of threats caught in mailflow
301- let Mal_Phish_Mailflow = toscalar(
302- EmailEventsThreats
303- | summarize count()
275+ | where Timestamp between (_startTime .. _endTime)
276+ and ActionType in ("Malware ZAP","Phish ZAP")
277+ and ActionResult in ("Success","UserTriaged")
278+ | summarize PostDelivery = count()
304279);
305- // get the number of threats caught in mailflow which turned out to be false positives (FPs) so we can correct the calculation
306- let FP_ZAP = toscalar(
307- EmailPostDeliveryFiltered
308- | where ThreatTypes !contains "Phish" and ThreatTypes !contains "Malware" and ActionType == "Redelivery"
309- | join kind=leftsemi (EmailEventsThreats) on NetworkMessageId
310- | summarize count()
311- );
312- // get the number of threats successfully cleaned up post delivery, ignoring where administrative policy stopped action
313- let FN_ZAP_Successful = toscalar(
314- EmailPostDeliveryFiltered
315- | where ActionType in ("Malware ZAP","Phish ZAP") and ActionResult in ("Success","AdminPolicy")
316- | join kind=leftsemi (EmailEventsClean) on NetworkMessageId
317- | summarize count()
318- );
319- // get the number of threats unsuccessfully cleaned up post delivery.
320- let FN_ZAP_Unsuccessful = toscalar(
321- EmailPostDeliveryFiltered
322- | where ActionType in ("Malware ZAP","Phish ZAP") and ActionResult !in ("Success","AdminPolicy")
323- | join kind=leftsemi (EmailEventsClean) on NetworkMessageId
324- | summarize count()
280+ let Uncaught = toscalar(
281+ EmailPostDeliveryEvents
282+ | where Timestamp between (_startTime .. _endTime)
283+ and ActionType in ("Malware ZAP","Phish ZAP")
284+ and ActionResult !in ("Success", "UserTriaged")
285+ | summarize Uncaught = count()
325286);
326- // join the administrative submissions to clean mailflow to find the additional miss
327- let FN_Admin_Submissions = toscalar(
328- CloudAppEventsFiltered
329- | join kind=rightsemi (EmailEventsClean) on NetworkMessageId
330- | summarize count()
331- );
332- // print each result, and run the calculation to work out effectiveness at time of delivery and post delivery.
333- union withsource=Table
334- (print StatisticName="Mal/Phish Mailflow totals - Minus FPs", Value=toreal(Mal_Phish_Mailflow) - toreal(FP_ZAP)),
335- (print StatisticName="Admin Mal/Phish FNs Submitted", Value=toreal(FN_Admin_Submissions)),
336- (print StatisticName="Mal/Phish FPs Reverse Zapped", Value=toreal(FP_ZAP)),
337- (print StatisticName="Mal / Phish Successfully Zapped ", Value=toreal(FN_ZAP_Successful)),
338- (print StatisticName="Mal / Phish UN-Successfully Zapped ", Value=toreal(FN_ZAP_Unsuccessful)),
339- (print StatisticName="Effectiveness Post Delivery ", Value=abs(round(((toreal(FN_Admin_Submissions)+toreal(FN_ZAP_Unsuccessful))/(toreal(Mal_Phish_Mailflow)+toreal(FN_ZAP_Successful)+toreal(FN_ZAP_Unsuccessful)+toreal(FN_Admin_Submissions)-toreal(FP_ZAP))*100-100),2))),
340- (print StatisticName="Effectiveness Pre-Delivery ", Value=abs(round(((toreal(FN_Admin_Submissions)+toreal(FN_ZAP_Unsuccessful)+toreal(FN_ZAP_Successful))/(toreal(Mal_Phish_Mailflow)+toreal(FN_ZAP_Successful)+toreal(FN_ZAP_Unsuccessful)+toreal(FN_Admin_Submissions)-toreal(FP_ZAP))*100-100),2)))
287+ let PreDeliveryReal = toreal(PreDelivery);
288+ let PostDeliveryReal = toreal(PostDelivery);
289+ let UncaughtReal = toreal(Uncaught);
290+ let Effectiveness = round(
291+ iif(
292+ (PreDeliveryReal + PostDeliveryReal + UncaughtReal) == 0,
293+ 0.0,
294+ ((PreDeliveryReal + PostDeliveryReal) / (PreDeliveryReal + PostDeliveryReal + UncaughtReal)) * 100.0
295+ ), 2
296+ );
297+ union
298+ (print StatisticName = "Pre-Delivery Catch ", Value = PreDeliveryReal),
299+ (print StatisticName = "Post-Delivery Catch ", Value = PostDeliveryReal),
300+ (print StatisticName = "Failed ZAP / Miss or Uncaught ", Value = UncaughtReal),
301+ (print StatisticName = "Phish / Malware Efficacy ", Value = Effectiveness)
341302| project StatisticName, Value
342303```
0 commit comments