Blog Post

Microsoft Defender for Cloud Blog
2 MIN READ

Exporting Azure Container Registry Vulnerability Assessment in Microsoft Defender for Cloud

YuriDiogenes's avatar
YuriDiogenes
Icon for Microsoft rankMicrosoft
Mar 26, 2020

Using Microsoft Defender for Containers  plan, you can monitor your ARM-based Azure Container Registry. When a new image is pushed, Microsoft Defender for Cloud scans the image using a scanner from the industry-leading vulnerability scanning vendor, Qualys.

For every vulnerability, Microsoft Defender for Cloud provides actionable recommendations, along with guidance for how to remediate the issue. This assessment is available in the Microsoft Defender for Cloud dashboard as shown below:

 

 

While this visualization is very helpful and dynamic, one question that comes up very often is: how can I export this assessment to a CSV file? The answer is: you can do that using Azure Resource Graph (ARG)! Follow the steps below to perform this task:

 

1. In the Azure Portal, go to Resource Graph Explorer as shown below:

 

 

2. Type the query below:

 

securityresources
where type == "microsoft.security/assessments"
where properties.displayName contains "Vulnerabilities in Azure Container Registry images should be remediated"
summarize by assessmentKey=name //the ID of the assessment
join kind=inner (
    securityresources
     | where type == "microsoft.security/assessments/subassessments"
     | extend assessmentKey = extract(".*assessments/(.+?)/.*",1,  id)
 ) on assessmentKey
project assessmentKey, subassessmentKey=name, id, parse_json(properties), resourceGroup, subscriptionId, tenantId
extend description = properties.description,
         displayName = properties.displayName,
         resourceId = properties.resourceDetails.id,
         resourceSource = properties.resourceDetails.source,
         category = properties.category,
         severity = properties.status.severity,
         code = properties.status.code,
         timeGenerated = properties.timeGenerated,
         remediation = properties.remediation,
         impact = properties.impact,
         vulnId = properties.id,
         additionalData = properties.additionalData

 

3. Click Run Query button and you will see the result, similar to figure below:

 

4. Click Download as CSV button.

Now that you download the CVS, you can open it and consume the data generated by the assessment.

 

Reviewers:

Maya Herskovic, Assaf Israel and Lana Salameh from the Microsoft Defender for Cloud Engineering Team

Updated Oct 28, 2021
Version 6.0

