"""
Faraday Penetration Test IDE
Copyright (C) 2013 Infobyte LLC (http://www.infobytesec.com/)
See the file 'doc/LICENSE' for the license information
"""
import re
import xml.etree.ElementTree as ET
from faraday_plugins.plugins.plugin import PluginBase
__author__ = "Morgan Lemarechal"
__copyright__ = "Copyright 2014, Faraday Project"
__credits__ = ["Morgan Lemarechal"]
__license__ = ""
__version__ = "1.0.0"
__maintainer__ = "Morgan Lemarechal"
__email__ = "[email protected]"
__status__ = "Development"
class WcscanParser:
"""
The objective of this class is to parse an xml file generated by the wcscan tool.
TODO: Handle errors.
TODO: Test wcscan output version. Handle what happens if the parser doesn't support it.
TODO: Test cases.
@param wcscan_filepath A proper simple report generated by wcscan
"""
def __init__(self, output):
self.scaninfo = {}
self.result = {}
tree = ET.parse(output)
root = tree.getroot()
for scan in root.findall(".//scan"):
infos = {}
for info in scan.attrib:
infos[info] = scan.attrib[info]
self.scaninfo[scan.attrib['file']] = infos
item = {}
if scan.attrib['type'] == "phpini":
for carac in scan:
item[carac.tag] = [carac.text, carac.attrib['rec'], ""]
if scan.attrib['type'] == "webconfig":
id = 0
for carac in scan:
id += 1
item[id] = [carac.text, carac.attrib['rec'],
carac.attrib['option'], carac.tag]
self.result[scan.attrib['file']] = item
class WcscanPlugin(PluginBase):
"""
Example plugin to parse wcscan output.
"""
def __init__(self, *arg, **kwargs):
super().__init__(*arg, **kwargs)
self.id = "Wcscan"
self.name = "Wcscan XML Output Plugin"
self.plugin_version = "0.0.2"
self.version = "0.30"
self._completition = {
"": "wcscan [-h] [-r] [-host HOST] [-port PORT] [--xml XMLOUTPUT] [--version] files [files ...]",
"-h": "show this help message and exit",
"-r": "enable the recommendation mode",
"--host": "to give the IP address of the conf file owner",
"--port": "to give a associated port",
"--xml": "enabled the XML output in a specified file",
"--version": "Show program's version number and exit",
}
self.options = None
self._command_regex = re.compile(r'^(sudo wcscan|wcscan|\.\/wcscan)\s+.*?')
self._use_temp_file = True
self._temp_file_extension = "xml"
self.xml_arg_re = re.compile(r"^.*(--xml\s*[^\s]+).*$")
def parseOutputString(self, output):
"""
This method will discard the output the shell sends, it will read it from
the xml where it expects it to be present.
NOTE: if 'debug' is true then it is being run from a test case and the
output being sent is valid.
"""
parser = WcscanParser(output)
for file in parser.scaninfo:
host = parser.scaninfo[file]['host']
port = parser.scaninfo[file]['port']
h_id = self.createAndAddHost(host)
s_id = self.createAndAddServiceToHost(h_id, "http", protocol="tcp", ports=port)
for vuln in parser.result[file]:
if parser.scaninfo[file]['type'] == "phpini":
vuln_name = f"{parser.scaninfo[file]['file']}: {vuln}"
vuln_description = f"{vuln}: {str(parser.result[file][vuln][0])}\n{str(parser.result[file][vuln][1])}"
v_id = self.createAndAddVulnToService(h_id, s_id, vuln_name, desc=vuln_description, severity=0)
if parser.scaninfo[file]['type'] == "webconfig":
vuln_name = f"{parser.scaninfo[file]['file']}: {str(parser.result[file][vuln][3])}"
vuln_description = f"{str(parser.result[file][vuln][3])} : {str(parser.result[file][vuln][2])} = {str(parser.result[file][vuln][0])}\n{str(parser.result[file][vuln][1])}"
self.createAndAddVulnToService(h_id, s_id, vuln_name, desc=vuln_description, severity=0)
def processCommandString(self, username, current_path, command_string):
"""
Adds the parameter to get output to the command string that the
user has set.
"""
super().processCommandString(username, current_path, command_string)
arg_match = self.xml_arg_re.match(command_string)
if arg_match is None:
return f"{command_string} --xml {self._output_file_path}"
else:
return re.sub(arg_match.group(1), r"-xml %s" % self._output_file_path, command_string)
def createPlugin(*args, **kwargs):
return WcscanPlugin(*args, **kwargs)