Vulnerability Scanning
Adversaries may scan victims for vulnerabilities that can be used during targeting. Vulnerability scans check if target host and application configurations align with specific exploits the adversary seeks to use. These scans harvest running software and version numbers via server banners, listening ports, or other network artifacts. Threat groups including Sandworm Team, APT28, APT29, Magic Hound, Ember Bear, and APT41 have conducted large-scale vulnerability scanning operations against public-facing infrastructure, targeting specific CVEs such as Log4Shell, ProxyShell, and Citrix vulnerabilities. Information from these scans informs follow-on exploitation (T1190), capability development (T1587, T1588), and further reconnaissance operations.
// T1595.002 — Vulnerability Scanning
// Branch 1: IDS/IPS/WAF/Firewall detection of inbound vulnerability scanning
let ScanToolSignatures = dynamic([
"Nessus", "Qualys", "OpenVAS", "Acunetix", "Nikto", "Masscan", "Nuclei",
"sqlmap", "dirb", "gobuster", "WPScan", "w3af", "skipfish", "wfuzz",
"Burp", "OWASP ZAP", "Metasploit", "Shodan", "Censys", "zgrab",
"nmap", "rustscan", "feroxbuster", "dirbuster"
]);
let ScanEventCategories = dynamic([
"scan", "probe", "reconnaissance", "vuln-scan", "port-scan",
"web-scan", "vulnerability", "exploit-attempt", "policy-violation"
]);
let IDSScanAlerts =
CommonSecurityLog
| where TimeGenerated > ago(24h)
| where Message has_any (ScanToolSignatures)
or Activity has_any (ScanEventCategories)
or DeviceEventCategory has_any (ScanEventCategories)
or AdditionalExtensions has_any (ScanToolSignatures)
or RequestURL has_any ([
"/.env", "/.git/HEAD", "/wp-login.php", "/phpmyadmin",
"/manager/html", "/actuator/env", "/actuator/health",
"/cgi-bin/test-cgi", "/xmlrpc.php", "/server-status",
"/../../../etc/passwd", "/api/swagger-ui.html"
])
| summarize
AlertCount = count(),
UniqueTargets = dcount(DestinationIP),
UniqueSignatures = dcount(Activity),
Signatures = make_set(Activity, 15),
TargetPorts = make_set(DestinationPort, 25),
ProbeURLs = make_set(RequestURL, 10),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated)
by SourceIP, DeviceVendor, DeviceProduct
| where AlertCount >= 3
| extend
DetectionBranch = "IDS-WAF-Firewall",
ScanIntensity = case(
AlertCount >= 200, "Critical",
AlertCount >= 50, "High",
AlertCount >= 10, "Medium",
"Low"),
DurationMinutes = datetime_diff('minute', LastSeen, FirstSeen)
| project
FirstSeen, LastSeen, DurationMinutes, SourceIP, ScanIntensity,
AlertCount, UniqueTargets, UniqueSignatures, Signatures,
TargetPorts, ProbeURLs, DeviceVendor, DeviceProduct, DetectionBranch;
// Branch 2: Internal endpoint executing known vulnerability scanning tools
// Detects pivot scanning, authorized scanner misuse, or compromised host scanning
let InternalScanExecution =
DeviceProcessEvents
| where Timestamp > ago(24h)
| where FileName has_any (
"nmap", "masscan", "nikto", "nuclei", "openvas", "nessus",
"acunetix", "sqlmap", "gobuster", "dirb", "wpscan", "wfuzz",
"ffuf", "feroxbuster", "skipfish", "rustscan", "zgrab")
or ProcessCommandLine has_any (
"--script vuln", "-sV --script", "--top-ports",
"-p 1-65535", "masscan --rate", "nuclei -t cves",
"nikto -h", "sqlmap -u", "gobuster dir -u",
"ffuf -w", "wfuzz -c", "-A --open")
| summarize
AlertCount = count(),
Commands = make_set(ProcessCommandLine, 5),
Signatures = make_set(FileName, 10),
FirstSeen = min(Timestamp),
LastSeen = max(Timestamp),
UniqueTargets = dcount(DeviceName)
by AccountName, DeviceName, FileName
| extend
DetectionBranch = "InternalScannerExecution",
ScanIntensity = "Medium",
SourceIP = DeviceName,
UniqueSignatures = array_length(Signatures),
TargetPorts = dynamic([]),
ProbeURLs = dynamic([]),
DurationMinutes = datetime_diff('minute', LastSeen, FirstSeen),
DeviceVendor = "MicrosoftDefenderEndpoint",
DeviceProduct = FileName
| project
FirstSeen, LastSeen, DurationMinutes, SourceIP, ScanIntensity,
AlertCount, UniqueTargets, UniqueSignatures, Signatures,
TargetPorts, ProbeURLs, DeviceVendor, DeviceProduct, DetectionBranch;
IDSScanAlerts
| union InternalScanExecution
| sort by AlertCount desc Data Sources
Required Tables
False Positives
- Authorized vulnerability management programs (Nessus, Qualys, Rapid7 InsightVM) running scheduled scan jobs — scanner IPs should be documented in a known-good IP allowlist and matched against SourceIP
- Approved penetration testing or red team engagements — will generate high-volume scanner tool execution events on endpoints and IDS alerts during the engagement window
- Security operations or IT infrastructure teams running nmap, masscan, or asset discovery tooling for network inventory and exposure management
- Cloud security scanners (AWS Inspector, Microsoft Defender for Cloud continuous assessment, Tenable.io cloud connectors) probing cloud workloads from cloud provider IP ranges
- Bug bounty platform scanners or contracted external assessments arriving from third-party IP ranges with change management approval documentation
References (12)
- https://attack.mitre.org/techniques/T1595/002/
- https://owasp.org/www-project-automated-threats-to-web-applications/assets/oats/EN/OAT-014_Vulnerability_Scanning
- https://www.cisa.gov/news-events/cybersecurity-advisories/aa24-249a
- https://www.trendmicro.com/en_us/research/19/j/pawn-storm-use-of-vulnerability-scans.html
- https://www.crowdstrike.com/blog/aquatic-panda-targets-use-of-log4shell-exploit/
- https://www.sentinelone.com/labs/winter-vivern-all-we-need-is-one-click/
- https://learn.microsoft.com/en-us/azure/sentinel/connect-common-event-format
- https://learn.microsoft.com/en-us/defender-endpoint/advanced-hunting-deviceprocessevents-table
- https://nmap.org/book/man-version-detection.html
- https://github.com/projectdiscovery/nuclei
- https://github.com/sullo/nikto
- https://github.com/robertdavidgraham/masscan
Unlock Pro Content
Get the full detection package for T1595.002 including response playbook, investigation guide, and atomic red team tests.