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.

13 thoughts on “Retrieving scan results through Nessus API

  1. Pingback: Tenable Nessus: registration, installation, scanning and reporting | Alexander V. Leonov

  2. Pingback: Choosing the right time for Nessus update | Alexander V. Leonov

  3. Pingback: Nessus V2 xml report format | Alexander V. Leonov

  4. Pingback: Vulnerability Assessment without Vulnerability Scanner | Alexander V. Leonov

  5. Pingback: Tenable SecurityCenter and its API | Alexander V. Leonov

  6. Pingback: Export anything in Splunk with HTTP Event Collector | Alexander V. Leonov

  7. Pingback: Nessus API for hosts scanning | Alexander V. Leonov

  8. Pingback: Custom Vulnerability Management Reports | Alexander V. Leonov

  9. Pingback: Parsing Nessus v2 XML reports with python | Alexander V. Leonov

  10. Pingback: What’s actually new in Tenable.io VM application | Alexander V. Leonov

  11. Pingback: Tracking software versions using Nessus and Splunk | Alexander V. Leonov

  12. Justin

    Hi Alexander,

    When using this curl command: curl -s -k -X POST -H ‘Content-Type: application/json’ -d “{\”username\”:\”admin\”,\”password\”:\”1\”}” https://192.168.56.101:8834/session

    I am getting the following error: {“error”:”Missing ‘username’ field”}

    I am of course changing your command to include the IP to my Nessus server as well as using the credentials I would log in to the GUI with. Any thoughts as to why this is happening?

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *