Malicious web application requests linked with Microsoft Defender for Endpoint formerly Microsoft Defender ATP alerts
| Id | fbfbf530-506b-49a4-81ad-4030885a195c |
| Rulename | Malicious web application requests linked with Microsoft Defender for Endpoint (formerly Microsoft Defender ATP) alerts |
| Description | Takes Microsoft Defender for Endpoint (formerly Microsoft Defender ATP) alerts where web scripts are present in the evidence and correlates with requests made to those scripts in the WCSIISLog to surface new alerts for potentially malicious web request activity. The lookback for alerts is set to 1h and the lookback for W3CIISLogs is set to 7d. A sample set of popular web script extensions has been provided in scriptExtensions that should be tailored to your environment. |
| Severity | Medium |
| Tactics | Persistence |
| Techniques | T1505 |
| Required data connectors | AzureMonitor(IIS) MicrosoftDefenderAdvancedThreatProtection |
| Kind | Scheduled |
| Query frequency | 1h |
| Query period | 7d |
| Trigger threshold | 0 |
| Trigger operator | gt |
| Source Uri | https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Web Shells Threat Protection/Analytic Rules/MaliciousAlertLinkedWebRequests.yaml |
| Version | 1.0.4 |
| Arm template | fbfbf530-506b-49a4-81ad-4030885a195c.json |
let alertTimeWindow = 1h;
let logTimeWindow = 7d;
// Define script extensions that suit your web application environment - a sample are provided below
let scriptExtensions = dynamic([".php", ".jsp", ".js", ".aspx", ".asmx", ".asax", ".cfm", ".shtml"]);
let alertData = materialize(SecurityAlert
| where TimeGenerated > ago(alertTimeWindow)
| where ProviderName == "MDATP"
// Parse and expand the alert JSON
| extend alertData = parse_json(Entities)
| mvexpand alertData);
let fileData = alertData
// Extract web script files from MDATP alerts - our malicious web scripts - candidate webshells
| where alertData.Type =~ "file"
| where alertData.Name has_any(scriptExtensions)
| extend FileName = tostring(alertData.Name), Directory = tostring(alertData.Directory);
let hostData = alertData
// Extract server details from alerts and map to alert id
| where alertData.Type =~ "host"
| project HostName = tostring(alertData.HostName), DnsDomain = tostring(alertData.DnsDomain), SystemAlertId
| distinct HostName, DnsDomain, SystemAlertId;
// Join the files on their impacted servers
let webshellData = fileData
| join kind=inner (hostData) on SystemAlertId
| project TimeGenerated, FileName, Directory, HostName, DnsDomain;
webshellData
| join (
// Find requests that were made to this file on the impacted server in the W3CIISLog table
W3CIISLog
| where TimeGenerated > ago(logTimeWindow)
// Restrict to accesses to script extensions
| where csUriStem has_any(scriptExtensions)
| extend splitUriStem = split(csUriStem, "/")
| extend FileName = splitUriStem[-1], HostName = sComputerName
// Summarize potential attacker activity
| summarize count(), StartTime=min(TimeGenerated), EndTime=max(TimeGenerated), RequestUserAgents=make_set(csUserAgent), ReqestMethods=make_set(csMethod), RequestStatusCodes=make_set(scStatus), RequestCookies=make_set(csCookie), RequestReferers=make_set(csReferer), RequestQueryStrings=make_set(csUriQuery) by AttackerIP=cIP, SiteName=sSiteName, ShellLocation=csUriStem, tostring(FileName), HostName
) on FileName, HostName
| project StartTime, EndTime, AttackerIP, RequestUserAgents, Computer = HostName, SiteName, ShellLocation, ReqestMethods, RequestStatusCodes, RequestCookies, RequestReferers, RequestQueryStrings, RequestCount = count_
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
description: |
'Takes Microsoft Defender for Endpoint (formerly Microsoft Defender ATP) alerts where web scripts are present in the evidence and correlates with requests made to those scripts in the WCSIISLog to surface new alerts for potentially malicious web request activity.
The lookback for alerts is set to 1h and the lookback for W3CIISLogs is set to 7d. A sample set of popular web script extensions has been provided in scriptExtensions that should be tailored to your environment.'
kind: Scheduled
tactics:
- Persistence
requiredDataConnectors:
- connectorId: MicrosoftDefenderAdvancedThreatProtection
dataTypes:
- SecurityAlert
- connectorId: AzureMonitor(IIS)
dataTypes:
- W3CIISLog
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Web Shells Threat Protection/Analytic Rules/MaliciousAlertLinkedWebRequests.yaml
severity: Medium
name: Malicious web application requests linked with Microsoft Defender for Endpoint (formerly Microsoft Defender ATP) alerts
metadata:
support:
tier: Community
author:
name: Microsoft Security Research
categories:
domains:
- Security - Others
source:
kind: Scheduled
triggerThreshold: 0
queryPeriod: 7d
query: |
let alertTimeWindow = 1h;
let logTimeWindow = 7d;
// Define script extensions that suit your web application environment - a sample are provided below
let scriptExtensions = dynamic([".php", ".jsp", ".js", ".aspx", ".asmx", ".asax", ".cfm", ".shtml"]);
let alertData = materialize(SecurityAlert
| where TimeGenerated > ago(alertTimeWindow)
| where ProviderName == "MDATP"
// Parse and expand the alert JSON
| extend alertData = parse_json(Entities)
| mvexpand alertData);
let fileData = alertData
// Extract web script files from MDATP alerts - our malicious web scripts - candidate webshells
| where alertData.Type =~ "file"
| where alertData.Name has_any(scriptExtensions)
| extend FileName = tostring(alertData.Name), Directory = tostring(alertData.Directory);
let hostData = alertData
// Extract server details from alerts and map to alert id
| where alertData.Type =~ "host"
| project HostName = tostring(alertData.HostName), DnsDomain = tostring(alertData.DnsDomain), SystemAlertId
| distinct HostName, DnsDomain, SystemAlertId;
// Join the files on their impacted servers
let webshellData = fileData
| join kind=inner (hostData) on SystemAlertId
| project TimeGenerated, FileName, Directory, HostName, DnsDomain;
webshellData
| join (
// Find requests that were made to this file on the impacted server in the W3CIISLog table
W3CIISLog
| where TimeGenerated > ago(logTimeWindow)
// Restrict to accesses to script extensions
| where csUriStem has_any(scriptExtensions)
| extend splitUriStem = split(csUriStem, "/")
| extend FileName = splitUriStem[-1], HostName = sComputerName
// Summarize potential attacker activity
| summarize count(), StartTime=min(TimeGenerated), EndTime=max(TimeGenerated), RequestUserAgents=make_set(csUserAgent), ReqestMethods=make_set(csMethod), RequestStatusCodes=make_set(scStatus), RequestCookies=make_set(csCookie), RequestReferers=make_set(csReferer), RequestQueryStrings=make_set(csUriQuery) by AttackerIP=cIP, SiteName=sSiteName, ShellLocation=csUriStem, tostring(FileName), HostName
) on FileName, HostName
| project StartTime, EndTime, AttackerIP, RequestUserAgents, Computer = HostName, SiteName, ShellLocation, ReqestMethods, RequestStatusCodes, RequestCookies, RequestReferers, RequestQueryStrings, RequestCount = count_
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
relevantTechniques:
- T1505
id: fbfbf530-506b-49a4-81ad-4030885a195c
queryFrequency: 1h
entityMappings:
- entityType: Host
fieldMappings:
- columnName: Computer
identifier: FullName
- columnName: HostName
identifier: HostName
- columnName: HostNameDomain
identifier: DnsDomain
- entityType: IP
fieldMappings:
- columnName: AttackerIP
identifier: Address
triggerOperator: gt
version: 1.0.4