Last active
November 17, 2025 06:17
-
-
Save dreizehnutters/e01d3a466617ef958a29fa4300036edc to your computer and use it in GitHub Desktop.
export nessus reports via CLI
This file contains hidden or 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
@fnickelsen, did you manage to get it working?