Last active
February 26, 2024 14:01
-
-
Save dreizehnutters/e01d3a466617ef958a29fa4300036edc to your computer and use it in GitHub Desktop.
export nessus reports via CLI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
__version__ = "1.0" | |
__about__ = "nessus report exporter" | |
from time import sleep | |
from os import environ | |
import requests | |
from requests.packages.urllib3.exceptions import InsecureRequestWarning | |
requests.packages.urllib3.disable_warnings(InsecureRequestWarning) | |
# DEFAULTS | |
AK = environ.get('NESSUS_AK') # CHANGE ME | |
SK = environ.get('NESSUS_SK') # CHANGE ME | |
TEMPLATE_ID = 1321 # CHANGE ME | |
CHUNK_SIZE = 1024 | |
NESSUS_INSTANCE = "localhost:8834" | |
OUT_DIR= "~/Desktop" | |
def trigger_download(scan_id, export_format='html'): | |
""" | |
return file_id | |
""" | |
burp0_url = f"https://{NESSUS_INSTANCE}/scans/{scan_id}/export" | |
burp0_headers = {"Content-Type": "application/json",\ | |
"X-Requested-With": "XMLHttpRequest",\ | |
"X-ApiKeys": f"accessKey={AK}; secretKey={SK}", "Connection": "close"} | |
burp0_json={"format": export_format, "template_id": TEMPLATE_ID} | |
resp = requests.post(burp0_url, headers=burp0_headers, json=burp0_json, verify=False, timeout=10) | |
if resp.status_code == 200: | |
try: | |
file_id = resp.json()['file'] | |
except Exception as err: | |
raise Exception(err) | |
else: | |
raise Exception(f"[!] {resp.text} (scan_id: {scan_id})") | |
return file_id | |
def download_report(scan_id, file_id, filename): | |
""" | |
return True if downloaded else False | |
""" | |
burp0_url = f"https://{NESSUS_INSTANCE}/scans/{scan_id}/export/{file_id}/download" | |
burp0_headers = {"Content-Type": "application/json",\ | |
"X-Requested-With": "XMLHttpRequest",\ | |
"X-ApiKeys": f"accessKey={AK}; secretKey={SK};",\ | |
"Connection": "close"} | |
resp = requests.get(burp0_url, headers=burp0_headers, verify=False, timeout=10) | |
if resp.status_code != 200: | |
return False | |
with open(f"{OUT_DIR}/{filename}", 'wb') as fd: | |
for chunk in resp.iter_content(CHUNK_SIZE): | |
fd.write(chunk) | |
return True | |
def select_scan_id(): | |
""" | |
return scan_id from user input | |
""" | |
choices = get_all_scan_ids() | |
for idx, name in enumerate(choices): | |
print(f"[{idx}] {name[0]}") | |
choice = -1 | |
while choice not in range(len(choices)): | |
try: | |
choice = int(input(f"[?] select a scan: 0-{len(choices)-1}: ")) | |
print("") | |
except Exception as err: | |
continue | |
if choice in range(len(choices)): | |
return (choices[choice][0], choices[choice][1]) | |
def get_all_scan_ids(): | |
""" | |
return list of scan ids that are ready to be exported (not in trash and completed) | |
""" | |
burp0_url = f"https://{NESSUS_INSTANCE}/scans" | |
burp0_headers = {"Content-Type": "application/json", | |
"X-Requested-With": "XMLHttpRequest", | |
"X-ApiKeys": f"accessKey={AK}; secretKey={SK};", | |
"Connection": "close"} | |
resp = requests.get(burp0_url, headers=burp0_headers, verify=False, timeout=10) | |
if resp.json()['scans'] is None: | |
exit("[!] no scans is ready to be exported") | |
trash_folder_id = [x['id'] for x in resp.json()['folders'] if x['type'] == 'trash'][-1] | |
scan_ids = [(x['name'], x['id']) for x in resp.json()['scans'] if x['status'] in ('completed', 'canceled', 'imported') and x['folder_id'] != trash_folder_id] | |
if len(scan_ids) > 0: | |
return scan_ids | |
exit("[!] no scans is ready to be exported") | |
def do_download(scan_id, file_id, filename): | |
""" | |
download file if status is ready | |
""" | |
code = False | |
n_sek = 0 | |
while code is not True: | |
print(f"\t[z] the report is being generated since {n_sek:02d} sec", end='\r') | |
code = download_report(scan_id, file_id, filename) | |
sleep(1) | |
n_sek+=1 | |
print(f"{' '*80}",end='\r') | |
if __name__ == '__main__': | |
option = input("[?] export all scans (y/n): ") | |
print("") | |
if (option.lower() == 'y') or (option.lower() == 'j'): | |
scan_ids = get_all_scan_ids() | |
else: | |
scan_ids = [select_scan_id()] | |
for scan_tuple in scan_ids: | |
print(f"[*] downloading report: '{scan_tuple[0]}'") | |
scan_id = scan_tuple[1] | |
for export_format in ['html', 'nessus']: | |
print(f"\t[.] getting the .{export_format} version") | |
try: | |
file_id = trigger_download(scan_id, export_format) | |
except Exception as err: | |
print(err) | |
continue | |
do_download(scan_id, file_id, filename=scan_tuple[0].replace(' ','_').replace('\\','_').replace('/','_')+f'.{export_format}') | |
print(f"{'-'*10}") | |
print("[$] done!") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nessus Report Exporter
This Python script automates the process of exporting Nessus scan reports in HTML and Nessus formats. It leverages the Nessus API to trigger report generation and download the resulting files. The script prompts users to select specific scans or export all available ones. It also includes error handling and retry mechanisms for downloading reports. Designed for ease of use and flexibility in managing Nessus scan data.
Features
Usage
NESSUS_AK
andNESSUS_SK
are set, corresponding to the Nessus access key and secret key.Requirements
pip install requests
)Configuration
Ensure that the following environment variables are set:
NESSUS_AK
: Nessus access keyNESSUS_SK
: Nessus secret keyAdditionally, you may customize the following default settings in the script:
TEMPLATE_ID
: Nessus template ID for report generationCHUNK_SIZE
: Size of chunks for downloading filesOUT_DIR
: Output directory for saving exported reportsExample
License
This project is licensed under the MIT License - see the LICENSE file for details.