6 Comments

  • deval1870's avatar
    deval1870
    Copper Contributor
    ### Azure Resource Graph Query for Extracting Detailed Security Assessment Data
    
    This Azure Resource Graph query helps extract detailed information about security assessments and sub-assessments. The query is designed to handle nested JSON properties and convert them into separate columns for easier analysis and export.
    
    **Query:**
    ```kusto
    securityresources
    | where type == "microsoft.security/assessments"
    | summarize by assessmentKey = name
    | join kind=inner (
       securityresources
       | where type == "microsoft.security/assessments/subassessments"
       | extend assessmentKey = extract(".*assessments/(.+?)/.*", 1, id)
    ) on assessmentKey
    | project assessmentKey, subassessmentKey = name, id, parse_json(properties), resourceGroup, subscriptionId, tenantId
    | extend
       description = tostring(properties.description),
       resourceProvider = tostring(properties.resourceDetails.ResourceProvider),
       resourceName = tostring(properties.resourceDetails.ResourceName),
       resourceType = tostring(properties.resourceDetails.ResourceType),
       nativeResourceId = tostring(properties.resourceDetails.NativeResourceId),
       vulnerabilityId = tostring(properties.id),
       source = tostring(properties.resourceDetails.source),
       displayName = tostring(properties.displayName),
       cveDescriptionAdditionalInformation = tostring(properties.additionalData.cveDescriptionAdditionalInformation),
       assessedResourceType = tostring(properties.additionalData.assessedResourceType),
       severity = tostring(properties.additionalData.vulnerabilityDetails.severity),
       lastModifiedDate = tostring(properties.additionalData.vulnerabilityDetails.lastModifiedDate),
       exploitabilityAssessment = parse_json(properties.additionalData.vulnerabilityDetails.exploitabilityAssessment),
       exploitStepsPublished = parse_json(properties.additionalData.vulnerabilityDetails.exploitabilityAssessment.exploitStepsPublished),
       exploitStepsVerified = parse_json(properties.additionalData.vulnerabilityDetails.exploitabilityAssessment.exploitStepsVerified),
       exploitUris = parse_json(properties.additionalData.vulnerabilityDetails.exploitabilityAssessment.exploitUris),
       isInExploitKit = parse_json(properties.additionalData.vulnerabilityDetails.exploitabilityAssessment.isInExploitKit),
       exploitTypes = parse_json(properties.additionalData.vulnerabilityDetails.exploitabilityAssessment.types),
       publishedDate = tostring(properties.additionalData.vulnerabilityDetails.publishedDate),
       workarounds = tostring(properties.additionalData.vulnerabilityDetails.workarounds),
       references = tostring(properties.additionalData.vulnerabilityDetails.references),
       weaknesses = tostring(properties.additionalData.vulnerabilityDetails.weaknesses),
       cveId = tostring(properties.additionalData.vulnerabilityDetails.cveId),
       cvssVectorString = tostring(properties.additionalData.vulnerabilityDetails.cvss.['3.0'].cvssVectorString),
       baseScore = todouble(properties.additionalData.vulnerabilityDetails.cvss.['3.0'].base),
       cpe = parse_json(properties.additionalData.vulnerabilityDetails.cpe),
       cpeUri = parse_json(properties.additionalData.vulnerabilityDetails.cpe.uri),
       lastPushedToRegistryUTC = tostring(properties.additionalData.artifactDetails.lastPushedToRegistryUTC),
       repositoryName = tostring(properties.additionalData.artifactDetails.repositoryName),
       artifactType = tostring(properties.additionalData.artifactDetails.artifactType),
       registryHost = tostring(properties.additionalData.artifactDetails.registryHost),
       mediaType = tostring(properties.additionalData.artifactDetails.mediaType),
       digest = tostring(properties.additionalData.artifactDetails.digest),
       tags = tostring(properties.additionalData.artifactDetails.tags),
       language = tostring(properties.additionalData.softwareDetails.language),
       version = tostring(properties.additionalData.softwareDetails.version),
       vendor = tostring(properties.additionalData.softwareDetails.vendor),
       fixedVersion = tostring(properties.additionalData.softwareDetails.fixedVersion),
       packageName = tostring(properties.additionalData.softwareDetails.packageName),
       category = tostring(properties.additionalData.softwareDetails.category),
       fixStatus = tostring(properties.additionalData.softwareDetails.fixStatus),
       osPlatform = tostring(properties.additionalData.softwareDetails.osDetails.osPlatform),
       osVersion = tostring(properties.additionalData.softwareDetails.osDetails.osVersion),
       fixReferenceDescription = tostring(properties.additionalData.softwareDetails.fixReference.description),
       fixReferenceId = tostring(properties.additionalData.softwareDetails.fixReference.id),
       fixReferenceReleaseDate = tostring(properties.additionalData.softwareDetails.fixReference.releaseDate),
       fixReferenceUrl = tostring(properties.additionalData.softwareDetails.fixReference.url),
       evidence = tostring(properties.additionalData.softwareDetails.evidence),
       cvssV30Score = todouble(properties.additionalData.cvssV30Score),
       timeGenerated = tostring(properties.timeGenerated),
       remediation = tostring(properties.remediation),
       statusSeverity = tostring(properties.status.severity),
       statusCode = tostring(properties.status.code),
       impact = tostring(properties.impact)

     

     

  • akssingh_shs's avatar
    akssingh_shs
    Copper Contributor

    Rajivmishra 

     

    Looks "properties.displayName" used in query has been changed in defender recommendation , please used given "properties.displayName" in query and then try it should work .

    "Container registry images should have vulnerability findings resolved"

     

    SecurityResources
    where type == 'microsoft.security/assessments'
    where properties.displayName contains 'Container registry images should have vulnerability findings resolved'
    summarize by assessmentKey=name //the ID of the assessment
    join kind=inner (
        securityresources
        | where type == 'microsoft.security/assessments/subassessments'
        | extend assessmentKey = extract('.*assessments/(.+?)/.*',1,  id)
    ) on assessmentKey
    project assessmentKey, subassessmentKey=name, id, parse_json(properties), resourceGroup, subscriptionId, tenantId
    extend description = properties.description,
        displayName = properties.displayName,
        resourceId = properties.resourceDetails.id,
        resourceSource = properties.resourceDetails.source,
        category = properties.category,
        severity = properties.status.severity,
        code = properties.status.code,
        timeGenerated = properties.timeGenerated,
        remediation = properties.remediation,
        impact = properties.impact,
        vulnId = properties.id,
        additionalData = properties.additionalData
        
        
        

     

    YuriDiogenes 

     

  • Rajivmishra's avatar
    Rajivmishra
    Copper Contributor

    Hi Yuri Diogenes,

     

    I am getting error while using your query saying The name 'displayName' does not refer to any known column, table, variable or function. from below line with displayName

     

    where properties.displayName contains 'Vulnerabilities in Azure Container Registry images should be remediated'
     
    Could you please advice here?
     
    Thanks
    Rajiv
     
     

     

     

  • ktaylor2285's avatar
    ktaylor2285
    Copper Contributor
    Microsoft Defender for Cloud , Recommendation , All recommendations
     
    Run below kusto queries in Azure Resource Graph Explorer.
     
     
    securityresources
    where type == "microsoft.security/assessments"
    extend displayName = trim(" ", tostring(properties.metadata.displayName))
    where displayName == "Deprecated accounts should be removed from your subscription"
     
     
    securityresources
    where type == "microsoft.security/assessments"
    extend source = trim(' ', tolower(tostring(properties.resourceDetails.Source)))
    extend resourceId = trim(' ', tolower(tostring(case(source =~ "azure", properties.resourceDetails.Id,extract('^(.+)/providers/Microsoft.Security/assessments/.+$',1,id)))))
    extend displayName = trim(" ", tostring(properties.metadata.displayName))
    extend description = trim(" ", tostring(properties.metadata.description))
    extend remediationDescription = trim(" ", tostring(properties.metadata.remediationDescription))
    extend status = trim(" ", tostring(properties.status.code))
    extend cause = trim(" ", tostring(properties.status.cause))
    extend severity = trim(" ", tostring(properties.metadata.severity))
    extend userImpact = trim(" ", tostring(properties.metadata.userImpact))
    extend azurePortal = trim(" ", tostring(properties.links.azurePortal))
    extend statusChangeDate = trim(" ", tostring(properties.status.statusChangeDate))
    extend assessmentKey = tostring(name)
    where displayName == "Deprecated accounts should be removed from your subscription"
    sort by todatetime(statusChangeDate)
     
     
    // *** displayName = Recommendation column in below screenshot.
    // *** status = Unhealthy resources column in below screenshot.
     
     
  • gadinaor's avatar
    gadinaor
    Copper Contributor

    YuriDiogenes is there a way to retrieve the package information as a typed field in the query ?

    Also, what the query should look like if one would want to have 1 CVE per line?

     

    {
        "description": "Debian has released security update for systemd to fix the vulnerabilities.<P>",
        "displayName": "Debian Security Update for systemd",
        "resourceDetails": {
            "source": "Azure",
            "id": "/repositories/myrepo/manyvuln/images/sha256:4343f035d365cc3968f4276e712dbb42908de6f5538611668b03b7b69c142593"
        },
        "additionalData": {
            "assessedResourceType": "ContainerRegistryVulnerability",
            "vendorReferences": [
                {
                    "title": "CVE-2018-1049",
                    "link": "https://security-tracker.debian.org/tracker/CVE-2018-1049"
                },
                {
                    "title": "CVE-2018-15686",
                    "link": "https://security-tracker.debian.org/tracker/CVE-2018-15686"
                }
            ],
            "publishedTime": "2019-05-06T10:54:00.0000000Z",
            "patchable": true,
            "type": "Vulnerability",
            "cvss": {
                "2.0": {
                    "base": 10
                },
                "3.0": {
                    "base": 9.8
                }
            },
            "cve": [
                {
                    "title": "CVE-2018-1049",
                    "link": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-1049"
                },
                {
                    "title": "CVE-2018-15686",
                    "link": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-15686"
                }
            ],
            "repositoryName": "myrepo/manyvuln",
            "registryHost": "myregistry.azurecr.io",
            "imageDigest": "sha256:4343f035d365cc3968f4276e712dbb42908de6f5538611668b03b7b69c142593"
        },
        "status": {
            "severity": "High",
            "code": "Unhealthy"
        },
        "timeGenerated": "2020-10-17T07:35:03.4900000Z",
        "remediation": "Refer to <A HREF=\"https://security-tracker.debian.org/tracker/CVE-2018-15686\" TARGET=\"_blank\">Debian 9 - CVE-2018-15686</A> and <A HREF=\"https://security-tracker.debian.org/tracker/CVE-2018-1049\" TARGET=\"_blank\">Debian 9 - CVE-2018-1049</A> to address this issue and obtain further details.\n<P>Patch:<BR>\nFollowing are links for downloading patches to fix the vulnerabilities:\n<P> <A HREF=\"https://security-tracker.debian.org/tracker/CVE-2018-15686\" TARGET=\"_blank\">CVE-2018-15686: Debian</A><P> <A HREF=\"https://security-tracker.debian.org/tracker/https://security-tracker.debian.org/tracker/CVE-2018-15686\" TARGET=\"_blank\">CVE-2018-1049: Debian</A>",
        "category": "Debian",
        "id": "176875",
        "impact": "This vulnerability could be exploited to gain partial access to sensitive information. Malicious users could also use this vulnerability to change partial contents or configuration on the system. Additionally this vulnerability can also be used to cause a limited denial of service in the form of interruptions in resource availability."
    }