diff --git a/kube-hunter.py b/kube-hunter.py index 107729a..d9ab4d1 100755 --- a/kube-hunter.py +++ b/kube-hunter.py @@ -20,7 +20,7 @@ parser.add_argument('--mapping', action="store_true", help="outputs only a mappi parser.add_argument('--remote', nargs='+', metavar="HOST", default=list(), help="one or more remote ip/dns to hunt") parser.add_argument('--active', action="store_true", help="enables active hunting") parser.add_argument('--log', type=str, metavar="LOGLEVEL", default='INFO', help="set log level, options are: debug, info, warn, none") -parser.add_argument('--report', type=str, default='plain', help="set report type, options are: plain, yaml") +parser.add_argument('--report', type=str, default='plain', help="set report type, options are: plain, yaml, json") import plugins @@ -35,9 +35,12 @@ if config.log.lower() != "none": from src.modules.report.plain import PlainReporter from src.modules.report.yaml import YAMLReporter +from src.modules.report.json import JSONReporter if config.report.lower() == "yaml": config.reporter = YAMLReporter() +elif config.report.lower() == "json": + config.reporter = JSONReporter() else: config.reporter = PlainReporter() diff --git a/src/modules/report/base.py b/src/modules/report/base.py new file mode 100644 index 0000000..b8986a0 --- /dev/null +++ b/src/modules/report/base.py @@ -0,0 +1,34 @@ +from collector import services, vulnerabilities, services_lock, vulnerabilities_lock + +class BaseReporter(object): + def get_nodes(self): + nodes = list() + node_locations = set() + services_lock.acquire() + for service in services: + node_location = str(service.host) + if node_location not in node_locations: + nodes.append({"type": "Node/Master", "location": str(service.host)}) + node_locations.add(node_location) + services_lock.release() + return nodes + + def get_services(self): + services_lock.acquire() + services_data = [{"service": service.get_name(), + "location": "{}:{}{}".format(service.host, service.port, service.get_path()), + "description": service.explain()} + for service in services] + services_lock.release() + return services_data + + def get_vulnerabilities(self): + vulnerabilities_lock.acquire() + vulnerabilities_data = [{"location": "{}:{}".format(vuln.host, vuln.port) if vuln.host else "", + "category": vuln.category.name, + "vulnerability": vuln.get_name(), + "description": vuln.explain(), + "evidence": str(vuln.evidence)} + for vuln in vulnerabilities] + vulnerabilities_lock.release() + return vulnerabilities_data diff --git a/src/modules/report/json.py b/src/modules/report/json.py new file mode 100644 index 0000000..ab2ac74 --- /dev/null +++ b/src/modules/report/json.py @@ -0,0 +1,13 @@ +import StringIO +import json +from base import BaseReporter + +class JSONReporter(BaseReporter): + def get_report(self): + report = { + "nodes": self.get_nodes(), + "services": self.get_services(), + "vulnerabilities": self.get_vulnerabilities(), + "vulnerability_count": self.get_count() + } + return json.dumps(report) diff --git a/src/modules/report/json_reporter.py b/src/modules/report/json_reporter.py new file mode 100644 index 0000000..0a1dde9 --- /dev/null +++ b/src/modules/report/json_reporter.py @@ -0,0 +1,12 @@ +import StringIO +import json +from base import BaseReporter + +class JSONReporter(BaseReporter): + def get_report(self): + report = { + "nodes": self.get_nodes(), + "services": self.get_services(), + "vulnerabilities": self.get_vulnerabilities() + } + return json.dumps(report) diff --git a/src/modules/report/yaml.py b/src/modules/report/yaml.py index 1ffcf58..2060fed 100644 --- a/src/modules/report/yaml.py +++ b/src/modules/report/yaml.py @@ -1,49 +1,16 @@ import StringIO from ruamel.yaml import YAML +from base import BaseReporter -from collector import services, vulnerabilities, services_lock, vulnerabilities_lock - -class YAMLReporter(object): +class YAMLReporter(BaseReporter): def get_report(self): yaml = YAML() report = { "nodes": self.get_nodes(), "services": self.get_services(), - "vulnerabilities": self.get_vulenrabilities() + "vulnerabilities": self.get_vulnerabilities() } output = StringIO.StringIO() yaml.dump(report, output) - return output.getvalue() - - def get_nodes(self): - nodes = list() - node_locations = set() - services_lock.acquire() - for service in services: - node_location = str(service.host) - if node_location not in node_locations: - nodes.append({"type": "Node/Master", "location": str(service.host)}) - node_locations.add(node_location) - services_lock.release() - return nodes - - def get_services(self): - services_lock.acquire() - services_data = [{"service": service.get_name(), - "location": "{}:{}{}".format(service.host, service.port, service.get_path()), - "description": service.explain()} - for service in services] - services_lock.release() - return services_data - - def get_vulenrabilities(self): - vulnerabilities_lock.acquire() - vulnerabilities_data = [{"location": "{}:{}".format(vuln.host, vuln.port) if vuln.host else "", - "category": vuln.category.name, - "vulnerability": vuln.get_name(), - "description": vuln.explain(), - "evidence": str(vuln.evidence)} - for vuln in vulnerabilities] - vulnerabilities_lock.release() - return vulnerabilities_data + return output.getvalue() \ No newline at end of file