I was asked from people if Microsoft Defender for Cloud had any information related to the CVE-2021-44228 (Log4Shell) vulnerability which is currently the hottest vulnerability right now.
In this article, I would like to share a Resource Graph Query to find virtual machines that are vulnerable against Log4Shell vulnerability.
Currently there are several vulnerability solutions that are supported to send data to Microsoft Defender for Cloud. Some common ones include Qualys (built-in vulnerability assessment) and Rapid 7. Log Analytics Agent would also report missing security patches on virtual machines.
securityresources | where type == "microsoft.security/assessments/subassessments" // Parse main assessment | extend data = properties.additionalData, displayName = properties.displayName, resourceId = properties.resourceDetails.id, timeGenerated = properties.timeGenerated, severity = properties.status.severity, statusCode = properties.status.code | extend assessedResourceType = tostring(data.assessedResourceType), source = data.source | mv-expand cves = data['cve'] | extend cve_number = cves['title'], cve_link_ref = cves['link'] | extend resourceName = split(resourceId,'/')[8], resourceGroup = split(resourceId,'/')[4], subscriptionId = split(resourceId,'/')[2] | where assessedResourceType == "ServerVulnerability" | where cve_number == "CVE-2021-44228" | project resourceName, resourceGroup, subscriptionId, displayName, cve_number, cve_link_ref, data, properties
This query works with VMs that have built-in vulnerability assessment solution aka Qualys installed. However you can modify the query to add another source such as Rapid 7 or data from UpdateManagement solution.
By the way, you can check from Microsoft Defender for Cloud under recommendation named “Machines should have vulnerability findings resolved“.
AzSec is working on a complete query to cover other sources. Right now if you have built-in VA you can test on your environment.
Use the following query to search data from Rapid 7, Qualys or UpdateManagement
securityresources | where type == "microsoft.security/assessments/subassessments" // Parse main assessment | extend data = properties.additionalData, displayName = properties.displayName, resourceId = properties.resourceDetails.id, timeGenerated = properties.timeGenerated, severity = properties.status.severity, statusCode = properties.status.code | extend assessedResourceType = tostring(data.assessedResourceType), source = data.source | mv-expand cves = data['cve'] | extend cveNumber = cves['title'], cveRef = cves['link'] | extend resourceName = split(resourceId,'/')[8], resourceGroup = split(resourceId,'/')[4], subscriptionId = split(resourceId,'/')[2] // Filter for Qualys (built-in ASC Vulnerability Assessment) and Rapid 7 | where assessedResourceType == "ServerVulnerability" | project resourceId, displayName, cveNumber, cveRef, data, properties | union ( securityresources | where type == "microsoft.security/assessments/subassessments" // Parse main assessment for Update Management | extend data = properties.additionalData, displayName = properties.displayName, resourceId = properties.resourceDetails.id, timeGenerated = properties.timeGenerated, severity = properties.status.severity, statusCode = properties.status.code // Parse assessment data | extend assessedResourceType = tostring(data.assessedResourceType), packageRepository = data.PackageRepository, cveNumber = data.data.CVENumbers, product = data.data.Product, OsType = data.data.OsType, cveRef = data.data.BulletinUrl // Filter for UpdateManagement | where assessedResourceType == "GeneralVulnerability" | extend resourceName = split(resourceId,'/')[8], resourceGroup = split(resourceId,'/')[4], subscriptionId = split(resourceId,'/')[2] | project resourceId, displayName, cveNumber, cveRef, data, properties ) // Search for CVEs | where cveNumber in ("CVE-2021-44228", "CVE-2021-45046") | extend resourceName = split(resourceId,'/')[8], resourceGroup = split(resourceId,'/')[4], subscriptionId = split(resourceId,'/')[2] | summarize cveLists = make_list(cveNumber) by tostring(resourceId) | extend resourceName = split(resourceId,'/')[8], resourceGroup = split(resourceId,'/')[4], subscriptionId = tostring(split(resourceId,'/')[2]) | join kind=leftouter( resourcecontainers | where type=='microsoft.resources/subscriptions' | project subscriptionName=name, subscriptionId ) on subscriptionId
If you are working on Azure environment, I’d highly recommend you to check this article from Microsoft MSRC