dusty/scanners/dast/nikto/parser.py (59 lines of code) (raw):

#!/usr/bin/python3 # coding=utf-8 # pylint: disable=I0011,W1401,E0401,R0914,R0915,R0912,C0103 # Copyright 2019 getcarrier.io # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """ Nikto XML parser Original author: aaronweaver Modified for Dusty 1.0 by: arozumenko Ported to Dusty 2.0 by: LifeDJIK """ import re import hashlib from defusedxml import ElementTree as ET from dusty.tools import log, url, markdown from dusty.models.finding import DastFinding from dusty.constants import SEVERITIES def parse_findings(output_file, scanner): """ Parse findings (code from dusty 1.0) """ log.debug("Parsing findings") dupes = dict() # tree = ET.parse(output_file) root = tree.getroot() new_root = root.find("niktoscan") scan = new_root.find("scandetails") # for item in scan.findall("item"): # Title titleText = None description = item.find("description").text # Cut the title down to the first sentence sentences = re.split( r'(?<!\w\.\w.)(?<![A-Z][a-z]\.)(?<=\.|\?)\s', description) if sentences: titleText = sentences[0][:900] else: titleText = description[:900] # # Url ip = item.find("iplink").text # Remove the port numbers for 80/443 ip = ip.replace(":80", "") ip = ip.replace(":443", "") # # Description description = "\nHost: " + ip + "\n" + item.find("description").text dupe_key = hashlib.md5(description.encode("utf-8")).hexdigest() # if dupe_key in dupes: finding = dupes[dupe_key] if finding["description"]: finding["description"] = \ finding["description"] + "\nHost:" + ip + "\n" + description finding["endpoints"].append(ip) dupes[dupe_key] = finding else: dupes[dupe_key] = True finding = { "title": titleText, "description": description, "endpoints": list() } dupes[dupe_key] = finding finding["endpoints"].append(ip) # Create finding objects for item in dupes.values(): finding = DastFinding( title=item["title"], description=markdown.markdown_escape(item["description"]) ) finding.set_meta("tool", scanner.get_name()) finding.set_meta("severity", SEVERITIES[-1]) # Endpoints (for backwards compatibility) endpoints = list() for entry in item["endpoints"]: endpoint = url.parse_url(entry) if endpoint in endpoints: continue endpoints.append(endpoint) finding.set_meta("endpoints", endpoints) log.debug(f"Endpoints: {finding.get_meta('endpoints')}") # Done scanner.findings.append(finding)