Codebase list faraday-plugins / 0e52bfd
New upstream version 1.5.2 Sophie Brun 2 years ago
22 changed file(s) with 748 addition(s) and 187 deletion(s). Raw diff Collapse all Expand all
0 cwe, capec, references, tags, impact, resolution, easeofresolution
0 Jul 27th, 2021
0 [FIX] Fix improt of CSV with big fields
0 Fix sslyze json bug with port
0 Only show report name in command data
0 Aug 9th, 2021
0 add new structure acunetix
0 1.5.2 [Aug 9th, 2021]:
1 ---
2 * add new structure acunetix
3
4 1.5.1 [Jul 27th, 2021]:
5 ---
6 * cwe, capec, references, tags, impact, resolution, easeofresolution
7 * add os openvas
8 * [FIX] Fix improt of CSV with big fields
9 * Fix sslyze json bug with port
10 * Only show report name in command data
11
012 1.5.0 [Jun 28th, 2021]:
113 ---
214 * Add Nipper Plugin
0 __version__ = '1.5.0'
0 __version__ = '1.5.2'
55 import shlex
66 import subprocess
77 import sys
8 from pathlib import Path
89
910 import click
1011 from tabulate import tabulate
7980 if not plugin:
8081 click.echo(click.style(f"Failed to detect report: {report_file}", fg="red"), err=True)
8182 return
82 plugin.processReport(report_file, getpass.getuser())
83 plugin.processReport(Path(report_file), getpass.getuser())
8384 if summary:
8485 click.echo(json.dumps(plugin.get_summary(), indent=4))
8586 else:
1313 import zipfile
1414 from collections import defaultdict
1515 from datetime import datetime
16 from pathlib import Path
1617
1718 import pytz
1819 import simplejson as json
276277 params = " ".join(command_string.split()[2:])
277278 else:
278279 params = " ".join(command_string.split()[1:])
279 self.vulns_data["command"]["params"] = params
280 self.vulns_data["command"]["params"] = params if not self.ignore_info else f"{params} (Info ignored)"
280281 self.vulns_data["command"]["user"] = username
281282 self.vulns_data["command"]["import_source"] = "shell"
282283 if self._use_temp_file:
299300
300301 def processOutput(self, command_output):
301302 if self.has_custom_output():
302 self._parse_filename(self.get_custom_file_path())
303 self._parse_filename(Path(self.get_custom_file_path()))
303304 else:
304305 self.parseOutputString(command_output)
305306
306 def _parse_filename(self, filename):
307 with open(filename, **self.open_options) as output:
307 def _parse_filename(self, filename: Path):
308 with filename.open(**self.open_options) as output:
308309 self.parseOutputString(output.read())
309310 if self._delete_temp_file:
310311 try:
311 if os.path.isfile(filename):
312 if filename.is_file():
312313 os.remove(filename)
313 elif os.path.isdir(filename):
314 elif filename.is_dir():
314315 shutil.rmtree(filename)
315316 except Exception as e:
316317 self.logger.error("Error on delete file: (%s) [%s]", filename, e)
317318
318 def processReport(self, filepath, user="faraday"):
319 if os.path.isfile(filepath):
320 self.vulns_data["command"]["params"] = filepath if not self.ignore_info else f"{filepath} (Info ignored)"
319 def processReport(self, filepath: Path, user="faraday"):
320 if type(filepath) == str: # TODO workaround for compatibility, remove in the future
321 filepath = Path(filepath)
322 if filepath.is_file():
323 self.vulns_data["command"]["params"] = filepath.name if not self.ignore_info else f"{filepath.name} (Info ignored)"
321324 self.vulns_data["command"]["user"] = user
322325 self.vulns_data["command"]["import_source"] = "report"
323326 self._parse_filename(filepath)
565568 def processOutput(self, term_output):
566569 # we discard the term_output since it's not necessary
567570 # for this type of plugins
568 self.processReport(self._output_file_path)
571 self.processReport(Path(self._output_file_path))
569572
570573
571574 class PluginByExtension(PluginBase):
0 from typing import List
1
2
3 class Technicaldetails:
4 def __init__(self, node):
5 self.node = node
6
7 @property
8 def request(self) -> str:
9 if not self.node:
10 return ''
11 return self.node.findtext('Request', '')
12
13 @property
14 def response(self) -> str:
15 if not self.node:
16 return ''
17 return self.node.findtext('Response', '')
18
19
20 class Cwe:
21 def __init__(self, node):
22 self.node = node
23
24 @property
25 def id_attr(self) -> str:
26 return self.node.findtext('id', '')
27
28 @property
29 def text(self) -> str:
30 return self.node.findtext('#text', '')
31
32
33 class Cwelist:
34 def __init__(self, node):
35 self.node = node
36
37 @property
38 def cwe(self) -> Cwe:
39 return Cwe(self.node.find('CWE'))
40
41
42 class Cvss:
43 def __init__(self, node):
44 self.node = node
45
46 @property
47 def descriptor(self) -> str:
48 return self.node.findtext('Descriptor', '')
49
50 @property
51 def score(self) -> str:
52 return self.node.findtext('Score', '')
53
54 @property
55 def av(self) -> str:
56 return self.node.findtext('AV', '')
57
58 @property
59 def ac(self) -> str:
60 return self.node.findtext('AC', '')
61
62 @property
63 def au(self) -> str:
64 return self.node.findtext('Au', '')
65
66 @property
67 def c(self) -> str:
68 return self.node.findtext('C', '')
69
70 @property
71 def i(self) -> str:
72 return self.node.findtext('I', '')
73
74 @property
75 def a(self) -> str:
76 return self.node.findtext('A', '')
77
78 @property
79 def e(self):
80 return self.node.find('E')
81
82 @property
83 def rl(self):
84 return self.node.find('RL')
85
86 @property
87 def rc(self):
88 return self.node.find('RC')
89
90
91 class Cvss3:
92 def __init__(self, node):
93 self.node = node
94
95 @property
96 def descriptor(self) -> str:
97 return self.node.findtext('Descriptor', '')
98
99 @property
100 def score(self) -> str:
101 return self.node.findtext('Score', '')
102
103 @property
104 def tempscore(self):
105 return self.node.find('TempScore')
106
107 @property
108 def envscore(self):
109 return self.node.find('EnvScore')
110
111 @property
112 def av(self) -> str:
113 return self.node.find('AV', '')
114
115 @property
116 def ac(self) -> str:
117 return self.node.find('AC', '')
118
119 @property
120 def pr(self) -> str:
121 return self.node.find('PR', '')
122
123 @property
124 def ui(self) -> str:
125 return self.node.find('UI', '')
126
127 @property
128 def s(self) -> str:
129 return self.node.find('S', '')
130
131 @property
132 def c(self) -> str:
133 return self.node.find('C', '')
134
135 @property
136 def i(self) -> str:
137 return self.node.findtext('I', '')
138
139 @property
140 def a(self) -> str:
141 return self.node.findtext('A', '')
142
143 @property
144 def e(self):
145 return self.node.find('E')
146
147 @property
148 def rl(self):
149 return self.node.find('RL')
150
151 @property
152 def rc(self):
153 return self.node.find('RC')
154
155
156 class Reference:
157 def __init__(self, node):
158 self.node = node
159
160 @property
161 def database(self) -> str:
162 return self.node.findtext('Database', '')
163
164 @property
165 def url(self) -> str:
166 return self.node.findtext('URL', '')
167
168
169 class References:
170 def __init__(self, node):
171 self.node = node
172
173 @property
174 def reference(self) -> List[Reference]:
175 return [Reference(i) for i in self.node.findall('Reference', [])]
176
177
178 class Reportitem:
179 def __init__(self, node):
180 self.node = node
181
182 @property
183 def id_attr(self) -> str:
184 return self.node.findtext('id', '')
185
186 @property
187 def color_attr(self) -> str:
188 return self.node.findtext('color', '')
189
190 @property
191 def name(self) -> str:
192 return self.node.findtext('Name', '')
193
194 @property
195 def modulename(self) -> str:
196 return self.node.findtext('ModuleName', '')
197
198 @property
199 def details(self) -> str:
200 return self.node.findtext('Details', '')
201
202 @property
203 def affects(self) -> str:
204 return self.node.findtext('Affects', '')
205
206 @property
207 def parameter(self) -> str:
208 return self.node.findtext('Parameter')
209
210 @property
211 def aop_sourcefile(self):
212 return self.node.find('AOP_SourceFile')
213
214 @property
215 def aop_sourceline(self):
216 return self.node.find('AOP_SourceLine')
217
218 @property
219 def aop_additional(self):
220 return self.node.find('AOP_Additional')
221
222 @property
223 def isfalsepositive(self):
224 return self.node.find('IsFalsePositive')
225
226 @property
227 def severity(self) -> str:
228 return self.node.findtext('Severity', '')
229
230 @property
231 def type(self) -> str:
232 return self.node.findtext('Type', '')
233
234 @property
235 def impact(self) -> str:
236 return self.node.findtext('Impact', '')
237
238 @property
239 def description(self) -> str:
240 return self.node.findtext('Description', '')
241
242 @property
243 def recommendation(self) -> str:
244 return self.node.findtext('Recommendation', '')
245
246 @property
247 def technicaldetails(self) -> Technicaldetails:
248 return Technicaldetails(self.node.find('TechnicalDetails'))
249
250 @property
251 def cwelist(self) -> Cwelist:
252 return Cwelist(self.node.find('CWEList'))
253
254 @property
255 def cvelist(self):
256 return self.node.find('CVEList')
257
258 @property
259 def cvss(self) -> Cvss:
260 return Cvss(self.node.find('cvss'))
261
262 @property
263 def cvss3(self) -> Cvss3:
264 return Cvss3(self.node.find('cvss3'))
265
266 @property
267 def references(self) -> References:
268 return References(self.node.find('References'))
269
270
271 class Reportitems:
272 def __init__(self, node):
273 self.node = node
274
275 @property
276 def reportitem(self) -> List[Reportitem]:
277 return [Reportitem(i) for i in self.node.findall('ReportItem', [])]
278
279
280 class Crawler:
281 def __init__(self, node):
282 self.node = node
283
284 @property
285 def start_url_attr(self) -> str:
286 return self.node.get('StartUrl', '')
287
288
289 class Scan:
290 def __init__(self, node):
291 self.node = node
292
293 @property
294 def reportitems(self) -> Reportitems:
295 return Reportitems(self.node.find('ReportItems'))
296
297 @property
298 def start_url(self) -> str:
299 return self.node.findtext("StartURL", "")
300
301 @property
302 def crawler(self) -> Crawler:
303 return Crawler(self.node.find('Crawler'))
304
305 @property
306 def os(self) -> str:
307 if not self.node.findtext("Os", "unknown"):
308 return "unknown"
309 return self.node.findtext("Os", "unknown")
310
311 @property
312 def banner(self) -> str:
313 if not self.node.findtext('Banner'):
314 return None
315 return self.node.findtext("Banner")
316
317 @property
318 def start_url_new(self) -> str:
319 return self.node.findtext("", "")
320
321
322 class Acunetix:
323 def __init__(self, node):
324 self.node = node
325
326 @property
327 def exportedon_attr(self) -> str:
328 return self.node.get('ExportedOn')
329
330 @property
331 def scan(self) -> List[Scan]:
332 return [Scan(i) for i in self.node.findall('Scan', [])]
33 See the file 'doc/LICENSE' for the license information
44
55 """
6 from re import findall
67 from urllib.parse import urlsplit
78
89 from lxml import etree
910
1011 from faraday_plugins.plugins.plugin import PluginXMLFormat
1112 from faraday_plugins.plugins.plugins_utils import resolve_hostname
13 from faraday_plugins.plugins.repo.acunetix.DTO import Acunetix, Scan
1214
1315 __author__ = "Francisco Amato"
1416 __copyright__ = "Copyright (c) 2013, Infobyte LLC"
3335 """
3436
3537 def __init__(self, xml_output):
38
3639 tree = self.parse_xml(xml_output)
37 if len(tree):
38 self.sites = list(self.get_items(tree))
39 else:
40 self.sites = []
40 self.acunetix = Acunetix(tree)
4141
4242 @staticmethod
4343 def parse_xml(xml_output):
4949
5050 @return xml_tree An xml tree instance. None if error.
5151 """
52
5253 try:
5354 parser = etree.XMLParser(recover=True)
5455 tree = etree.fromstring(xml_output, parser=parser)
5758 return None
5859
5960 return tree
60
61 @staticmethod
62 def get_items(tree):
63 """
64 @return items A list of Host instances
65 """
66
67 for node in tree.findall('Scan'):
68 yield Site(node)
69
70
71 def get_attrib_from_subnode(xml_node, subnode_xpath_expr, attrib_name):
72 """
73 Finds a subnode in the item node and the retrieves a value from it
74
75 @return An attribute value
76 """
77
78 node = xml_node.find(subnode_xpath_expr)
79
80 if node is not None:
81 return node.get(attrib_name)
82
83 return None
84
85
86 class Site:
87
88 def __init__(self, item_node):
89 self.node = item_node
90 url_data = self.get_url(self.node)
91
92 self.protocol = url_data.scheme
93 if url_data.hostname:
94 self.host = url_data.hostname
95 else:
96 self.host = None
97 # Use the port in the URL if it is defined, or 80 or 443 by default
98 self.port = url_data.port or (443 if url_data.scheme == "https" else 80)
99 self.ip = resolve_hostname(self.host)
100 self.os = self.get_text_from_subnode('Os')
101 self.banner = self.get_text_from_subnode('Banner')
102 self.items = []
103 for alert in self.node.findall('ReportItems/ReportItem'):
104 self.items.append(Item(alert))
105
106 def get_text_from_subnode(self, subnode_xpath_expr):
107 """
108 Finds a subnode in the host node and the retrieves a value from it.
109
110 @return An attribute value
111 """
112 sub_node = self.node.find(subnode_xpath_expr)
113 if sub_node is not None:
114 return sub_node.text
115
116 return None
117
118 def get_url(self, node):
119 url = self.get_text_from_subnode('StartURL')
120 if not url.startswith('http'):
121 url = f'http://{url}'
122 url_data = urlsplit(url)
123 if not url_data.scheme:
124 # Getting url from subnode 'Crawler'
125 url_aux = get_attrib_from_subnode(node, 'Crawler', 'StartUrl')
126 url_data = urlsplit(url_aux)
127
128 return url_data
129
130
131 class Item:
132 """
133 An abstract representation of a Item
134
135
136 @param item_node A item_node taken from an acunetix xml tree
137 """
138
139 def __init__(self, item_node):
140 self.node = item_node
141 self.name = self.get_text_from_subnode('Name')
142 self.severity = self.get_text_from_subnode('Severity')
143 self.request = self.get_text_from_subnode('TechnicalDetails/Request')
144 self.response = self.get_text_from_subnode('TechnicalDetails/Response')
145 self.parameter = self.get_text_from_subnode('Parameter')
146 self.uri = self.get_text_from_subnode('Affects')
147
148 if self.get_text_from_subnode('Description'):
149 self.desc = self.get_text_from_subnode('Description')
150 else:
151 self.desc = ""
152
153 if self.get_text_from_subnode('Recommendation'):
154 self.resolution = self.get_text_from_subnode('Recommendation')
155 else:
156 self.resolution = ""
157
158 if self.get_text_from_subnode('reference'):
159 self.desc += "\nDetails: " + self.get_text_from_subnode('Details')
160
161 # Add path and params to the description to create different IDs if at
162 # least one of this fields is different
163 if self.uri:
164 self.desc += '\nPath: ' + self.uri
165 if self.parameter:
166 self.desc += '\nParameter: ' + self.parameter
167
168 self.ref = []
169 for n in item_node.findall('References/Reference'):
170 n2 = n.find('URL')
171 self.ref.append(n2.text)
172
173 def get_text_from_subnode(self, subnode_xpath_expr):
174 """
175 Finds a subnode in the host node and the retrieves a value from it.
176
177 @return An attribute value
178 """
179 sub_node = self.node.find(subnode_xpath_expr)
180 if sub_node is not None:
181 return sub_node.text
182
183 return None
18461
18562
18663 class AcunetixPlugin(PluginXMLFormat):
21087 """
21188 parser = AcunetixXmlParser(output)
21289
213 for site in parser.sites:
214 if site.ip is None:
90 for site in parser.acunetix.scan:
91 url_data = self.get_domain(site)
92 if not url_data:
21593 continue
94 if url_data.hostname:
95 self.old_structure(url_data, site)
96 else:
97 self.new_structure(site)
21698
217 if site.host != site.ip and site.host is not None:
218 hostnames = [site.host]
219 else:
220 hostnames = None
221 h_id = self.createAndAddHost(site.ip, site.os, hostnames=hostnames)
99 def new_structure(self, site):
100 for item in site.reportitems.reportitem:
101 host = item.technicaldetails.request
102 host = findall('Host: (.*)', host)[0]
103 url = f'http://{host}'
104 url_data = urlsplit(url)
105 site_ip = resolve_hostname(host)
106 h_id = self.createAndAddHost(site_ip, site.os, hostnames=[host])
222107 s_id = self.createAndAddServiceToHost(
223108 h_id,
224109 "http",
225110 "tcp",
226 ports=[site.port],
111 ports=['443'],
227112 version=site.banner,
228113 status='open')
229 for item in site.items:
114 self.create_vul(item, h_id, s_id, url_data)
230115
231 if item.desc is None:
232 self.createAndAddVulnWebToService(
233 h_id,
234 s_id,
235 item.name,
236 desc="",
237 website=site.host,
238 severity=item.severity,
239 resolution=item.resolution,
240 path=item.uri,
241 params=item.parameter,
242 request=item.request,
243 response=item.response,
244 ref=item.ref)
245 else:
246 self.createAndAddVulnWebToService(
247 h_id,
248 s_id,
249 item.name,
250 item.desc,
251 website=site.host,
252 severity=item.severity,
253 resolution=item.resolution,
254 path=item.uri,
255 params=item.parameter,
256 request=item.request,
257 response=item.response,
258 ref=item.ref)
259 del parser
116 def old_structure(self, url_data, site: Scan):
117 site_ip = resolve_hostname(url_data.hostname)
118 if url_data.hostname:
119 hostnames = [url_data.hostname]
120 else:
121 hostnames = None
122 port = url_data.port or (443 if url_data.scheme == "https" else 80)
123
124 h_id = self.createAndAddHost(site_ip, site.os, hostnames=hostnames)
125 s_id = self.createAndAddServiceToHost(
126 h_id,
127 "http",
128 "tcp",
129 ports=[port],
130 version=site.banner,
131 status='open')
132 for item in site.reportitems.reportitem:
133 self.create_vul(item, h_id, s_id, url_data)
134
135 def create_vul(self, item, h_id, s_id, url_data):
136 description = item.description
137 if item.affects:
138 description += f'\nPath: {item.affects}'
139 if item.parameter:
140 description += f'\nParameter: {item.parameter}'
141 self.createAndAddVulnWebToService(
142 h_id,
143 s_id,
144 item.name,
145 description,
146 website=url_data.hostname,
147 severity=item.severity,
148 resolution=item.recommendation,
149 path=item.affects,
150 params=item.parameter,
151 request=item.technicaldetails.request,
152 response=item.technicaldetails.response,
153 ref=[i.url for i in item.references.reference])
154
155 @staticmethod
156 def get_domain(scan: Scan):
157 url = scan.start_url
158 if not url.startswith('http'):
159 url = f'http://{url}'
160 url_data = urlsplit(url)
161 if not url_data.scheme:
162 url_data = urlsplit(scan.crawler.start_url_attr)
163 return url_data
260164
261165
262166 def createPlugin(ignore_info=False):
0 from typing import List
1
2
3 class InfoVul:
4 def __init__(self, node):
5 self.node = node
6
7 @property
8 def vt_id(self) -> str:
9 if not self.node:
10 return ''
11 return self.node.get('vt_id', '')
12
13 @property
14 def request(self) -> str:
15 if not self.node:
16 return ''
17 return self.node.get('request', '')
18
19
20 class Vulnerabilities:
21 def __init__(self, node):
22 self.node = node
23
24 @property
25 def info(self) -> InfoVul:
26 return InfoVul(self.node.get('info'))
27
28 @property
29 def response(self) -> str:
30 if not self.node:
31 return ''
32 return self.node.get('response', '')
33
34
35 class VulnerabilityTypes:
36 def __init__(self, node):
37 self.node = node
38
39 @property
40 def vt_id(self) -> str:
41 if not self.node:
42 return ''
43 return self.node.get('vt_id', '')
44
45 @property
46 def name(self) -> str:
47 if not self.node:
48 return ''
49 return self.node.get('name', '')
50
51 @property
52 def description(self) -> str:
53 if not self.node:
54 return ''
55 return self.node.get('description', '')
56
57 @property
58 def severity(self) -> int:
59 return self.node.get('severity', '')
60
61 @property
62 def recommendation(self) -> str:
63 if not self.node:
64 return ''
65 return self.node.get('recommendation', '')
66
67 @property
68 def app_id(self) -> str:
69 if not self.node:
70 return ''
71 return self.node.get('app_id', '')
72
73 @property
74 def use_ssl(self) -> bool:
75 return self.node.get('use_ssl', '')
76
77
78 class Info:
79 def __init__(self, node):
80 self.node = node
81
82 @property
83 def host(self) -> str:
84 if not self.node:
85 return ''
86 return self.node.get('host', '')
87
88
89 class Scan:
90 def __init__(self, node):
91 self.node = node
92
93 @property
94 def info(self) -> Info:
95 return Info(self.node.get('info'))
96
97 @property
98 def vul_types(self) -> List[VulnerabilityTypes]:
99 return [VulnerabilityTypes(i) for i in self.node.get('vulnerability_types', [])]
100
101 @property
102 def vulnerabilities(self) -> List[Vulnerabilities]:
103 return [Vulnerabilities(i) for i in self.node.get('vulnerabilities', [])]
104
105
106 class Export:
107 def __init__(self, node):
108 self.node = node
109
110 @property
111 def scans(self) -> List[Scan]:
112 return [Scan(i) for i in self.node.get('scans', [])]
113
114 @property
115 def lang(self) -> str:
116 if not self.node:
117 return ''
118 return self.node.get('scans', '')
119
120
121 class AcunetixJsonParser:
122 def __init__(self, node):
123 self.node = node
124
125 @property
126 def export(self) -> Export:
127 return Export(self.node.get('export'))
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
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
8 from lxml import etree
9
10 from faraday_plugins.plugins.plugin import PluginXMLFormat, PluginJsonFormat
11 from faraday_plugins.plugins.plugins_utils import resolve_hostname
12 from faraday_plugins.plugins.repo.acunetix.DTO import Acunetix, Scan
13 from json import loads
14
15 __author__ = "Francisco Amato"
16 __copyright__ = "Copyright (c) 2013, Infobyte LLC"
17 __credits__ = ["Francisco Amato"]
18 __version__ = "1.0.0"
19 __maintainer__ = "Francisco Amato"
20 __email__ = "[email protected]"
21 __status__ = "Development"
22
23 from faraday_plugins.plugins.repo.acunetix_json.DTO import AcunetixJsonParser, Vulnerabilities, \
24 VulnerabilityTypes
25
26
27 class AcunetixXmlParser:
28 """
29 The objective of this class is to parse an xml file generated by
30 the acunetix tool.
31
32 TODO: Handle errors.
33 TODO: Test acunetix output version. Handle what happens if
34 the parser doesn't support it.
35 TODO: Test cases.
36
37 @param acunetix_xml_filepath A proper xml generated by acunetix
38 """
39
40 def __init__(self, xml_output):
41
42 tree = self.parse_xml(xml_output)
43 self.acunetix = Acunetix(tree)
44
45 @staticmethod
46 def parse_xml(xml_output):
47 """
48 Open and parse an xml file.
49
50 TODO: Write custom parser to just read the nodes that we need instead
51 of reading the whole file.
52
53 @return xml_tree An xml tree instance. None if error.
54 """
55
56 try:
57 parser = etree.XMLParser(recover=True)
58 tree = etree.fromstring(xml_output, parser=parser)
59 except SyntaxError as err:
60 print("SyntaxError: %s. %s", err, xml_output)
61 return None
62
63 return tree
64
65
66 class AcunetixJsonPlugin(PluginJsonFormat):
67
68 def __init__(self, *arg, **kwargs):
69 super().__init__(*arg, **kwargs)
70 self.id = "Acunetix_Json"
71 self.name = "Acunetix JSON Output Plugin"
72 self.plugin_version = "0.1"
73 self.version = "9"
74 self.json_keys = {'export'}
75 self.framework_version = "1.0.0"
76 self._temp_file_extension = "json"
77 """
78 Example plugin to parse acunetix output.
79 """
80
81 def parseOutputString(self, output):
82 """
83 This method will discard the output the shell sends, it will read it
84 from the xml where it expects it to be present.
85
86 NOTE: if 'debug' is true then it is being run from a test case and the
87 output being sent is valid.
88 """
89 parser = AcunetixJsonParser(loads(output))
90 for site in parser.export.scans:
91 self.new_structure(site)
92
93 def new_structure(self, site: Scan):
94 start_url = site.info.host
95 url_data = urlsplit(start_url)
96 site_ip = resolve_hostname(url_data.hostname)
97 ports = '443' if (url_data.scheme == 'https') else '80'
98 vulnerability_type = {i.vt_id: i for i in site.vul_types}
99 h_id = self.createAndAddHost(site_ip, None, hostnames=[url_data.hostname])
100 s_id = self.createAndAddServiceToHost(
101 h_id,
102 "http",
103 "tcp",
104 ports=[ports],
105 version=None,
106 status='open')
107 for i in site.vulnerabilities:
108 vul_type = vulnerability_type[i.info.vt_id]
109 self.create_vul(i, vul_type, h_id, s_id, url_data)
110
111 def create_vul(self, vul: Vulnerabilities, vul_type: VulnerabilityTypes, h_id, s_id, url_data):
112 self.createAndAddVulnWebToService(
113 h_id,
114 s_id,
115 vul_type.name,
116 vul_type.description,
117 website=url_data.hostname,
118 severity=vul_type.severity,
119 resolution=vul_type.recommendation,
120 request=vul.info.request,
121 response=vul.response)
122
123 @staticmethod
124 def get_domain(scan: Scan):
125 url = scan.start_url
126 if not url.startswith('http'):
127 url = f'http://{url}'
128 url_data = urlsplit(url)
129 if not url_data.scheme:
130 url_data = urlsplit(scan.crawler.start_url_attr)
131 return url_data
132
133
134 def createPlugin(ignore_info=False):
135 return AcunetixJsonPlugin(ignore_info=ignore_info)
22 Copyright (C) 2013 Infobyte LLC (http://www.infobytesec.com/)
33 See the file 'doc/LICENSE' for the license information
44 """
5 import sys
56 import re
67 import csv
78 from ast import literal_eval
5960
6061 def parse_csv(self, output):
6162 items = []
63 csv.field_size_limit(sys.maxsize)
6264 reader = csv.DictReader(output, delimiter=',')
6365 obj_to_import = self.check_objects_to_import(reader.fieldnames)
6466 if not obj_to_import:
44
55 """
66 import socket
7 import re
78 import json
89 import dateutil
910 from collections import defaultdict
1516 __copyright__ = "Copyright (c) 2021, Infobyte LLC"
1617 __credits__ = ["Nicolas Rebagliati"]
1718 __license__ = ""
18 __version__ = "0.0.1"
19 __version__ = "1.0.0"
1920 __maintainer__ = "Nicolas Rebagliati"
2021 __email__ = "[email protected]"
2122 __status__ = "Development"
3031 super().__init__(*arg, **kwargs)
3132 self.id = "nuclei"
3233 self.name = "Nuclei"
33 self.plugin_version = "0.1"
34 self.version = "2.3.0"
34 self.plugin_version = "1.0.0"
35 self.version = "2.3.8"
3536 self.json_keys = {"matched", "templateID", "host"}
3637
3738 def parseOutputString(self, output, debug=False):
5960 description='web server')
6061 matched = vuln_dict.get('matched')
6162 matched_data = urlparse(matched)
62 references = [f"author: {vuln_dict['info'].get('author', '')}"]
63 reference = vuln_dict["info"].get('reference', [])
64 if reference:
65 if isinstance(reference, str):
66 if re.match('^- ', reference):
67 reference = list(filter(None, [re.sub('^- ','', elem) for elem in reference.split('\n')]))
68 else:
69 reference = [reference]
70 references = vuln_dict["info"].get('references', [])
71 if references:
72 if isinstance(references, str):
73 if re.match('^- ', references):
74 references = list(filter(None, [re.sub('^- ','', elem) for elem in references.split('\n')]))
75 else:
76 references = [references]
77 cwe = vuln_dict['info'].get('cwe', [])
78 capec = vuln_dict['info'].get('capec', [])
79 refs = list(set(reference + references + cwe + capec)).sort()
80 tags = vuln_dict['info'].get('tags', '').split(',')
81 impact = vuln_dict['info'].get('impact')
82 resolution = vuln_dict['info'].get('resolution', '')
83 easeofresolution = vuln_dict['info'].get('easeofresolution')
6384 request = vuln_dict.get('request', '')
6485 if request:
6586 method = request.split(" ")[0]
7899 service_id,
79100 name=name,
80101 desc=vuln_dict["info"].get("description", name),
81 ref=references,
102 ref=refs,
82103 severity=vuln_dict["info"].get('severity'),
104 tags=tags,
105 impact=impact,
106 resolution=resolution,
107 easeofresolution=easeofresolution,
83108 website=host,
84109 request=request,
85110 response=vuln_dict.get('response', ''),
321321 from the xml where it expects it to be present.
322322 """
323323 parser = OpenvasXmlParser(output, self.logger)
324 web = False
325324 ids = {}
326325 # The following threats values will not be taken as vulns
327326 self.ignored_severities = ['Log', 'Debug']
328327 for ip, values in parser.hosts.items():
329328 # values contains: ip details and ip hostnames
329 os_report = values['details'].get('best_os_txt')
330330 h_id = self.createAndAddHost(
331331 ip,
332 os_report[0] if os_report else '',
332333 hostnames=values['hostnames']
333334 )
334335 ids[ip] = h_id
7474 hostname = server_location.get('hostname', None)
7575 ip = server_location.get('ip_address', resolve_hostname(hostname))
7676 if port != 443:
77 url = 'https://' + hostname + ':' + port
77 url = f"https://{hostname}:{port}"
7878 else:
79 url = 'https://' + hostname
79 url = f"https://{hostname}"
8080
8181 json_host = {
8282 "name": 'https',
11 import socket
22 import json
33 import pytest
4 from pathlib import Path
45 from faraday_plugins.plugins.manager import PluginsManager, ReportAnalyzer
56 from faraday_plugins.plugins.plugin import PluginBase
67 from faraday.server.api.modules.bulk_create import BulkCreateSchema
4445 if not plugin_json:
4546 plugin = get_plugin_from_cache(report_file)
4647 if plugin:
47 plugin.processReport(report_file)
48 plugin.processReport(Path(report_file))
4849 plugin_json = json.loads(plugin.get_json())
4950 REPORTS_JSON_CACHE[report_file] = plugin_json
5051 else: