Query Details

Hunt Public Remotly Exploitable Devices With High EPSS

Query

# *Hunt for public remotly exploitable devices (with high EPSS)*

## Query Information

#### MITRE ATT&CK Technique(s)

| Technique ID | Title    | Link    |
| ---  | --- | --- |
| T1190 | Exploit Public-Facing Application | https://attack.mitre.org/techniques/T1190 |


#### Description
This query searches for devices that comply with the following criteria:
- Incomming connections from public IP addresses in last 7 days (internet exposed)
- High or Critical severity CVE's
- CVE's must have known exploits
- CVE's are remotely exploitable over the network
- No user interaction is required to exploit the CVE's
- EPSS score of CVE must by above 10% (likelihood of exploitation)

> If devices are placed behind a proxy, they will not be returned in this query by default


#### Risk
Devices that return from these results are possible high-risk devices that could be exploited successfully any time. 


#### Author <Optional>
- **Name:** Robbe Van den Daele
- **Github:** https://github.com/RobbeVandenDaele
- **Twitter:** https://x.com/RobbeVdDaele
- **LinkedIn:** https://www.linkedin.com/in/robbe-van-den-daele-677986190/
- **Website:** https://hybridbrothers.com/

#### References

## Defender XDR
```KQL
// Flag remotly exploitable, no user interaction, CVE's with a EPSS score above a certain threshold (likelyhood of exploitation)
// For devices with incomming public connections
// See efficiency research on https://www.first.org/epss/model
let epss_threshold = 0.1;
let exploit_statusses = dynamic(["ExploitIsPublic","ExploitIsInKit","ExploitIsVerified"]);
// Xspm base query we materialize since we need these results multiple times
let xspm_base = materialize (
    ExposureGraphNodes
    // Get device nodes with their inventory ID
    | mv-expand EntityIds
    | where EntityIds.type == "DeviceInventoryId"
    // Get first important properties
    | extend DeviceId = tostring(parse_json(EntityIds)["id"]),
        ExposureScore = tostring(parse_json(NodeProperties)["rawData"]["exposureScore"]),
        HasHighOrCriticalCve = tostring(parse_json(NodeProperties)["rawData"]["highRiskVulnerabilityInsights"]["hasHighOrCritical"])
    // Focus on devices with high exposure
    | where ExposureScore == "High"
    // Get vulnerability exploit information
    | extend RceExploitLevels = parse_json(NodeProperties)["rawData"]["highRiskVulnerabilityInsights"]["vulnerableToRemoteCodeExecution"]["explotabilityLevels"]
    | extend PrivEscExploitLevels = parse_json(NodeProperties)["rawData"]["highRiskVulnerabilityInsights"]["vulnerableToPrivilegeEscalation"]["explotabilityLevels"]
    // Focus on devices where cve has known epxloits
    | where RceExploitLevels has_any (exploit_statusses) or PrivEscExploitLevels has_any (exploit_statusses)
    // Focus on devices that are public exposed
    | join kind=inner (
        DeviceNetworkEvents
        | where TimeGenerated > ago(7d)
        | where ActionType contains "InboundConnection"
        | where RemoteIPType == "Public"
        // Exclude MacOS Rapportd and ControlCenter
        | where InitiatingProcessFileName != "rapportd" and InitiatingProcessFileName != "controlcenter"
        | distinct DeviceName, DeviceId, LocalPort, InitiatingProcessFolderPath, InitiatingProcessVersionInfoProductName, InitiatingProcessFileName
    ) on $left.DeviceId == $right.DeviceId
    // Save all the open ports and their process in a JSON
    | extend OpenPortJson = bag_pack_columns(LocalPort, InitiatingProcessFolderPath, InitiatingProcessFileName)
    // Save open ports by Device ID
    | summarize PublicOpenPortList = make_set(OpenPortJson) by DeviceId
);
// Save flagged device IDs in list to limit results of CVE's we need to search later
let flagged_devices = toscalar(
    xspm_base
    | summarize make_set(DeviceId)
);
// CVE base query we materialize since we need these results multiple times
let cve_base = materialize (
    DeviceTvmSoftwareVulnerabilities
    | where VulnerabilitySeverityLevel in ("High", "Critical")
    | where DeviceId in ( flagged_devices )
);
// Save flagged CVE IDs in list to limit results of CVE database we need to search later
let flagged_cves = toscalar(
    cve_base
    | summarize make_set(CveId)
);
// Query the CVE's of the flagged devices
cve_base
// Enrich the CVE data with their EPSS and CVSS Score
| join kind=inner (
    DeviceTvmSoftwareVulnerabilitiesKB
    // Focus on flagged CVE's
    | where CveId in ( flagged_cves )
    // Focus on CVE's tagged with Attack Vector being over the Network
    // 'Vulnerabilities with this rating are remotely exploitable, from one or more hops away, up to and including remote exploitation over the Internet.'
    // 'Does not require user interaction'
    | where CvssVector contains "/AV:N" and CvssVector contains "/UI:N"
    // Focus on CVE's where an exploit is available
    | where IsExploitAvailable != 0
    | distinct CveId, EpssScore, CvssScore, CvssVector, IsExploitAvailable, AffectedSoftwareList=tostring(AffectedSoftware)
) on CveId
// Continue with only relevant data
| project DeviceId, DeviceName, OSPlatform, OSVersion, OSArchitecture, SoftwareName, SoftwareVendor, SoftwareVersion, CveId, VulnerabilitySeverityLevel, EpssScore, CvssScore, CvssVector, IsExploitAvailable, AffectedSoftwareList
// Now flag CVE's with a EPSS score above a certain threshold
// See efficiency research on https://www.first.org/epss/model
| where EpssScore >= epss_threshold
// Save all the CVE data in a JSON column
| extend CveJson = bag_pack_columns(SoftwareName, SoftwareVendor, SoftwareVersion, CveId, EpssScore, CvssScore, CvssVector, IsExploitAvailable, AffectedSoftwareList)
// Group the CVE data for each device per device
| summarize CveList = make_list(CveJson) by DeviceId, DeviceName
// Add xspm data again
| join kind=inner xspm_base on DeviceId
| project-away DeviceId1
// Sort by CVE amount
| extend CveCount = array_length(CveList)
| sort by CveCount desc
```

Explanation

This query is designed to identify potentially vulnerable devices within a network that are at high risk of being exploited. Here's a simplified breakdown of what the query does:

  1. Objective: The query aims to find devices that are exposed to the internet and have vulnerabilities that can be exploited remotely without user interaction. These vulnerabilities have a high likelihood of being exploited, as indicated by their EPSS (Exploit Prediction Scoring System) score.

  2. Criteria for Identifying Devices:

    • The device has received incoming connections from public IP addresses in the last 7 days, indicating it is exposed to the internet.
    • The device has vulnerabilities (CVEs) classified as high or critical severity.
    • These vulnerabilities have known exploits available.
    • The vulnerabilities can be exploited remotely over the network without requiring any user interaction.
    • The EPSS score of these vulnerabilities is above 10%, suggesting a higher likelihood of exploitation.
  3. Process:

    • The query first identifies devices with a high exposure score and known vulnerabilities that can be exploited remotely.
    • It checks for incoming connections from public IPs to ensure the devices are internet-exposed.
    • It gathers information about open ports and processes on these devices.
    • It filters vulnerabilities to include only those with a high or critical severity and a high EPSS score.
    • It compiles a list of these vulnerabilities for each device.
  4. Output:

    • The query outputs a list of devices along with their associated vulnerabilities, sorted by the number of vulnerabilities each device has. This helps prioritize which devices might need immediate attention due to their high risk of exploitation.
  5. Risk:

    • Devices identified by this query are considered high-risk and could be exploited at any time, making them a priority for security teams to address.

Overall, this query helps security teams proactively identify and mitigate risks associated with publicly exposed devices that have severe vulnerabilities.

Details

Robbe Van den Daele profile picture

Robbe Van den Daele

Released: September 15, 2025

Tables

ExposureGraphNodesDeviceNetworkEventsDeviceTvmSoftwareVulnerabilitiesDeviceTvmSoftwareVulnerabilitiesKB

Keywords

Devices

Operators

letmaterializemv-expandwhereextendparse_jsontostringhas_anyjoinkind=innerondistinctbag_pack_columnssummarizemake_settoscalarinprojectcontainsproject-awayarray_lengthsort bydesc

Actions