forked from ascemama/nucleusPlugins
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added support for trustwave pentest results
- Loading branch information
Showing
3 changed files
with
219 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
Script to pull the vulnerability report from a Trustwave automated pentest output, convert to Nucleus CSV, then post to Nucleus | ||
*** Populate the following variables in the script prior to using *** | ||
NUCLEUS_ROOT_URL | ||
NUCLEUS_API_KEY | ||
|
||
Required command line arguments: | ||
-i for input file path | ||
-o for output file in Nucleus format | ||
-# for project id |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
requests | ||
xmltodict |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
#!/usr/bin/python3.7 | ||
__author__ = "Nucleus Security" | ||
__license__ = "MIT License" | ||
__version__ = "0.1" | ||
|
||
#Used for writing to csv | ||
import csv | ||
# Used for arguments | ||
import argparse | ||
# Used to post the file to Nucleus | ||
import requests | ||
import xmltodict | ||
import json | ||
|
||
|
||
# Enter in the root URL of your Nucleus instance. | ||
# Example https://example.nucleussec.com | ||
NUCLEUS_ROOT_URL = "{Enter root URL of your Nucleus Instance here}" | ||
|
||
# Generate an API key through the Nucleus UI | ||
API_KEY = "{Enter your API key from Nucleus here}" | ||
|
||
|
||
def convert_to_json(inputPath): | ||
|
||
with open (inputPath) as xml_file: | ||
|
||
data_dict = xmltodict.parse(xml_file.read()) | ||
|
||
xml_file.close() | ||
|
||
json_data = json.dumps(data_dict) | ||
|
||
#print(json_data) | ||
|
||
return json_data | ||
|
||
|
||
|
||
def customParser(json_data, outputPath): | ||
|
||
# Create the csv file for writing | ||
with open(outputPath, 'w', newline='') as csvfile: | ||
|
||
csvwriter = csv.writer(csvfile, delimiter=',') | ||
|
||
csvwriter.writerow(['nucleus_import_version', 'host_name', 'ip_address', 'scan_type', 'scan_tool', 'finding_type', 'finding_cve', 'finding_number', 'finding_name', 'finding_severity', 'finding_description', 'finding_recommendation', 'finding_output', 'finding_result', 'finding_references']) | ||
|
||
# Try to parse the data. | ||
try: | ||
|
||
json_data = json.loads(json_data) | ||
|
||
#print(json_data) | ||
|
||
export = json_data['export'] | ||
|
||
findings = export['finding'] | ||
|
||
#print(findings) | ||
|
||
for finding in findings: | ||
|
||
csv_line = [] | ||
|
||
severity = finding['severity'] | ||
|
||
finding_name = finding['title'] | ||
|
||
asset_name = finding['assetName'] | ||
|
||
asset_ip = finding['ip'] | ||
|
||
finding_number = finding['title'] | ||
|
||
description = finding['description'] | ||
|
||
scan_date = finding['createdOn'] | ||
|
||
# Loop and fix references | ||
references = finding['references'] | ||
|
||
# Skipping references for now for speed | ||
#TODO: Parse the references into Nucleus format | ||
''' | ||
try: | ||
#reference_info = references.replace(",", ";") | ||
reference_info = references.replace(":", "-") | ||
reference_info = reference_info.replace(" ", "_") | ||
#Replace https:// | ||
reference_info = reference_info.replace("ps-", "ps:") | ||
except: | ||
pass | ||
#print(reference_info) | ||
''' | ||
|
||
|
||
solution = finding['remediation'] | ||
|
||
# Loop and fix finding output | ||
finding_output = finding['evidences']['evidence'] | ||
|
||
#print(finding_output) | ||
|
||
finding_output_data = '' | ||
|
||
try: | ||
|
||
for output in finding_output: | ||
|
||
title = output['title'] | ||
value = output['value'] | ||
output_type = output['type'] | ||
|
||
finding_output_data = output_type + ': ' + title + ' - ' + value | ||
|
||
#print(finding_output_data) | ||
|
||
except Exception as e: | ||
|
||
pass | ||
|
||
csv_line.extend(['1', asset_name, asset_ip, 'Host', 'Trustwave Pentest', 'Vuln', '', finding_number, finding_name, severity, description, solution, finding_output_data, 'Failed']) | ||
|
||
#print(csv_line) | ||
|
||
csvwriter.writerow(csv_line) | ||
|
||
|
||
|
||
except Exception as e: | ||
|
||
print("Error:", e) | ||
|
||
|
||
def get_args(): | ||
parser = argparse.ArgumentParser(description="For parsing whitesource files to be uploaded into Nucleus. If project ID is specified, will post the Nucleus supported file to Nucleus project.") | ||
|
||
# List arguments. Should only include input file and output file | ||
parser.add_argument('-i', '--inputfile', dest='inputFile', help="Path to trustwave xml file", required=True) | ||
parser.add_argument('-o', '--outputfile', dest='outputFile', help="Path to csv file output", required=True) | ||
parser.add_argument('-#', '--project_id', dest="project_id", help="This is the project ID of the Nucleus project to which you want to post. If not specified, this script will only parse the whitesource file for manual upload.") | ||
|
||
# Define the arguments globally for ease of use | ||
global args | ||
|
||
args = parser.parse_args() | ||
|
||
return args | ||
|
||
# Send the file to Nucleus | ||
def post_to_nucleus(outputfile): | ||
|
||
# Enter the ID of the project which you wish to post to here | ||
PROJECT_ID = args.project_id | ||
|
||
# open the file to send | ||
with open(outputfile.name, 'rb') as f: | ||
|
||
# Get the final Nucleus URL to post to | ||
nucleus_url = str(NUCLEUS_ROOT_URL+'/nucleus/api/projects/'+PROJECT_ID+'/scans') | ||
|
||
print("Posted to URL:", nucleus_url) | ||
|
||
# Send file with proper header. Keep note of the project ID you need to send | ||
file_upload = requests.post(nucleus_url, files={outputfile.name: f}, headers={'x-apikey': API_KEY}) | ||
|
||
# Print the response from the server | ||
print(file_upload.content) | ||
|
||
|
||
|
||
if __name__ == "__main__": | ||
|
||
# Get the arguments | ||
arguments = get_args() | ||
|
||
# Get the input file to parse | ||
inputPath = arguments.inputFile | ||
|
||
# Get the output file to save to | ||
outputPath = arguments.outputFile | ||
|
||
json_data = convert_to_json(inputPath) | ||
|
||
# Start the parsing and csv writing | ||
outputfile = customParser(json_data, outputPath) | ||
|
||
#print(outputfile.name) | ||
|
||
# If a project ID was specified, send the file to Nucleus | ||
if arguments.project_id: | ||
|
||
# Send the newly created csv file to Nucleus if project id was specified | ||
post_to_nucleus(outputfile) | ||
|
||
# If no project ID was specified, just parse file to Nucleus format for manual file upload | ||
else: | ||
|
||
pass |