Detection rules › Kusto

A client made a web request to a potentially harmful file (ASIM Web Session schema)

Severity
medium
Time window
10m
Group by
SrcHostname, SrcIpAddr, SrcUsername, Url, requestedFileName
Author
Yaron
Source
github.com/Azure/Azure-Sentinel

'This rule identifies a web request to a URL that holds a file type, including .ps1, .bat, .vbs, and .scr that can be harmful if downloaded. This analytic rule uses ASIM and supports any built-in or custom source that supports the ASIM WebSession schema (ASIM WebSession Schema)'

MITRE ATT&CK coverage

TacticTechniques
Initial AccessT1189 Drive-by Compromise

Rule body kusto

id: 09c49590-4e9d-4da9-a34d-17222d0c9e7e
name: A client made a web request to a potentially harmful file (ASIM Web Session schema)
description: |
  'This rule identifies a web request to a URL that holds a file type, including .ps1, .bat, .vbs, and .scr that can be harmful if downloaded. This analytic rule uses [ASIM](https://aka.ms/AboutASIM) and supports any built-in or custom source that supports the ASIM WebSession schema (ASIM WebSession Schema)'
severity: Medium
tags:
  - ParentAlert: https://github.com/Azure/Azure-Sentinel/blob/master/Detections/CiscoUmbrella/CiscoUmbrellaRequestBlocklistedFileType.yaml
    version: 1.0.0
  - Schema: ASimWebSession
    SchemaVersion: 0.2.1
requiredDataConnectors:
  - connectorId: SquidProxy
    dataTypes:
      - SquidProxy_CL
  - connectorId: Zscaler
    dataTypes:
      - CommonSecurityLog
queryFrequency: 10m
queryPeriod: 10m
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InitialAccess
relevantTechniques:
  - T1189
query: |
  let default_file_ext_blocklist = dynamic(['.ps1', '.vbs', '.bat', '.scr']); // Update this list as per your requirement
  let custom_file_ext_blocklist=toscalar(_GetWatchlist('RiskyFileTypes')
    | extend Extension=column_ifexists("Extension", "")
    | where isnotempty(Extension)
    | summarize make_set(Extension)); // If you have an extensive list, you can also create a Watchlist that includes the file extensions you want to detect
  let file_ext_blocklist = array_concat(default_file_ext_blocklist, custom_file_ext_blocklist);
  _Im_WebSession(starttime=ago(10min), url_has_any=file_ext_blocklist, eventresult='Success')
  | extend requestedFileName=tostring(split(tostring(parse_url(Url)["Path"]), '/')[-1])
  | extend requestedFileExtension=extract(@'(\.\w+)$', 1, requestedFileName, typeof(string))
  | where requestedFileExtension in (file_ext_blocklist)
  | summarize
    EventStartTime=min(TimeGenerated),
    EventEndTime=max(TimeGenerated),
    EventCount=count()
    by SrcIpAddr, SrcUsername, SrcHostname, requestedFileName, Url
  | extend
    Name = iif(SrcUsername contains "@", tostring(split(SrcUsername, '@', 0)[0]), SrcUsername),
    UPNSuffix = iif(SrcUsername contains "@", tostring(split(SrcUsername, '@', 1)[0]), "")
alertDetailsOverride:
  alertDisplayNameFormat: Client {{SrcIpAddr}} accessed a URL with potentially harmful extension {{requestedFileExtension}}
  alertDescriptionFormat: The client at address {{SrcIpAddr}} accessed the URL {{Url}} that has the extension {{requestedFileExtension}}. Downloading a file with this extension may be harmful and may indicate malicious activity.
customDetails:
  requestedFileExt: requestedFileExtension
  Username: SrcUsername
  SrcHostname: SrcHostname
eventGroupingSettings:
  aggregationKind: AlertPerResult
entityMappings:
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SrcIpAddr
  - entityType: URL
    fieldMappings:
      - identifier: Url
        columnName: Url
  - entityType: File
    fieldMappings:
      - identifier: Name
        columnName: requestedFileName
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: SrcUsername
      - identifier: Name
        columnName: Name
      - identifier: UPNSuffix
        columnName: UPNSuffix
version: 1.1.3
kind: Scheduled
metadata:
    source:
        kind: Community
    author:
        name: Yaron
    support:
        tier: Community
    categories:
        domains: [ "Security - Others" ]

Stages and Predicates

Parameters

let default_file_ext_blocklist = dynamic(['.ps1', '.vbs', '.bat', '.scr']);
let file_ext_blocklist = array_concat(default_file_ext_blocklist, custom_file_ext_blocklist);

Let binding: custom_file_ext_blocklist

let custom_file_ext_blocklist = toscalar(_GetWatchlist('RiskyFileTypes')
  | extend Extension=column_ifexists("Extension", "")
  | where isnotempty(Extension)
  | summarize make_set(Extension));

Stage 1: source

_Im_WebSession(starttime=ago(10min), url_has_any=file_ext_blocklist, eventresult='Success')

Stage 2: extend

| extend requestedFileName=tostring(split(tostring(parse_url(Url)["Path"]), '/')[-1])

Stage 3: extend

| extend requestedFileExtension=extract(@'(\.\w+)$', 1, requestedFileName, typeof(string))

Stage 4: where

| where requestedFileExtension in (file_ext_blocklist)

Stage 5: summarize

| summarize
  EventStartTime=min(TimeGenerated),
  EventEndTime=max(TimeGenerated),
  EventCount=count()
  by SrcIpAddr, SrcUsername, SrcHostname, requestedFileName, Url

Stage 6: extend

| extend
  Name = iif(SrcUsername contains "@", tostring(split(SrcUsername, '@', 0)[0]), SrcUsername),
  UPNSuffix = iif(SrcUsername contains "@", tostring(split(SrcUsername, '@', 1)[0]), "")

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
requestedFileExtensionin
  • file_ext_blocklist transforms: cased

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
EventCountsummarize
EventEndTimesummarize
EventStartTimesummarize
SrcHostnamesummarize
SrcIpAddrsummarize
SrcUsernamesummarize
Urlsummarize
requestedFileNamesummarize
Nameextend
UPNSuffixextend