Codebase list faraday-plugins / e02d6cf
New upstream version 1.8.0 Sophie Brun 1 year, 5 months ago
19 changed file(s) with 459 addition(s) and 23 deletion(s). Raw diff Collapse all Expand all
0 default_stages: [commit]
1 repos:
2 - repo: https://github.com/pre-commit/pre-commit-hooks
3 rev: v3.1.0
4 hooks:
5 - id: trailing-whitespace
6 - id: end-of-file-fixer
7 - id: check-json
8 - id: check-yaml
9 args: [ --unsafe ]
10 - id: debug-statements
11 - repo: https://gitlab.com/pycqa/flake8
12 rev: 3.8.3
13 hooks:
14 - id: flake8
15 additional_dependencies: [flake8-typing-imports==1.9.0]
16 - repo: https://github.com/ikamensh/flynt/
17 rev: '0.56'
18 hooks:
19 - id: flynt
20 args: [ -df ]
21 - repo: https://github.com/asottile/pyupgrade
22 rev: v2.29.0
23 hooks:
24 - id: pyupgrade
25 args: [ --py3-plus , --py36-plus]
0 [Add] Add invicti plugin
0 [Add] Add nessus_sc plugin
0 [FIX] Remove cvss_vector from refs in nexpose_full
0 Add new identifier_tag to nikto plugin
0 [FIX] Now plugins check if ref field is already a dictionary
0 [MOD] Improve grype plugin for dockers images and change report_belong_to method for
1 json plugins to check if json_keys is a list, in that case iterate the list and try if
2 any of them create a match.
0 Oct 26th, 2022
0 1.8.0 [Oct 26th, 2022]:
1 ---
2 * [Add] Add invicti plugin
3 * [Add] Add nessus_sc plugin
4 * [FIX] Remove cvss_vector from refs in nexpose_full
5 * Add new identifier_tag to nikto plugin
6 * [FIX] Now plugins check if ref field is already a dictionary
7 * [MOD] Improve grype plugin for dockers images and change report_belong_to method for
8 json plugins to check if json_keys is a list, in that case iterate the list and try if
9 any of them create a match.
10
011 1.7.0 [Sep 5th, 2022]:
112 ---
213 * Add CWE to PluginBase. The plugins that have this implemented are the following:
0 __version__ = '1.7.0'
0 __version__ = '1.8.0'
427427 """
428428 refs = []
429429 if ref:
430 refs = [{'name': url, 'type': 'other'} for url in ref]
430 for r in ref:
431 if isinstance(r, dict):
432 refs.append(r)
433 else:
434 refs.append({'name': r, 'type': 'other'})
431435 return refs
432436
433437 def createAndAddVulnToHost(self, host_id, name, desc="", ref=None,
739743 if super().report_belongs_to(**kwargs):
740744 if file_json_keys is None:
741745 file_json_keys = set()
742 match = self.json_keys.issubset(file_json_keys)
743 self.logger.debug(f"Json Keys Match: [{file_json_keys} =/in {self.json_keys}] -> {match}")
746 if isinstance(self.json_keys, list):
747 for jk in self.json_keys:
748 match = jk.issubset(file_json_keys)
749 self.logger.debug(f"Json Keys Match: [{file_json_keys} =/in {jk}] -> {match}")
750 if match:
751 break
752 else:
753 match = self.json_keys.issubset(file_json_keys)
754 self.logger.debug(f"Json Keys Match: [{file_json_keys} =/in {self.json_keys}] -> {match}")
744755 return match
745756
746757
2424 self._command_regex = re.compile(r'^grype\s+.*')
2525 self._use_temp_file = True
2626 self._temp_file_extension = "json"
27 self.json_keys = {"source", "matches", "descriptor"}
27 self.json_keys = [{"source", "matches", "descriptor"}, {"matches", "image"}]
2828
2929 def parseOutputString(self, output, debug=True):
3030 grype_json = json.loads(output)
31 if "userInput" in grype_json["source"]["target"]:
31 if "userInput" in grype_json.get("source", {"target": ""}).get("target"):
3232 name = grype_json["source"]["target"]["userInput"]
33 host_type = grype_json['source']['type']
34 elif "tags" in grype_json.get("image", {}):
35 name = " ".join(grype_json["image"]["tags"])
36 host_type = "Docker Image"
3337 else:
3438 name = grype_json["source"]["target"]
35 host_id = self.createAndAddHost(name, description=f"Type: {grype_json['source']['type']}")
39 host_type = grype_json['source']['type']
40 host_id = self.createAndAddHost(name, description=f"Type: {host_type}")
3641 for match in grype_json['matches']:
3742 name = match.get('vulnerability').get('id')
3843 cve = name
3944 references = []
40 if match["relatedVulnerabilities"]:
45 if match.get("relatedVulnerabilities"):
4146 description = match["relatedVulnerabilities"][0].get('description')
4247 references.append(match["relatedVulnerabilities"][0]["dataSource"])
4348 related_vuln = match["relatedVulnerabilities"][0]
4449 severity = related_vuln["severity"].lower().replace("negligible", "info")
45 for url in related_vuln["urls"]:
46 references.append(url)
50 if related_vuln.get("links"):
51 for url in related_vuln["links"]:
52 references.append(url)
53 else:
54 for url in related_vuln["urls"]:
55 references.append(url)
4756 else:
48 description = match.get('vulnerability').get('description')
57 description = match.get('vulnerability').get('description', "Issues provided no description")
4958 severity = match.get('vulnerability').get('severity').lower().replace("negligible", "info")
50 for url in match.get('vulnerability').get('urls'):
51 references.append(url)
59 if match.get('vulnerability').get("links"):
60 for url in match.get('vulnerability')["links"]:
61 references.append(url)
62 else:
63 for url in match.get('vulnerability')["urls"]:
64 references.append(url)
5265 if not match['artifact'].get('metadata'):
5366 data = f"Artifact: {match['artifact']['name']}" \
5467 f"Version: {match['artifact']['version']} " \
6073 f"Type: {match['artifact']['type']}"
6174 elif "VirtualPath" in match['artifact']['metadata']:
6275 data = f"Artifact: {match['artifact']['name']} [{match['artifact']['metadata']['VirtualPath']}] " \
76 f"Version: {match['artifact']['version']} " \
77 f"Type: {match['artifact']['type']}"
78 else:
79 data = f"Artifact: {match['artifact']['name']}" \
6380 f"Version: {match['artifact']['version']} " \
6481 f"Type: {match['artifact']['type']}"
6582 self.createAndAddVulnToHost(host_id,
0 from typing import List
1
2
3 class Cvss3:
4 def __init__(self, node):
5 self.node = node
6
7 @property
8 def vector(self) -> str:
9 return self.node.find('vector').text
10
11
12 class Reference:
13 def __init__(self, node):
14 self.node = node
15
16 @property
17 def owasp(self) -> str:
18 return self.node.find('owasp').text
19
20 @property
21 def wasc(self) -> str:
22 return self.node.find('wasc').text
23
24 @property
25 def cwe(self) -> str:
26 return self.node.find('cwe').text
27
28 @property
29 def capec(self) -> str:
30 return self.node.find('capec').text
31
32 @property
33 def pci32(self) -> str:
34 return self.node.find('pci32').text
35
36 @property
37 def hipaa(self) -> str:
38 return self.node.find('hipaa').text
39
40 @property
41 def owasppc(self) -> str:
42 return self.node.find('owasppc').text
43
44 @property
45 def cvss3(self) -> Cvss3:
46 return Cvss3(self.node.find("cvss31"))
47
48
49 class Request:
50 def __init__(self, node):
51 self.node = node
52
53 @property
54 def method(self) -> str:
55 return self.node.find("method").text
56
57 @property
58 def content(self) -> str:
59 return self.node.find("content").text
60
61
62 class Response:
63 def __init__(self, node):
64 self.node = node
65
66 @property
67 def content(self) -> str:
68 return self.node.find("content").text
69
70
71 class Vulnerability:
72 def __init__(self, node):
73 self.node = node
74
75 @property
76 def look_id(self) -> str:
77 return self.node.find('LookupId').text
78
79 @property
80 def url(self) -> str:
81 return self.node.find("url").text
82
83 @property
84 def name(self) -> str:
85 return self.node.find('name').text
86
87 @property
88 def severity(self) -> str:
89 return self.node.find('severity').text
90
91 @property
92 def confirmed(self) -> str:
93 return self.node.find('confirmed').text
94
95 @property
96 def description(self) -> str:
97 return self.node.find('description').text
98
99 @property
100 def http_request(self) -> Request:
101 return Request(self.node.find("http-request"))
102
103 @property
104 def http_response(self) -> Response:
105 return Response(self.node.find("http-response"))
106
107 @property
108 def impact(self) -> str:
109 return self.node.find("impact").text
110
111 @property
112 def remedial_actions(self) -> str:
113 return self.node.find("remedial-actions").text
114
115 @property
116 def remedial_procedure(self) -> str:
117 return self.node.find("remedial-procedure").text
118
119 @property
120 def classification(self) -> Reference:
121 return Reference(self.node.find("classification"))
122
123
124 class Target:
125 def __init__(self, node):
126 self.node = node
127
128 @property
129 def scan_id(self) -> str:
130 return self.node.find("scan-id").text
131
132 @property
133 def url(self) -> str:
134 return self.node.find("url").text
135
136
137 class Invicti:
138 def __init__(self, node):
139 self.node = node
140
141 @property
142 def target(self) -> Target:
143 return Target(self.node.find('target'))
144
145 @property
146 def vulnerabilities(self) -> List[Vulnerability]:
147 return [Vulnerability(i) for i in self.node.findall('vulnerabilities/vulnerability')]
0 """
1 Faraday Penetration Test IDE
2 Copyright (C) 2013 Infobyte LLC (http://www.infobytesec.com/)
3 See the file 'doc/LICENSE' for the license information
4
5 """
6 from urllib.parse import urlsplit
7 from bs4 import BeautifulSoup
8 from lxml import etree
9
10 from faraday_plugins.plugins.plugin import PluginXMLFormat
11 from faraday_plugins.plugins.repo.invicti.DTO import Invicti
12
13 __author__ = "Gonzalo Martinez"
14 __copyright__ = "Copyright (c) 2013, Infobyte LLC"
15 __credits__ = ["Gonzalo Martinez"]
16 __version__ = "1.0.0"
17 __maintainer__ = "Gonzalo Martinez"
18 __email__ = "[email protected]"
19 __status__ = "Development"
20
21
22 class InvictiXmlParser:
23 """
24 The objective of this class is to parse a xml file generated by
25 the acunetix tool.
26
27 @param invicti_xml_filepath A proper xml generated by acunetix
28 """
29
30 def __init__(self, xml_output):
31
32 tree = self.parse_xml(xml_output)
33 self.invicti = Invicti(tree)
34
35 @staticmethod
36 def parse_xml(xml_output):
37 """
38 Open and parse an xml file.
39
40 TODO: Write custom parser to just read the nodes that we need instead
41 of reading the whole file.
42
43 @return xml_tree An xml tree instance. None if error.
44 """
45
46 try:
47 parser = etree.XMLParser(recover=True)
48 tree = etree.fromstring(xml_output, parser=parser)
49 except SyntaxError as err:
50 print(f"SyntaxError: {err}. {xml_output}")
51 return None
52
53 return tree
54
55
56 class InvictiPlugin(PluginXMLFormat):
57 """
58 Example plugin to parse invicti output.
59 """
60
61 def __init__(self, *arg, **kwargs):
62 super().__init__(*arg, **kwargs)
63 self.identifier_tag = "invicti-enterprise"
64 self.id = "Invicti"
65 self.name = "Invicti XML Output Plugin"
66 self.plugin_version = "1.0.0"
67 self.version = "9"
68 self.framework_version = "1.0.0"
69 self.options = None
70 self._current_output = None
71 self.target = None
72
73 def parseOutputString(self, output):
74 """
75 This method will discard the output the shell sends, it will read it
76 from the xml where it expects it to be present.
77
78 NOTE: if 'debug' is true then it is being run from a test case and the
79 output being sent is valid.
80 """
81 parser = InvictiXmlParser(output)
82 url = urlsplit(parser.invicti.target.url)
83 ip = self.resolve_hostname(url.netloc)
84 h_id = self.createAndAddHost(ip)
85 s_id = self.createAndAddServiceToHost(h_id, url.scheme, ports=433)
86 for vulnerability in parser.invicti.vulnerabilities:
87 vuln = {"name": vulnerability.name, "severity": vulnerability.severity,
88 "confirmed": vulnerability.confirmed,
89 "desc": BeautifulSoup(vulnerability.description, features="lxml").text,
90 "path": vulnerability.url.replace(parser.invicti.target.url, ""),
91 "external_id": vulnerability.look_id,
92 "resolution": BeautifulSoup(vulnerability.remedial_procedure, features="lxml").text}
93 if vulnerability.classification:
94 references = []
95 if vulnerability.classification.owasp:
96 references.append("OWASP" + vulnerability.classification.owasp)
97 if vulnerability.classification.wasc:
98 references.append("WASC" + vulnerability.classification.wasc)
99 if vulnerability.classification.cwe:
100 vuln["cwe"] = "CWE-" + vulnerability.classification.cwe
101 if vulnerability.classification.capec:
102 references.append("CAPEC" + vulnerability.classification.capec)
103 if vulnerability.classification.pci32:
104 references.append("PCI32" + vulnerability.classification.pci32)
105 if vulnerability.classification.hipaa:
106 references.append("HIPAA" + vulnerability.classification.hipaa)
107 if vulnerability.classification.owasppc:
108 references.append("OWASPPC" + vulnerability.classification.owasppc)
109 if vulnerability.classification.cvss3.node is not None:
110 vuln["cvss3"] = {"vector_string": vulnerability.classification.cvss3.vector}
111 vuln["ref"] = references
112 if vulnerability.http_response.node is not None:
113 vuln["response"] = vulnerability.http_response.content
114 if vulnerability.http_request.node is not None:
115 vuln["request"] = vulnerability.http_request.content
116 self.createAndAddVulnWebToService(h_id, s_id, **vuln)
117
118
119 def createPlugin(*args, **kwargs):
120 return InvictiPlugin(*args, **kwargs)
0 """
1 Faraday Penetration Test IDE
2 Copyright (C) 2017 Infobyte LLC (http://www.infobytesec.com/)
3 See the file 'doc/LICENSE' for the license information
4
5 """
0 """
1 Faraday Penetration Test IDE
2 Copyright (C) 2013 Infobyte LLC (http://www.infobytesec.com/)
3 See the file 'doc/LICENSE' for the license information
4
5 """
6
7 from faraday_plugins.plugins.plugin import PluginCSVFormat
8 import csv
9 import io
10
11
12 __author__ = "Gonzalo Martinez"
13 __copyright__ = "Copyright (c) 2019, Infobyte LLC"
14 __credits__ = ["Gonzalo Martinez"]
15 __license__ = ""
16 __version__ = "1.0.0"
17 __maintainer__ = "Gonzalo Martinez"
18 __email__ = "[email protected]"
19 __status__ = "Development"
20
21
22 class NessusScPlugin(PluginCSVFormat):
23 """
24 Example plugin to parse Nessus Sc output.
25 """
26
27 def __init__(self, *arg, **kwargs):
28 super().__init__(*arg, **kwargs)
29 self.csv_headers = [{'Plugin', 'Plugin Name'}]
30 self.id = "Nessus_sc"
31 self.name = "Nessus Sc Output Plugin"
32 self.plugin_version = "1.0.0"
33 self.version = "1.0.0"
34 self.framework_version = "1.0.0"
35
36 def parseOutputString(self, output):
37 try:
38 reader = csv.DictReader(io.StringIO(output))
39 except:
40 print("Error parser output")
41 return None
42
43 for row in reader:
44 ip = row['IP Address']
45 hostname = row['DNS Name']
46 h_id = self.createAndAddHost(name=ip, hostnames=hostname)
47 protocol = row['Protocol']
48 port = row['Port']
49 s_id = self.createAndAddServiceToHost(h_id, name=port, protocol=protocol, ports=port, status="open")
50 name = row['Plugin Name']
51 severity = row['Severity']
52 description = row['Description']
53 vuln = {"name": name, "severity": severity, "desc": description}
54 solution = row['Solution']
55 if solution:
56 vuln["resolution"] = solution
57 cvss3_vector = row['CVSS V3 Vector']
58 if cvss3_vector:
59 if not cvss3_vector.startswith("CVSS:3.0/"):
60 cvss3_vector = "CVSS:3.0/"+cvss3_vector
61 vuln["cvss3"] = {"vector_string": cvss3_vector}
62 cvss2_vector = row['CVSS V2 Vector']
63 if cvss2_vector:
64 vuln["cvss2"] = {"vector_string": cvss2_vector}
65 external_ref = row["See Also"]
66 cross_ref = row["Cross References"]
67 references = []
68 if external_ref:
69 references.append(external_ref)
70 if cross_ref:
71 references.append(cross_ref)
72 vuln["ref"] = references
73 cve = row['CVE']
74 if cve:
75 vuln["cve"] = cve
76 self.createAndAddVulnToService(h_id, s_id, **vuln)
77
78
79 def createPlugin(*args, **kwargs):
80 return NessusScPlugin(*args, **kwargs)
140140 vuln = {
141141 'desc': "",
142142 'name': vulnDef.get('title'),
143 'refs': ["vector: " + vector, vid],
143 'refs': [],
144144 'resolution': "",
145145 'severity': "",
146146 'tags': list(),
171171 vuln['refs'].append(nameMalware)
172172 if item.tag == 'references':
173173 for ref in list(item):
174 if ref.text:
175 rf = ref.text.strip()
176 check = CVE_regex.search(rf.upper())
177 if check:
178 vuln["CVE"].append(check.group())
179 else:
180 vuln['refs'].append(rf)
174 if not ref.text:
175 continue
176 source = ""
177 if "source" in ref.attrib:
178 source = ref.attrib['source'] + ": "
179 rf = ref.text.strip()
180 check = CVE_regex.search(rf.upper())
181 if check:
182 vuln["CVE"].append(check.group())
183 else:
184 if rf.isnumeric():
185 rf = source + rf
186 vuln['refs'].append(rf)
181187 if item.tag == 'solution':
182188 for htmlType in list(item):
183189 vuln['resolution'] += self.parse_html_type(htmlType)
9999 self.node = item_node
100100
101101 self.osvdbid = [
102 "OSVDB-ID: " + self.node.get('osvdbid')] if self.node.get('osvdbid') != "0" else []
102 "OSVDB-ID: " + self.node.get('osvdbid')] if self.node.get('osvdbid', "0") != "0" else []
103103
104104 self.namelink = self.get_text_from_subnode('namelink')
105105 self.iplink = self.get_text_from_subnode('iplink')
206206
207207 def __init__(self, *arg, **kwargs):
208208 super().__init__(*arg, **kwargs)
209 self.identifier_tag = "niktoscan"
209 self.identifier_tag = ["niktoscan", "niktoscans"]
210210 self.id = "Nikto"
211211 self.name = "Nikto XML Output Plugin"
212212 self.plugin_version = "0.0.2"