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“).
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.
Hi! My name is Alexander and I am a Vulnerability Management specialist. You can read more about me here. Currently, the best way to follow me is my Telegram channel @avleonovcom. I update it more often than this site. If you haven’t used Telegram yet, give it a try. It’s great. You can discuss my posts or ask questions at @avleonovchat.
А всех русскоязычных я приглашаю в ещё один телеграмм канал @avleonovrus, первым делом теперь пишу туда.
Pingback: Tenable Nessus: registration, installation, scanning and reporting | Alexander V. Leonov
Pingback: Choosing the right time for Nessus update | Alexander V. Leonov
Pingback: Nessus V2 xml report format | Alexander V. Leonov
Pingback: Vulnerability Assessment without Vulnerability Scanner | Alexander V. Leonov
Pingback: Tenable SecurityCenter and its API | Alexander V. Leonov
Pingback: Export anything in Splunk with HTTP Event Collector | Alexander V. Leonov
Pingback: Nessus API for hosts scanning | Alexander V. Leonov
Pingback: Custom Vulnerability Management Reports | Alexander V. Leonov
Pingback: Parsing Nessus v2 XML reports with python | Alexander V. Leonov
Pingback: What’s actually new in Tenable.io VM application | Alexander V. Leonov
Pingback: Tracking software versions using Nessus and Splunk | Alexander V. Leonov
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?
@Justin,
I had to make some small syntax tweaks and then I was able to get the token:
curl -s -k -X POST -H ‘Content-Type: application/json’ -d ‘{“username”:”joemama”,”password”:”Password123!”}’ https://10.100.10.1:8834/session
Hi Alexander, I just want to give you credit for your article. I used it to develop an entire program at my company. These APIs are facilitating the management of tens of thousands of hosts with the Nessus Professional product, saving our company hundreds of thousands of dollars.
While Tenable is preparing to shut down the API for N.P., I am hopeful that I can still use it through Tenable.IO.
Just a note to say thank-you, it’s really appreciated.
Hi! Thanks for your kind words! You were right, Tenable really finally did it. Very sad.
Great articles – helped me develop similar in Python. Sadly, all in vain now Tenable have pulled the API in version 7 – we have just had to can the project and cancel our Nessus order.
Thanks, Julian! Yes, it’s very sad. I also thinking what to do next.
Tenable has pulled the API in version 7. Does this apply to this article?
I thought the Tenable REST API uses access keys and secret keys. In this article, username and password are used for authentication, which I thought was the basic web functionality.
Hi, John! Unfortunately, they pulled from NP the API I used in this post. This apply to the article.
Nessus REST API supports Session Token and API Keys for authentication. This example uses Session Token. https://cloud.tenable.com/api#/resources/session/create
Yiou can also use keys: https://cloud.tenable.com/api#/authorization
Hi Alexander,
Thanks for puttiung this up. It’s REALLY helpful (especially that the functionality has been readded to 7.0.3).
Do you knopw if there’s any way to filter the output to severity > 0? (i.e. only low/medium/high/critical?). I’m currently downloading scans of a few thousand hosts and the raw nessus files total around 4Gb. I tarball them before downloading, but then need to process them with perl in their uncopressed state, but the full nessus files are too big.
Thanks again!
Jim
In reply to my previous question… If anyone out there needs an answer:
xmlstarlet ed -L -d ‘//ReportItem[@severity=”0″]’ filename.nessus
xmlstarlet ed -L -d //ReportHost[not\(.//ReportItem\)] filename.nessus
Hi Alexander,
I generated api keys in Nessus scanner and I try use:
curl -k -H “X-Impersonate: username={test}” -H “X-ApiKeys: accessKey={3ea8251517ff6de23d86f0ee61cc2caa7aee6a052520d715d1692bb9c2575458}; secretKey={bad16019001f7104df864824dc7af091bf867542dd6b8023252ff5738dc6d897}” https://192.168.1.43:8834/scans
or
curl -k -H “X-ApiKeys: accessKey={3ea8251517ff6de23d86f0ee61cc2caa7aee6a052520d715d1692bb9c2575458}; secretKey={bad16019001f7104df864824dc7af091bf867542dd6b8023252ff5738dc6d897}” https://192.168.1.43:8834/scans
I have error “invalid credentials”, I double-checked all from my side, I haven’t error from my side.
Also if I use session token from your script:
curl -s -k -X POST -H ‘Content-Type: application/json’ -d “{\”username\”:\”admin\”,\”password\”:\”1\”}” https://192.168.1.43:8834/session
This script is work, but I can’t use this token because every time if I use this script this token has new value.
Can you clarify for me this ? How can I use token with one session ?
I found my error in previous message. I used wrong key – “{key}” instead just – “key” . Fields keys needs use without “{}”
Thanks Alexander !
I’m able to get report using python. When I tried to convert it to Ansible module, It is failing at scan.scan_results().
Any idea
Hi Alexander,
I try connect the Tenable Security Center v5 with IBM QRadar and there is needed a user account for authentication with API.
Nowhere reported the Role of this user ! Do you know the Role for just user API authentication?
ps. I havent used Tenable Security Center before !
Thanks in advance,
Ioannis
Pingback: Making simple Nmap SPA web GUI with Apache, AngularJS and Python Twisted | Alexander V. Leonov
Hello,
I have been using PyTeable and we have a report called “Report X” under Reports section of Security Center. This report will automatically create under “Report” section. I would like to download it using API. Can you please point me in a correct direction?