Retrieving scan results through Nessus API

In this first article about Nessus API I want to describe process of getting scan results from Nessus.

Of course, it’s also great to create and run scans or even create policies via API. But to be honest, in practice, you may need this functionality rarely. And it’s easier to do it manually in GUI. On the other hand, sometimes it very efficient to create automatically some specific scan task for specific group of hosts using existing (inventory) scan results. But we will talk about this topic next time (Upd. I wrote post about scan creation “Nessus API for hosts scanning”).

Nessus API

Now, imagine that we have configured regular Nessus scans. And we want to get this scan results on a regular basis to make some analysis and maybe create some tickets in Jira.

As usual, I will use curl for all examples, because it is easy to read and easy to test in any Linux terminal.

Starting from Nessus v.6 the API manual is built in GUI: https://<scanner_ip>:8834/api#

In order to communicate with Nessus, we need to get a token. If we have a user “admin” with password “1” (this is wrong, because passwords must be complex, remember the warning during installation). We can token with this command:

curl -s -k -X POST -H 'Content-Type: application/json' -d "{\"username\":\"admin\",\"password\":\"1\"}" https://192.168.56.101:8834/session

{"token":"8b52551086c22dbf8954566099fd469c934f3706aaa6b025"}

Ok, we have a token, that we will use it in X-Cookie for every request. We know, that in GUI our scan task is called “Test Ubuntu Scan”. First of all, we need a scan_id of this scan. Let’s get the list of all scans:

curl -s -k -X GET -H "X-Cookie: token=8b52551086c22dbf8954566099fd469c934f3706aaa6b025" https://192.168.56.101:8834/scans | python -m json.tool

{
    "folders": [
        {
            "custom": 0,
            "default_tag": 1,
            "id": 313,
            "name": "My Scans",
            "type": "main",
            "unread_count": 1
        },
        {
            "custom": 0,
            "default_tag": 0,
            "id": 314,
            "name": "Trash",
            "type": "trash",
            "unread_count": null
        }
    ],
    "scans": [
        {
            "control": true,
            "creation_date": 1464970735,
            "enabled": false,
            "folder_id": 313,
            "id": 318,
            "last_modification_date": 1464970801,
            "name": "Test Ubuntu Scan",
            "owner": "admin",
            "read": false,
            "rrules": null,
            "shared": false,
            "starttime": null,
            "status": "completed",
            "timezone": null,
            "type": "local",
            "user_permissions": 128,
            "uuid": "f18bd8bd-a0c1-410f-79d2-ac427d7798378d1c324929b01998"
        }
    ],
    "timestamp": 1464971208
}

Ok, now we see “Test Ubuntu Scan” has id “318”. Let’s get more information about this scan.

curl -s -k -X GET -H "X-Cookie: token=8b52551086c22dbf8954566099fd469c934f3706aaa6b025" https://192.168.56.101:8834/scans/318 | python -m json.tool

{
    "comphosts": [],
    "compliance": [],
    "filters": [
        {
            "control": {
                "readable_regex": "CVE-YYYY-ID (ie: CVE-2011-0018)",
                "regex": "^(CVE|CAN)-(1999|20[01][0-9])-[0-9]{4,}$",
                "type": "entry"
            },
            "name": "cve",
            "operators": [
                "eq",
                "neq",
                "match",
                "nmatch"
            ],
            "readable_name": "CVE"
        },
[...]
        {
            "control": {
                "type": "datefield"
            },
            "name": "vuln_publication_date",
            "operators": [
                "date-lt",
                "date-gt",
                "date-eq",
                "date-neq",
                "match",
                "nmatch"
            ],
            "readable_name": "Vulnerability Publication Date"
        }
    ],
    "history": [
        {
            "alt_targets_used": false,
            "creation_date": 1444816022,
            "history_id": 319,
            "last_modification_date": 1444816093,
            "owner_id": 4,
            "scheduler": 0,
            "status": "completed",
            "type": "local",
            "uuid": "eec6d22e-27d7-3a56-422d-9941230b0ea88fdc32bd32332d61"
        {
            "alt_targets_used": false,
            "creation_date": 1444816385,
            "history_id": 320,
            "last_modification_date": 1444816451,
            "owner_id": 4,
            "scheduler": 0,
            "status": "completed",
            "type": "local",
            "uuid": "8dcc129f-81dc-780f-cce0-0c3940ef87a234444e6992ea571f"
        {
            "alt_targets_used": false,
            "creation_date": 1444818512,
            "history_id": 321,
            "last_modification_date": 1444818583,
            "owner_id": 4,
            "scheduler": 0,
            "status": "completed",
            "type": "local",
            "uuid": "303ae60a-11b2-6ccf-e3f2-6aadb74b82b92e3f2d40bc1d8233"
        {
            "alt_targets_used": false,
            "creation_date": 1447333579,
            "history_id": 381,
            "last_modification_date": 1447333652,
            "owner_id": 4,
            "scheduler": 0,
            "status": "completed",
            "type": "local",
            "uuid": "cf2ac68c-42c2-3817-f264-de36205bd94385c234ce85392cb2"
        },
        {
            "alt_targets_used": false,
            "creation_date": 1464970735,
            "history_id": 2613,
            "last_modification_date": 1464970801,
            "owner_id": 4,
            "scheduler": 0,
            "status": "completed",
            "type": "local",
            "uuid": "f18bd8bd-a0c1-410f-79d2-ac427d7798378d1cwee111b01998"
        }
    ],
    "hosts": [
        {
            "critical": 0,
            "high": 0,
            "host_id": 2,
            "host_index": 0,
            "hostname": "100.100.14.248",
            "info": 5,
            "low": 0,
            "medium": 0,
            "numchecksconsidered": 465,
            "progress": "465-465/79806-79806",
            "scanprogresscurrent": 465,
            "scanprogresstotal": 465,
            "score": 5,
            "severity": 5,
            "severitycount": {
                "item": [
                    {
                        "count": 5,
                        "severitylevel": 0
                    },
                    {
                        "count": 0,
                        "severitylevel": 1
                    },
                    {
                        "count": 0,
                        "severitylevel": 2
                    },
                    {
                        "count": 0,
                        "severitylevel": 3
                    },
                    {
                        "count": 0,
                        "severitylevel": 4
                    }
                ]
            },
            "totalchecksconsidered": 465
        }
    ],
    "info": {
        "acls": [
            {
                "display_name": null,
                "id": null,
                "name": null,
                "owner": null,
                "permissions": 0,
                "type": "default"
            },
            {
                "display_name": "admin",
                "id": 4,
                "name": "admin",
                "owner": 1,
                "permissions": 128,
                "type": "user"
            }
        ],
        "alt_targets_used": null,
        "control": true,
        "edit_allowed": true,
        "folder_id": 313,
        "hasaudittrail": true,
        "haskb": true,
        "hostcount": 1,
        "name": "Test Ubuntu Scan",
        "no_target": null,
        "object_id": 318,
        "pci-can-upload": false,
        "policy": "Advanced Scan",
        "scan_end": 1464970801,
        "scan_start": 1464970735,
        "scan_type": "local",
        "scanner_end": 1464970800,
        "scanner_name": "Local Scanner",
        "scanner_start": 1464970735,
        "status": "completed",
        "targets": "100.100.14.248",
        "timestamp": 1464970801,
        "user_permissions": 128,
        "uuid": "f18bd8bd-a0c1-410f-79d2-ac427d7798378d1cwee111b01998"
    },
    "notes": null,
    "remediations": {
        "num_cves": 1,
        "num_hosts": 1,
        "num_impacted_hosts": 0,
        "num_remediated_cves": 0,
        "remediations": null
    },
    "vulnerabilities": [
        {
            "count": 1,
            "plugin_family": "General",
            "plugin_id": 10287,
            "plugin_name": "Traceroute Information",
            "severity": 0,
            "severity_index": 0,
            "vuln_index": 9
        },
        {
            "count": 1,
            "plugin_family": "Settings",
            "plugin_id": 19506,
            "plugin_name": "Nessus Scan Information",
            "severity": 0,
            "severity_index": 1,
            "vuln_index": 8
        },
        {
            "count": 1,
            "plugin_family": "Settings",
            "plugin_id": 46215,
            "plugin_name": "Inconsistent Hostname and IP Address",
            "severity": 0,
            "severity_index": 2,
            "vuln_index": 7
        },
        {
            "count": 1,
            "plugin_family": "General",
            "plugin_id": 10114,
            "plugin_name": "ICMP Timestamp Request Remote Date Disclosure",
            "severity": 0,
            "severity_index": 3,
            "vuln_index": 6
        },
        {
            "count": 1,
            "plugin_family": "General",
            "plugin_id": 12053,
            "plugin_name": "Host Fully Qualified Domain Name (FQDN) Resolution",
            "severity": 0,
            "severity_index": 4,
            "vuln_index": 5
        }
    ]
}

The output is quite informative. As you can see, you can get right here statistics by hosts, vulnerabilities, remediations, information about scan policy and methods of results filtering. So, you may want to work with this output (and other API requests) instead of getting results in nessus2 format. As for me, I prefer to analyze nessus2 xml format more because it is the same for Nessus and Security Center, when API for those products is completely different. But it’s a matter of taste.

“History” part contains links (history_id) to the saved scan results. Let’s get scan results by history_id “2613” (with the latest Unix timestamp and “completed” status) in nessus2 xml format:

curl -s -k -X POST -H "X-Cookie: token=8b52551086c22dbf8954566099fd469c934f3706aaa6b025" -H 'Content-Type: application/json' -d '{"format": "nessus"}' https://192.168.56.101:8834/scans/318/export?history_id=2613

{"file":1178397097}

With this id I can check file status:

curl -s -k -X GET -H "X-Cookie: token=8b52551086c22dbf8954566099fd469c934f3706aaa6b025" -H 'Content-Type: application/json' https://192.168.56.101:8834/scans/318/export/1178397097/status

{"status":"loading"}

After some time it status will be changed to

{"status":"ready"}

Now I can download this file:

curl -s -k -X GET -H "X-Cookie: token=8b52551086c22dbf8954566099fd469c934f3706aaa6b025" -H 'Content-Type: application/json' https://192.168.56.101:8834/scans/318/export/1178397097/download

<!--?xml version="1.0" ?-->
<pre>
<?xml version="1.0" ?>
<NessusClientData_v2>
<Policy><policyName>Advanced Scan</policyName>
<Preferences><ServerPreferences><preference><name>service_detection.search_for_ssl</name>
<value>yes</value>
</preference>
<preference><name>plugin_set</name>
<value>36080;32809;84316;61117;35292;87560;75260;83156;[...]
</ReportItem>
</ReportHost>
</Report>
</NessusClientData_v2>

Analysis of scan results in nessus2 file format is very interesting topic, and I hope we will explore it next time.