Codebase list faraday-plugins / eabb978
Import upstream version 1.3.0 Kali Janitor 3 years ago
125 changed file(s) with 1556 addition(s) and 1046 deletion(s). Raw diff Collapse all Expand all
1313 when: never
1414 - when: always
1515
16 .install_faraday_venv: &install_faraday_venv
17 - pip3 install virtualenv
18 - virtualenv -p python3 faraday_venv
19 - source faraday_venv/bin/activate
20 - pip3 install pytest pytest-xdist pytest-cov
21 - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/faradaysec/faraday.git
22 - cd faraday
23 - pip3 install $PIP_FLAGS .
24 - pip uninstall faraday-plugins -y # we need to install fardaysec for marshmallow schemas, we remove plugins from pypi
25 - cd ..
26
27 .clone_reports: &clone_reports
28 - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/faradaysec/support/report-collection.git
29 - cd report-collection
30 - (git branch -a | grep $CI_COMMIT_BRANCH) && export REPORT_REF=$CI_COMMIT_BRANCH || export REPORT_REF=master
31 - git checkout $REPORT_REF
32 - cd ..
33
34
1635 flake8:
1736 image: python:3
1837 stage: pre_testing
2645 after_script:
2746 - wc -l files.processed
2847
48 .test_base:
49 stage: testing
50 coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/'
51 script:
52 - *clone_reports
53 - *install_faraday_venv
54 - pip3 install $PIP_FLAGS .
55 - pytest tests --capture=sys -v --cov=faraday_plugins --color=yes --disable-warnings $PYTEST_FLAGS
56
2957 tests:
30 image: python:3.7
31 stage: testing
32 coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/'
33 before_script:
34 - pip3 install virtualenv
35 - virtualenv -p python3 faraday_venv
36 - source faraday_venv/bin/activate
37 - pip3 install pytest pytest-xdist pytest-cov
38 - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/faradaysec/faraday.git
39 - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/faradaysec/support/report-collection.git
40 - cd faraday
41 - python3 setup.py install
42 - pip uninstall faraday-plugins -y # we need to install fardaysec for marshmallow schemas, we remove plugins from pypi
43 - cd ..
44 script:
45 - source faraday_venv/bin/activate
46 - python3 setup.py install
47 - pytest tests --capture=sys -v --cov=faraday_plugins --color=yes --disable-warnings
48
58 extends: .test_base
59 image: python:3
4960
5061 test_performance:
51 image: python:3.7
52 stage: post_testing
53 coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/'
54 allow_failure: true
55 before_script:
56 - pip3 install virtualenv
57 - virtualenv -p python3 faraday_venv
58 - source faraday_venv/bin/activate
59 - pip3 install pytest pytest-xdist pytest-cov
60 - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/faradaysec/faraday.git
61 - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/faradaysec/support/report-collection.git
62 - cd faraday
63 - python3 setup.py install
64 - pip uninstall faraday-plugins -y # we need to install fardaysec for marshmallow schemas, we remove plugins from pypi
65 - cd ..
66 script:
67 - source faraday_venv/bin/activate
68 - python3 setup.py install
69 - pytest tests --capture=sys -v --cov=faraday_plugins --color=yes --disable-warnings --performance
70 rules:
71 - if: '$CI_COMMIT_BRANCH == "develop"'
72 when: on_success
62 extends: .test_base
63 image: python:3
64 stage: post_testing
65 allow_failure: true
66 variables:
67 PYTEST_FLAGS: --performance
68 rules:
69 - if: '$CI_COMMIT_BRANCH == "dev"'
70 when: on_success
7371
7472 publish_pypi:
7573 image: python:3
0 ADD plugin AppSpider
0 Add tests to faraday-plugins cli
0 add a default value to plugin_version
0 Add --output-file parameter to faraday-plugins process command
0 Add plugins prowler
0 Add plugins ssl labs
0 Add support for tenable io
0 delete old deprecated methods
0 Bug fix: Arachni Plugin 'NoneType' object has no attribute 'find'
0 Bug fix: Openvas Plugin - Import xml from OpenVas doesnt work
0 Bug fix: QualysWebApp Plugin, error in get info OPERATING_SYSTEM
0 Fix Hydra plugin to resolve ip address
0 Fix Nessus mod severity HIGH for Low
0 Bug Fix: Detect plugins AWS Prowler
0 Fix broken xml on nmap plugin
0 Add new rdpscan plugin
0 UPDATE xml report to appscan
0 Fix how ZAP genereate vulns
0 1.3.0:
1 ---
2 * ADD plugin AppSpider
3 * Add tests to faraday-plugins cli
4 * add a default value to plugin_version
5 * Add --output-file parameter to faraday-plugins process command
6 * Add plugins prowler
7 * Add plugins ssl labs
8 * Add support for tenable io
9 * delete old deprecated methods
10 * Bug fix: Arachni Plugin 'NoneType' object has no attribute 'find'
11 * Bug fix: Openvas Plugin - Import xml from OpenVas doesnt work
12 * Bug fix: QualysWebApp Plugin, error in get info OPERATING_SYSTEM
13 * Fix Hydra plugin to resolve ip address
14 * Fix Nessus mod severity HIGH for Low
15 * Bug Fix: Detect plugins AWS Prowler
16 * Fix broken xml on nmap plugin
17 * Add new rdpscan plugin
18 * UPDATE xml report to appscan
19 * Update Readme
20 * Fix how ZAP genereate vulns
21
(New empty file)
0 ADD plugin AppSpider
0 Add tests to faraday-plugins cli
0 add a default value to plugin_version
0 Add --output-file parameter to faraday-plugins process command
0 Add plugins prowler
0 Add plugins ssl labs
0 Add support for tenable io
0 delete old deprecated methods
0 * Bug fix: Arachni Plugin 'NoneType' object has no attribute 'find'
0 * Bug fix: Openvas Plugin - Import xml from OpenVas doesnt work
0 * Bug fix: QualysWebApp Plugin, error in get info OPERATING_SYSTEM
0 Fix Hydra plugin to resolve ip address
0 Fix Nessus mod severity HIGH for Low
0 * Bug Fix: Detect plugins AWS Prowler
0 * Fix broken xml on nmap plugin
0 * Add new rdpscan plugin
0 UPDATE xml report to appscan
0 Fix how ZAP genereate vulns
77
88 > List Plugins
99
10 List all plugins and if its compatible with command or/and report
11
12 Optional params:
13
14 - -cpf / --custom-plugins-folder PATH: If given will also look for custom plugins on that path
15
1016 ```shell script
11 faraday-plugins show
17 faraday-plugins list-plugins
1218 ```
1319
1420 > Test autodetect plugin from command
1521
1622 ```shell script
1723 faraday-plugins detect-command "ping -c 4 www.google.com"
18 > Faraday Plugin: ping
24
25 Faraday Plugin: ping
1926 ```
2027
21 > Test command with plugin
28 > Test process command with plugin
2229
2330 Optional params:
2431
25 - -dr: Dont run, just show the generated command
32 - --plugin_id PLUGIN_ID: Dont detect the plugin, use this one
33 - -cpf / --custom-plugins-folder PATH: If given will also look for custom plugins on that path
34 - -dr / --dont-run: Dont run, just show the generated command
35 - -o / --output-file PATH: send json outout to file instead of stdout
36 - -sh / --show-output: show the output of the command
2637
2738 ```shell script
2839 faraday-plugins process-command "ping -c4 www.google.com"
29 Running command: ping -c4 www.google.com
30
31 PING www.google.com (216.58.222.36): 56 data bytes
32 64 bytes from 216.58.222.36: icmp_seq=0 ttl=54 time=11.144 ms
33 64 bytes from 216.58.222.36: icmp_seq=1 ttl=54 time=14.330 ms
34 64 bytes from 216.58.222.36: icmp_seq=2 ttl=54 time=11.997 ms
35 64 bytes from 216.58.222.36: icmp_seq=3 ttl=54 time=11.190 ms
36
37 --- www.google.com ping statistics ---
38 4 packets transmitted, 4 packets received, 0.0% packet loss
39 round-trip min/avg/max/stddev = 11.144/12.165/14.330/1.295 ms
40
41 Faraday API json:
4240 {
4341 "hosts": [
4442 {
45 "ip": "216.58.222.36",
43 "ip": "216.58.202.36",
4644 "os": "unknown",
4745 "hostnames": [
4846 "www.google.com"
4947 ],
5048 "description": "",
51 "mac": "00:00:00:00:00:00",
49 "mac": null,
5250 "credentials": [],
5351 "services": [],
54 "vulnerabilities": []
52 "vulnerabilities": [],
53 "tags": []
5554 }
5655 ],
5756 "command": {
5857 "tool": "ping",
5958 "command": "ping",
6059 "params": "-c4 www.google.com",
61 "user": "aenima",
60 "user": "user",
6261 "hostname": "",
63 "start_date": "2020-05-05T23:09:39.656132",
64 "duration": 56789,
65 "import_source": "report"
62 "start_date": "2020-06-19T17:02:37.982293",
63 "duration": 39309,
64 "import_source": "shell"
6665 }
6766 }
6867 ```
7170
7271 ```shell script
7372 faraday-plugins detect-report /path/to/report.xml
73
74 Faraday Plugin: Nmap
7475 ```
7576
7677
7778 > Test report with plugin
7879
80 Optional params:
81
82 - --plugin_id PLUGIN_ID: Dont detect the plugin, use this one
83 - -cpf / --custom-plugins-folder PATH: If given will also look for custom plugins on that path
84
7985 ```shell script
80 faraday-plugins process-report /path/to/report.xml
86 faraday-plugins process-report /path/to/nmap_report.xml
87
88 {
89 "hosts": [
90 {
91 "ip": "192.168.66.1",
92 "os": "unknown",
93 "hostnames": [],
94 "description": "",
95 "mac": "00:00:00:00:00:00",
96 "credentials": [],
97 "services": [
98 {
99 "name": "domain",
100 "protocol": "tcp",
101 "port": 53,
102 "status": "open",
103 "version": "",
104 "description": "domain",
105 "credentials": [],
106 "vulnerabilities": [],
107 "tags": []
108 },
109 {
110 "name": "netbios-ssn",
111 "protocol": "tcp",
112 "port": 139,
113 "status": "open",
114 "version": "",
115 "description": "netbios-ssn",
116 "credentials": [],
117 "vulnerabilities": [],
118 "tags": []
119 }
120 ],
121 "vulnerabilities": [],
122 "tags": []
123 }
124 ],
125 "command": {
126 "tool": "Nmap",
127 "command": "Nmap",
128 "params": "/path/to/nmap_report.xml",
129 "user": "user",
130 "hostname": "",
131 "start_date": "2020-06-19T17:22:11.608134",
132 "duration": 1233,
133 "import_source": "report"
134 }
135 }
81136 ```
82
83 > Process options:
84
85 Both process-xxx command have this optional parameters
86
87 - --plugin_id: If given will use that plugin instead of try to detect it
88 - --summary: If given will generate a summary of the findings instead of the result
89 - -cpf/--custom-plugins-folder: If given will also look for custom plugins if that path
90
91 NOTE: you can also use -cpf in **show** command to test if your custom plugins load ok
92137
93138 > Plugin Logger
94139
0 1.3.0:
1 ---
2 * ADD plugin AppSpider
3 * Add tests to faraday-plugins cli
4 * add a default value to plugin_version
5 * Add --output-file parameter to faraday-plugins process command
6 * Add plugins prowler
7 * Add plugins ssl labs
8 * Add support for tenable io
9 * delete old deprecated methods
10 * Bug fix: Arachni Plugin 'NoneType' object has no attribute 'find'
11 * Bug fix: Openvas Plugin - Import xml from OpenVas doesnt work
12 * Bug fix: QualysWebApp Plugin, error in get info OPERATING_SYSTEM
13 * Fix Hydra plugin to resolve ip address
14 * Fix Nessus mod severity HIGH for Low
15 * Bug Fix: Detect plugins AWS Prowler
16 * Fix broken xml on nmap plugin
17 * Add new rdpscan plugin
18 * UPDATE xml report to appscan
19 * Update Readme
20 * Fix how ZAP genereate vulns
21
0 with import <nixpkgs> {};
1 pkgs.python38Packages.buildPythonPackage rec {
2 name = "env";
3
4 env = buildEnv { name = name; paths = buildInputs; };
5
6 buildInputs = [
7 (python38.buildEnv.override {
8 ignoreCollisions = true;
9 extraLibs = with python38Packages; [
10 requests
11 click
12 simplejson
13 requests
14 lxml
15 html2text
16 beautifulsoup4
17 pytz
18 python-dateutil
19 colorama
20 ];
21 })
22 ];
23 }
0 __version__ = '1.2'
0 __version__ = '1.3.0'
5050 @click.option('--plugin_id', type=str)
5151 @click.option('-cpf', '--custom-plugins-folder', type=str)
5252 @click.option('--summary', is_flag=True)
53 def process_report(report_file, plugin_id, custom_plugins_folder, summary):
53 @click.option('-o', '--output-file', type=click.Path(exists=False))
54 def process_report(report_file, plugin_id, custom_plugins_folder, summary, output_file):
5455 if not os.path.isfile(report_file):
55 click.echo(click.style(f"File {report_file} Don't Exists", fg="red"))
56 click.echo(click.style(f"File {report_file} Don't Exists", fg="red"), err=True)
5657 else:
5758 plugins_manager = PluginsManager(custom_plugins_folder)
5859 analyzer = ReportAnalyzer(plugins_manager)
5960 if plugin_id:
6061 plugin = plugins_manager.get_plugin(plugin_id)
6162 if not plugin:
62 click.echo(click.style(f"Invalid Plugin: {plugin_id}", fg="red"))
63 click.echo(click.style(f"Invalid Plugin: {plugin_id}", fg="red"), err=True)
6364 return
6465 else:
6566 plugin = analyzer.get_plugin(report_file)
6667 if not plugin:
67 click.echo(click.style(f"Failed to detect report: {report_file}", fg="red"))
68 click.echo(click.style(f"Failed to detect report: {report_file}", fg="red"), err=True)
6869 return
6970 plugin.processReport(report_file, getpass.getuser())
7071 if summary:
71 click.echo(click.style("\nPlugin Summary: ", fg="cyan"))
7272 click.echo(json.dumps(plugin.get_summary(), indent=4))
7373 else:
74 click.echo(click.style("\nFaraday API json: ", fg="cyan"))
75 click.echo(json.dumps(plugin.get_data(), indent=4))
74 if output_file:
75 with open(output_file, "w") as f:
76 json.dump(plugin.get_data(), f)
77 else:
78 click.echo(json.dumps(plugin.get_data(), indent=4))
7679
7780
7881 @cli.command()
8184 @click.option('-cpf', '--custom-plugins-folder', type=str)
8285 @click.option('-dr', '--dont-run', is_flag=True)
8386 @click.option('--summary', is_flag=True)
84 def process_command(command, plugin_id, custom_plugins_folder, dont_run, summary):
87 @click.option('-o', '--output-file', type=click.Path(exists=False))
88 @click.option('-sh', '--show-output', is_flag=True)
89 def process_command(command, plugin_id, custom_plugins_folder, dont_run, summary, output_file, show_output):
8590 plugins_manager = PluginsManager(custom_plugins_folder)
8691 analyzer = CommandAnalyzer(plugins_manager)
8792 if plugin_id:
8893 plugin = plugins_manager.get_plugin(plugin_id)
8994 if not plugin:
90 click.echo(click.style(f"Invalid Plugin: {plugin_id}", fg="red"))
95 click.echo(click.style(f"Invalid Plugin: {plugin_id}", fg="red"), err=True)
9196 return
9297 else:
9398 plugin = analyzer.get_plugin(command)
9499 if not plugin:
95 click.echo(click.style(f"Failed to detect command: {command}", fg="red"))
100 click.echo(click.style(f"Failed to detect command: {command}", fg="red"), err=True)
96101 return
97102 current_path = os.path.abspath(os.getcwd())
98103 modified_command = plugin.processCommandString(getpass.getuser(), current_path, command)
99104 if modified_command:
100105 command = modified_command
101 if not dont_run:
102 color_message = click.style("Running command: ", fg="green")
103 click.echo(f"{color_message} {command}\n")
106 if dont_run:
107 color_message = click.style("Command: ", fg="green")
108 click.echo(f"{color_message} {command}")
109 else:
104110 p = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
105111 output = io.StringIO()
106112 while True:
107113 retcode = p.poll()
108114 line = p.stdout.readline().decode('utf-8')
109 sys.stdout.write(line)
115 if show_output:
116 sys.stdout.write(line)
110117 output.write(line)
111118 if retcode is not None:
112119 extra_lines = map(lambda x: x.decode('utf-8'), p.stdout.readlines())
113 sys.stdout.writelines(line)
120 if show_output:
121 sys.stdout.writelines(line)
114122 output.writelines(extra_lines)
115123 break
116124 output_value = output.getvalue()
117125 if retcode == 0:
118126 plugin.processOutput(output_value)
119127 if summary:
120 click.echo(click.style("\nPlugin Summary: ", fg="cyan"))
121128 click.echo(json.dumps(plugin.get_summary(), indent=4))
122129 else:
123 click.echo(click.style("\nFaraday API json: ", fg="cyan"))
124 click.echo(json.dumps(plugin.get_data(), indent=4))
130 if output_file:
131 with open(output_file, "w") as f:
132 json.dump(plugin.get_data(), f)
133 else:
134 click.echo(json.dumps(plugin.get_data(), indent=4))
125135 else:
126 click.echo(click.style("Command execution error!!", fg="red"))
127 else:
128 color_message = click.style("Command: ", fg="green")
129 click.echo(f"{color_message} {command}")
136 click.echo(click.style("Command execution error!!", fg="red"), err=True)
130137
131138
132139
143150 if plugin:
144151 click.echo(click.style(f"Faraday Plugin: {plugin.id}", fg="cyan"))
145152 else:
146 click.echo(click.style(f"Failed to detect report: {report_file}", fg="red"))
153 click.echo(click.style(f"Failed to detect report: {report_file}", fg="red"), err=True)
147154
148155
149156 @cli.command()
156163 if plugin:
157164 click.echo(click.style(f"Faraday Plugin: {plugin.id}", fg="cyan"))
158165 else:
159 click.echo(click.style(f"Failed to detect command: {command}", fg="red"))
166 click.echo(click.style(f"Failed to detect command: {command}", fg="red"), err=True)
5656 self.start_date = datetime.now()
5757 self.logger = logger.getChild(self.__class__.__name__)
5858 self.open_options = {"mode": "r", "encoding": "utf-8"}
59 self.plugin_version = "0.0"
5960 self.vulns_data = {"hosts": [], "command": {"tool": "",
6061 "command": "",
6162 "params": "",
315316
316317 if not hostnames:
317318 hostnames = []
319 if not isinstance(hostnames, list):
320 hostnames = [hostnames]
318321 # Some plugins sends a list with None, we filter empty and None values.
319322 hostnames = [hostname for hostname in hostnames if hostname]
320323 if os is None:
327330 "credentials": [], "services": [], "vulnerabilities": [], "tags": tags}
328331 host_id = self.save_host_cache(host)
329332 return host_id
330
331 # @deprecation.deprecated(deprecated_in="3.0", removed_in="3.5",
332 # current_version=VERSION,
333 # details="Interface object removed. Use host or service instead")
334 def createAndAddInterface(
335 self, host_id, name="", mac="00:00:00:00:00:00",
336 ipv4_address="0.0.0.0", ipv4_mask="0.0.0.0", ipv4_gateway="0.0.0.0",
337 ipv4_dns=None, ipv6_address="0000:0000:0000:0000:0000:0000:0000:0000",
338 ipv6_prefix="00",
339 ipv6_gateway="0000:0000:0000:0000:0000:0000:0000:0000", ipv6_dns=None,
340 network_segment="", hostname_resolution=None):
341 if ipv4_dns is None:
342 ipv4_dns = []
343 if ipv6_dns is None:
344 ipv6_dns = []
345 if hostname_resolution is None:
346 hostname_resolution = []
347 if not isinstance(hostname_resolution, list):
348 self.logger.warning("hostname_resolution parameter must be a list and is (%s)", type(hostname_resolution))
349 hostname_resolution = [hostname_resolution]
350 # We don't use interface anymore, so return a host id to maintain
351 # backwards compatibility
352 # Little hack because we dont want change all the plugins for add hostnames in Host object.
353 # SHRUG
354 host = self.get_from_cache(host_id)
355 for hostname in hostname_resolution:
356 if hostname not in host["hostnames"]:
357 host["hostnames"].append(hostname)
358 host["mac"] = mac
359 return host_id
360
361 # @deprecation.deprecated(deprecated_in="3.0", removed_in="3.5",
362 # current_version=VERSION,
363 # details="Interface object removed. Use host or service instead. Service will be attached
364 # to Host!")
365 def createAndAddServiceToInterface(self, host_id, interface_id, name,
366 protocol="tcp", ports=None,
367 status="open", version="unknown",
368 description="", tags=None):
369 return self.createAndAddServiceToHost(host_id, name, protocol, ports, status, version, description, tags)
370333
371334 def createAndAddServiceToHost(self, host_id, name,
372335 protocol="tcp", ports=None,
419382 vulnerability["run_date"] = self.get_utctimestamp(run_date)
420383 vulnerability_id = self.save_host_vuln_cache(host_id, vulnerability)
421384 return vulnerability_id
422
423 # @deprecation.deprecated(deprecated_in="3.0", removed_in="3.5",
424 # current_version=VERSION,
425 # details="Interface object removed. Use host or service instead. Vuln will be added
426 # to Host")
427 def createAndAddVulnToInterface(self, host_id, interface_id, name,
428 desc="", ref=None, severity="",
429 resolution="", data="", tags=None):
430 return self.createAndAddVulnToHost(host_id, name, desc=desc, ref=ref, severity=severity, resolution=resolution,
431 data=data, tags=tags)
432385
433386 def createAndAddVulnToService(self, host_id, service_id, name, desc="",
434387 ref=None, severity="", resolution="", data="", external_id=None, run_date=None,
514467 def createAndAddNoteToHost(self, host_id, name, text):
515468 return None
516469
517 def createAndAddNoteToInterface(self, host_id, interface_id, name, text):
518 return None
519470
520471 def createAndAddNoteToService(self, host_id, service_id, name, text):
521472 return None
529480 service["credentials"].append(credential)
530481 credential_id = self.save_cache(credential)
531482 return credential_id
532
533 def log(self, msg, level='INFO'):# TODO borrar
534 pass
535 #self.__addPendingAction(Modelactions.LOG, msg, level)
536
537 def devlog(self, msg): # TODO borrar
538 pass
539 #self.__addPendingAction(Modelactions.DEVLOG, msg)
540483
541484 def get_data(self):
542485 self.vulns_data["command"]["tool"] = self.id
9999
100100 def resolve_hostname(hostname):
101101 try:
102 socket.inet_aton(hostname) # is already an ip
103 return hostname
104 except socket.error:
105 pass
106 try:
102107 ip_address = socket.gethostbyname(hostname)
103108 except Exception as e:
104109 return hostname
228228 self._current_output = None
229229 self.target = None
230230
231 def parseOutputString(self, output, debug=False):
231 def parseOutputString(self, output):
232232 """
233233 This method will discard the output the shell sends, it will read it
234234 from the xml where it expects it to be present.
242242 if site.ip is None:
243243 continue
244244
245 if site.host != site.ip:
246 host = site.host
247 h_id = self.createAndAddHost(site.ip, site.os)
248 if site.host is None:
249 i_id = self.createAndAddInterface(h_id, site.ip, ipv4_address=site.ip)
245 if site.host != site.ip and site.host is not None:
246 hostnames = [site.host]
250247 else:
251 i_id = self.createAndAddInterface(h_id, site.ip,
252 ipv4_address=site.ip,
253 hostname_resolution=[host])
254 s_id = self.createAndAddServiceToInterface(
248 hostnames = None
249 h_id = self.createAndAddHost(site.ip, site.os, hostnames=hostnames)
250 s_id = self.createAndAddServiceToHost(
255251 h_id,
256 i_id,
257252 "http",
258253 "tcp",
259254 ports=[site.port],
3636 for line in output.split('\n'):
3737 if line.startswith('#'):
3838 continue
39
4039 fields = self.get_info(line)
41
4240 if len(fields) < 6:
4341 continue
44
4542 address = fields[0]
46 h_id = self.createAndAddHost(address)
47
4843 port = fields[1]
4944 protocol = fields[2]
5045 port_status = fields[3]
51
5246 identification = fields[5]
5347 printable_banner = fields[6]
54
5548 if port in services.keys():
5649 if identification != 'unidentified':
5750 services[port][5] += ', ' + identification
6659 printable_banner,
6760 None]
6861
69 args = {}
70
71 if self.args.__getattribute__("6"):
72 self.ip = self.get_ip_6(self.args.m)
73 args['ipv6_address'] = address
62 if address != self.args.m:
63 hostnames = [self.args.m]
7464 else:
75 self.ip = resolve_hostname(self.args.m)
76 args['ipv4_address'] = address
77
78 if address != self.args.m:
79 args['hostname_resolution'] = [self.args.m]
80
81 i_id = self.createAndAddInterface(h_id, name=address, **args)
65 hostnames = None
66 h_id = self.createAndAddHost(address, hostnames=hostnames)
8267
8368 for key in services:
8469 service = services.get(key)
85 self.createAndAddServiceToInterface(
70 self.createAndAddServiceToHost(
8671 h_id,
87 i_id,
8872 service[5],
8973 service[2],
9074 ports=[service[1]],
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 #!/usr/bin/env python
1 # -*- coding: utf-8 -*-
62 from faraday_plugins.plugins.plugin import PluginXMLFormat
73 from faraday_plugins.plugins.plugins_utils import resolve_hostname
8 from lxml import objectify
9 from urllib.parse import urlparse
10
11 __author__ = "Alejando Parodi, Ezequiel Tavella"
4 try:
5 import xml.etree.cElementTree as ET
6 except ImportError:
7 import xml.etree.ElementTree as ET
8
9
10 __author__ = "Alejando Parodi, Ezequiel Tavella, Blas Moyano"
1211 __copyright__ = "Copyright (c) 2015, Infobyte LLC"
1312 __credits__ = ["Alejando Parodi", "Ezequiel Tavella"]
1413 __license__ = ""
1716 __status__ = "Development"
1817
1918
20
21 class AppscanParser():
22
23 def __init__(self, output, logger):
24 self.issue_list = []
25 self.logger = logger
26 self.obj_xml = objectify.fromstring(output)
27
28 def parse_issues(self):
29 issue_type = self.parse_issue_type()
30 for issue in self.obj_xml["issue-group"]["item"]:
31 issue_data = issue_type[issue['issue-type']['ref']]
32 obj_issue = {}
33 obj_issue["name"] = issue_data["name"]
34 obj_issue['advisory'] = issue_data["advisory"]
35 if "cve" in issue_data:
36 obj_issue['cve'] = issue_data["cve"].text
37 obj_issue['url'] = self.get_url(issue['url']['ref'].text)
38 obj_issue['cvss_score'] = issue["cvss-score"].text
39 obj_issue['response'] = self.get_response(issue)
40 obj_issue['request'] = issue['variant-group']['item']["test-http-traffic"].text
41 obj_issue['method'] = self.get_method(issue['variant-group']['item']["test-http-traffic"].text)
42 obj_issue['severity'] = issue['severity'].text
43 obj_issue['issue-description'] = self.parse_advisory_group(issue_data['advisory'])
44 for recommendation in self.obj_xml["fix-recommendation-group"]["item"]:
45 full_data = ""
46 if recommendation.attrib['id'] == issue_data["fix-recommendation"]:
47 for data in recommendation['general']['fixRecommendation']["text"]:
48 full_data += '' + data
49 obj_issue["recomendation"] = full_data
50 if hasattr(recommendation['general']['fixRecommendation'], 'link'):
51 obj_issue["ref_link"] = recommendation['general']['fixRecommendation']['link'].text
52 self.issue_list.append(obj_issue)
53 return self.issue_list
54
55 def parse_hosts(self):
56 hosts_list = []
57 for host in self.obj_xml['scan-configuration']['scanned-hosts']['item']:
58 hosts_dict = {}
59 hosts_dict['ip'] = resolve_hostname(host['host'].text)
60 hosts_dict['hostname'] = host['host'].text
61 hosts_dict['os'] = host['operating-system'].text
62 hosts_dict['port'] = host['port'].text
63 if host['port'].text == '443':
64 hosts_dict['scheme'] = 'https'
19 class AppScanParser:
20 def __init__(self, xml_output):
21 self.tree = self.parse_xml(xml_output)
22 if self.tree:
23 self.operating_system = self.tree.attrib['technology']
24 url_group = [tags.tag for tags in self.tree]
25 check_url = True if 'url-group' in url_group else False
26 if check_url:
27 self.urls = self.get_urls_info(self.tree.find('url-group'))
6528 else:
66 hosts_dict['scheme'] = 'http'
67 hosts_list.append(hosts_dict)
68 return hosts_list
69
70 def parse_issue_type(self):
71 res = {}
72 for issue_type in self.obj_xml["issue-type-group"]["item"]:
73 res[issue_type.attrib['id']] = {
74 'name': issue_type.name.text,
75 'advisory': issue_type["advisory"]["ref"].text,
76 'fix-recommendation': issue_type["fix-recommendation"]["ref"].text
29 self.urls = None
30 self.layout = self.get_layout_info(self.tree.find('layout'))
31 self.item = self.get_issue_type(self.tree.find('issue-type-group'))
32 self.name_scan = self.get_issue_data(self.tree.find('advisory-group'))
33 self.host_data = None if self.tree.find('scan-configuration/scanned-hosts/item') is None else \
34 self.get_scan_conf_data(self.tree.find('scan-configuration/scanned-hosts/item'))
35 self.issue_group = self.get_info_issue_group(self.tree.find("issue-group"))
36 self.fix_recomendation = self.get_fix_info(self.tree.find('fix-recommendation-group'))
37
38 else:
39 self.tree = None
40
41 def parse_xml(self, xml_output):
42 try:
43 tree = ET.fromstring(xml_output)
44 except SyntaxError as err:
45 print('SyntaxError In xml: %s. %s' % (err, xml_output))
46 return None
47 return tree
48
49 def get_fix_info(self, tree):
50 list_fix = []
51 for item in tree:
52 text_info_join = []
53 if item.find("general/fixRecommendation"):
54 for text_tag in tree.findall('text'):
55 text_info_join += text_tag.text
56 info_fix = {
57 "id": item.attrib.get('id', None),
58 "text": text_info_join
59 }
60 list_fix.append(info_fix)
61 return list_fix
62
63 def get_info_issue_group(sef,tree):
64 data_res_req = []
65 for item in tree:
66 if item.find("variant-group/item/issue-information"):
67 resp = item.find("variant-group/item/issue-information").text
68 else:
69 resp = "Not Response"
70
71 json_res_req = {
72 "request": "Not request" if item.find("variant-group/item/test-http-traffic") is None else
73 item.find("variant-group/item/test-http-traffic").text,
74 "response": resp,
75 "location": "Not Location" if item.find("location") is None else item.find("location").text,
76 "source_file": "0.0.0.0" if item.find("source-file") is None else item.find("source-file").text,
77 "line": 0 if item.find("line") is None else item.find("line").text,
78 "id_item": item.attrib.get('id', 'Not id item'),
79 "severity": 0 if item.find("severity-id") is None else item.find("severity-id").text,
80 "cvss": "No cvss" if item.find("cvss-score") is None else item.find("cvss-score").text,
81 "cwe": "No cwe" if item.find("cwe") is None else item.find("cwe").text,
82 "remediation": "No remedation" if item.find("remediation/ref") is None else item.find(
83 "remediation/ref").text,
84 "advisory": "No advisory" if item.find("advisory/ref") is None else item.find("advisory/ref").text,
85 "url_id": "No url id" if item.find("url/ref") is None else item.find("url/ref").text,
86 "id_adv": "Not info" if item.find("issue-type/ref") is None else item.find("issue-type/ref").text
87 }
88
89 data_res_req.append(json_res_req)
90 return data_res_req
91
92 def get_layout_info(self, tree):
93 info_layout = {
94 "name": "Not info" if tree.find("application-name") is None else tree.find("application-name").text,
95 "date": "Not info" if tree.find("report-date") is None else tree.find("report-date").text,
96 "details": f'Departamento: {"Not info" if tree.find("department") is None else tree.find("department").text}'
97 f'Compania: {"Not info" if tree.find("company") is None else tree.find("company").text}'
98 f'Titulo Reporte: {"Not info" if tree.find("title") is None else tree.find("title").text}',
99 "nro_issues": None if tree.find("total-issues-in-application") is None else tree.find("total-issues-in-application").text,
100 }
101 return info_layout
102
103 def get_issue_type(self, tree):
104 list_item = []
105 for item in tree:
106 severity = item.attrib.get('severity-id', None)
107 if severity is None:
108 severity = item.attrib.get('maxIssueSeverity', None)
109
110 item_info = {
111 "id": item.attrib.get('id', None),
112 "name": item.find("name").text,
113 "severity_id": severity,
114 "severity": item.attrib.get('severity', None),
115 "cwe": "Not info" if item.find("cme") is None else item.find("cwe").text,
116 "xfid": "Not info" if item.find("xfid") is None else item.find("xfid").text,
117 "advisory": "Not info" if item.find("advisory/ref") is None else item.find("advisory/ref").text
118 }
119 list_item.append(item_info)
120
121 return list_item
122
123 def get_issue_data(self, tree):
124 list_item_data = []
125 item_data = {}
126 for item in tree:
127 for adivisory in item:
128 if adivisory.find("cwe/link"):
129 cwe = adivisory.find("cwe/link").text
130 else:
131 cwe = "Not Response"
132
133 if adivisory.find("xfid/link"):
134 xfid = adivisory.find("xfid/link").text
135 else:
136 xfid = "Not Response"
137
138 item_data = {
139 "id": item.attrib.get('id', None),
140 "name": "Not info" if adivisory.find("name") is None else adivisory.find("name").text,
141 "description": "Not info" if adivisory.find("testDescription") is None else
142 adivisory.find("testDescription").text,
143 "threatClassification": {
144 "name": "Not info" if adivisory.find("threatClassification/name") is None else
145 adivisory.find("threatClassification/name").text,
146 "reference": "Not info" if adivisory.find("threatClassification/reference") is None else
147 adivisory.find("threatClassification/reference").text,
148 },
149 "testTechnicalDescription": "Not info" if adivisory.find("testTechnicalDescription") is None else
150 self.get_parser(adivisory.find("testTechnicalDescription")),
151 "testTechnicalDescriptionMixed": "Not info" if adivisory.find("testTechnicalDescriptionMixed") is None else
152 self.get_parser(adivisory.find("testTechnicalDescriptionMixed")),
153
154 "testDescriptionMixed": "Not info" if adivisory.find("testDescriptionMixed") is None else
155 self.get_parser(adivisory.find("testDescriptionMixed")),
156 "causes": "Not info" if adivisory.find("causes/cause") is None else
157 adivisory.find("causes/cause").text,
158 "securityRisks": "Not info" if adivisory.find("securityRisks/securityRisk") is None else
159 adivisory.find("securityRisks/securityRisk").text,
160 "affectedProducts": "Not info" if adivisory.find("affectedProducts/affectedProduct") is None else
161 adivisory.find("affectedProducts/affectedProduct").text,
162 "cwe": cwe,
163 "xfid": xfid,
164 "references": "Not info" if adivisory.find("references") is None else
165 self.get_parser(adivisory.find("references")),
166 "fixRecommendations": "Not info" if adivisory.find("fixRecommendations/fixRecommendation") is None else
167 self.get_parser(adivisory.find("fixRecommendations/fixRecommendation"))
77168 }
78 if "cve" in issue_type:
79 res[issue_type.attrib['id']] = {'cve': issue_type["cve"].text}
80 return res
81
82 def parse_advisory_group(self, advisory):
83 """
84 Function that parse advisory-group in order to get the item's description
85 """
86 for item in self.obj_xml["advisory-group"]["item"]:
87 if item.attrib['id'] == advisory:
88 return item['advisory']['testTechnicalDescription']['text'].text
89
90 def get_url(self, ref):
91 for item in self.obj_xml['url-group']['item']:
92 if item.attrib['id'] == ref:
93 return item['name'].text
94
95 def get_method(self, http_traffic):
96 methods_list = ['GET', 'POST', 'PUT', 'DELETE', 'CONNECT', 'PATCH', 'HEAD', 'OPTIONS']
97 try:
98 if http_traffic:
99 for item in methods_list:
100 if http_traffic.startswith(item):
101 return item
102 except TypeError:
103 return None
104 return None
105
106 def get_response(self, node):
107 try:
108 response = node['variant-group']['item']['issue-information']["testResponseChunk"].text
109 return response
110 except AttributeError:
111 return None
112
113 def get_scan_information(self):
114
115 scan_information = "File: " + self.obj_xml["scan-information"]["scan-file-name"]\
116 + "\nStart: " + self.obj_xml["scan-information"]["scan-date-and-time"]\
117 + "\nSoftware: " + self.obj_xml["scan-information"]["product-name"]\
118 + "\nVersion: " + self.obj_xml["scan-information"]["product-version"]\
119 + "\nScanner Elapsed time: " + self.obj_xml["scan-summary"]["scan-Duration"]
120
121 return scan_information
122
123
124 class AppscanPlugin(PluginXMLFormat):
125 """ Example plugin to parse Appscan XML report"""
126
169 list_item_data.append(item_data)
170 return list_item_data
171
172 def get_parser(self, tree):
173 text_join = ""
174 code_join = ""
175 link_join = ""
176
177 if tree.tag == 'testTechnicalDescription':
178
179 for text_info in tree.findall('text'):
180 text_join += text_info.text
181
182 for code_info in tree.findall('code'):
183 text_join += code_info.text
184
185 tech_data = {
186 "text": text_join,
187 "code": code_join
188 }
189
190 elif tree.tag == 'testDescriptionMixed':
191
192 for text_info in tree.findall('p'):
193 text_join += text_info.text
194
195 for code_info in tree.findall('li'):
196 text_join += code_info.text
197
198 tech_data = {
199 "text": text_join,
200 "items": code_join
201 }
202
203 elif tree.tag == 'testTechnicalDescriptionMixed':
204
205 for text_info in tree.findall('p'):
206 text_join += text_info.text
207
208 tech_data = {
209 "text": text_join,
210 }
211
212 elif tree.tag == 'references':
213 for text_info in tree.findall('text'):
214 text_join += "no info " if text_info.text is None else text_info.text
215
216 for link_info in tree.findall('link'):
217 link_join += "no info " if link_info.text is None else link_info.text
218 link_join += link_info.attrib.get('target', 'not target')
219
220 tech_data = {
221 "text": text_join,
222 "Link": link_join
223 }
224
225 elif tree.tag == 'fixRecommendation':
226 for text_info in tree.findall('text'):
227 text_join += "no info " if text_info.text is None else text_info.text
228
229 for link_info in tree.findall('link'):
230 link_join += "no info " if link_info.text is None else link_info.text
231 link_join += link_info.attrib.get('target', 'not target')
232
233 tech_data = {
234 "text": text_join,
235 "link": link_join
236 }
237
238 return tech_data
239
240 def get_urls_info(self, tree):
241 list_url = []
242 for url in tree:
243 url_info = {
244 "id_item": url.attrib.get('id', 'Not id item'),
245 "id": "Not info" if url.find("issue-type") is None else url.find("issue-type").text,
246 "url": "Not info" if url.find("name") is None else url.find("name").text,
247 }
248 list_url.append(url_info)
249
250 return list_url
251
252 def get_scan_conf_data(self, host_info):
253 info_host = {
254 "host": "Not info" if host_info.find("host") is None else host_info.find("host").text,
255 "port": "Not info" if host_info.find("port") is None else host_info.find("port").text,
256 "os": "Not info" if host_info.find("operating-system") is None else host_info.find("operating-system").text,
257 "webserver": "Not info" if host_info.find("web-server") is None else host_info.find("web-server").text,
258 "appserver": "Not info" if host_info.find("application-server") is None else host_info.find("application-server").text,
259 }
260 return info_host
261
262
263 class AppScanPlugin(PluginXMLFormat):
127264 def __init__(self):
128265 super().__init__()
129266 self.identifier_tag = "xml-report"
130 self.id = "Appscan"
131 self.name = "Appscan XML Plugin"
132 self.plugin_version = "0.0.1"
267 self.id = 'Appscan'
268 self.name = 'Appscan XML Plugin'
269 self.plugin_version = '0.0.1'
270 self.version = '1.0.0'
271 self.framework_version = '1.0.0'
133272 self.options = None
134 self.open_options = {"mode": "r", "encoding": "utf-8"}
273 self.protocol = None
274 self.port = '80'
275 self.address = None
135276
136277 def parseOutputString(self, output):
137 try:
138 parser = AppscanParser(output, self.logger)
139 issues = parser.parse_issues()
140 scanned_hosts = parser.parse_hosts()
141 hosts_dict = {}
142 for host in scanned_hosts:
143 host_id = self.createAndAddHost(host['ip'], os=host['os'], hostnames=[host['hostname']])
144 service_id = self.createAndAddServiceToHost(
145 host_id,
146 host['scheme'],
147 ports=[host['port']],
148 protocol="tcp?HTTP")
149 if host['port']:
150 if host['port'] not in ('443', '80'):
151 key_url = f"{host['scheme']}://{host['hostname']}:{host['port']}"
152 else:
153 key_url = f"{host['scheme']}://{host['hostname']}"
278 parser = AppScanParser(output)
279 layout = parser.layout
280 operating_system = parser.operating_system
281 host_data = parser.host_data
282 urls = parser.urls
283 item = parser.item
284 name_scan = parser.name_scan
285 issues = parser.issue_group
286 recomendation = parser.fix_recomendation
287
288 if operating_system == 'DAST':
289 host_id = self.createAndAddHost(resolve_hostname(host_data['host']), os=host_data['os'],
290 hostnames=[host_data['host']], description=layout['details'])
291
292 service_id = self.createAndAddServiceToHost(host_id, host_data['host'], ports=host_data['port'],
293 protocol="tcp?HTTP",
294 description=f'{host_data["webserver"]} - {host_data["appserver"]}')
295 if layout['nro_issues'] is None:
296 nro_check = True
297
298 else:
299 nro_check = False
300 check_issues = []
301
302 for issue in issues:
303 id = f"{issue['url_id']}{issue['advisory']}"
304 if id in check_issues and nro_check is True:
305 check_issues.append(id)
154306 else:
155 key_url = f"{host['scheme']}://{host['hostname']}"
156 hosts_dict[key_url] = {'host_id': host_id, 'service_id': service_id}
157 for issue in issues:
158 url_parsed = urlparse(issue['url'])
159 url_string = f'{url_parsed.scheme}://{url_parsed.netloc}'
160 for key in hosts_dict:
161 if url_string == key:
162 h_id = hosts_dict[key]['host_id']
163 s_id = hosts_dict[key]['service_id']
164 refs = []
165 if "ref_link" in issue:
166 refs.append(f"Fix link: {issue['ref_link']}" )
167 if "cvss_score" in issue:
168 refs.append(f"CVSS Score: {issue['cvss_score']}")
169 if "cve" in issue:
170 refs.append(f"CVE: {issue['cve']}")
171 if "advisory" in issue:
172 refs.append(f"Advisory: {issue['advisory']}")
173 self.createAndAddVulnWebToService(
174 h_id,
175 s_id,
176 issue["name"],
177 desc=issue["issue_description"] if "issue_description" in issue else "",
178 ref=refs,
179 severity=issue["severity"],
180 resolution=issue["recomendation"],
181 website=url_parsed.netloc,
182 path=url_parsed.path,
183 request=issue["request"] if "request" in issue else "",
184 response=issue["response"] if issue["response"] else "",
185 method=issue["method"] if issue["method"] else "")
186 except Exception as e:
187 self.logger.error("Parsing Output Error: %s", e)
307 check_issues.append(id)
308 for info in name_scan:
309 if info['id'] == issue['advisory']:
310 vuln_name = info['name']
311 vuln_desc = info['description']
312 resolution = f'Text: {info["fixRecommendations"]["text"]}. ' \
313 f'Link: {info["fixRecommendations"]["link"]}'
314 vuln_data = f'xfix: {info["xfid"]} cme: {info["cwe"]}'
315
316 for url in urls:
317 if url['id'] == issue['advisory']:
318 url_name = url['url']
319 elif url['id_item'] == issue['id_item']:
320 url_name = url['url']
321 else:
322 url_name = None
323
324 for rec in recomendation:
325 if rec['id'] == issue['advisory']:
326 vuln_data = f'{vuln_data}, {rec["text"]} '
327
328 ref = f'cwe: {issue["cwe"]} cvss: {issue["cvss"]} remediation: {issue["remediation"]}'
329 self.createAndAddVulnWebToService(host_id=host_id, service_id=service_id, name=vuln_name,
330 desc=vuln_desc, severity=issue['severity'], ref=[ref],
331 website=host_data['host'], request=issue['request'],
332 response=issue['response'], method=issue['request'],
333 resolution=resolution, data=vuln_data, path=url_name)
334
335 elif operating_system == 'SAST':
336 for info_loc_source in issues:
337 source_file = info_loc_source['source_file']
338 host_id = self.createAndAddHost(source_file, os=operating_system)
339 ref = f'{info_loc_source["location"]} - {info_loc_source["line"]}'
340 for vuln_data in name_scan:
341 if vuln_data['id'] == info_loc_source["id_adv"]:
342 desc = f'desc: {vuln_data["description"]} DescMix {vuln_data["testDescriptionMixed"]}'
343 resolution = f'Fix Recomendarion {vuln_data["fixRecommendations"]}' \
344 f' - TestTecnical {vuln_data["testTechnicalDescriptionMixed"]}'
345
346 self.createAndAddVulnToHost(host_id=host_id,
347 name=vuln_data['name'],
348 desc=desc,
349 ref=[ref],
350 severity=info_loc_source['severity'],
351 resolution=resolution,
352 data=f'xfix: {vuln_data["xfid"]} cme: {vuln_data["cwe"]}',
353 run_date=None,
354 )
355 else:
356 host_id = self.createAndAddHost(layout['name'], os=operating_system)
357 for vulnserv in name_scan:
358 for sev in item:
359 if sev['id'] == vulnserv['id']:
360 info_severity = sev['severity_id']
361 if vulnserv['description'] is None:
362 desc = ""
363 else:
364 desc = vulnserv['description']
365
366 resolution = f"Text:{vulnserv['fixRecommendations']['text']}. Link: {vulnserv['fixRecommendations']['link']}."
367 self.createAndAddVulnToHost(host_id=host_id, name=vulnserv['name'], desc=desc,
368 severity=info_severity, resolution=resolution,
369 data=f'xfix: {vulnserv["xfid"]} cme: {vulnserv["cwe"]}', run_date=None)
188370
189371
190372 def createPlugin():
191 return AppscanPlugin()
192
193 # I'm Py3
373 return AppScanPlugin()
0 #!/usr/bin/env python
1 # -*- coding: utf-8 -*-
2 """
3 Faraday Penetration Test IDE
4 Copyright (C) 2016 Infobyte LLC (http://www.infobytesec.com/)
5 See the file 'doc/LICENSE' for the license information
6 """
7 from faraday_plugins.plugins.plugin import PluginXMLFormat
8 from datetime import datetime
9 try:
10 import xml.etree.cElementTree as ET
11 except ImportError:
12 import xml.etree.ElementTree as ET
13
14 __author__ = 'Blas Moyano'
15 __copyright__ = 'Copyright 2020, Faraday Project'
16 __credits__ = ['Blas Moyano']
17 __license__ = ''
18 __version__ = '1.0.0'
19 __status__ = 'Development'
20
21
22 class AppSpiderParser:
23 def __init__(self, xml_output):
24 self.tree = self.parse_xml(xml_output)
25 if self.tree:
26 self.vuln_list = self.tree.find('VulnList')
27 self.name_scan = self.tree.find('ScanName').text
28 else:
29 self.tree = None
30
31 def parse_xml(self, xml_output):
32 try:
33 tree = ET.fromstring(xml_output)
34 except SyntaxError as err:
35 print('SyntaxError In xml: %s. %s' % (err, xml_output))
36 return None
37 return tree
38
39
40 class AppSpiderPlugin(PluginXMLFormat):
41 def __init__(self):
42 super().__init__()
43 self.identifier_tag = ["VulnSummary"]
44 self.id = 'AppSpider'
45 self.name = 'AppSpider XML Output Plugin'
46 self.plugin_version = '1.0.0'
47 self.version = '1.0.0'
48 self.framework_version = '1.0.0'
49 self.options = None
50 self.protocol = None
51 self.port = '80'
52 self.address = None
53
54 def parseOutputString(self, output):
55 parser = AppSpiderParser(output)
56 websites = []
57 websites_ip = []
58
59 for vuln in parser.vuln_list:
60 websites.append(vuln.find('WebSite').text)
61 websites_ip.append(vuln.find('WebSiteIP').text)
62
63 url = set(websites)
64 ip = set(websites_ip)
65 if None in ip:
66 ip.remove(None)
67
68 host_id = self.createAndAddHost(name=sorted(list(ip))[0], hostnames=sorted(list(url)),
69 description=parser.name_scan)
70 data_info = []
71
72 for vulns in parser.vuln_list:
73 vuln_name = vulns.find('VulnType').text
74 vuln_desc = vulns.find('Description').text
75 vuln_ref = vulns.find('VulnUrl').text
76 severity = vulns.find('AttackScore').text
77 vuln_resolution = vulns.find('Recommendation').text
78 vuln_external_id = vulns.find('DbId').text
79 vuln_run_date = vulns.find('ScanDate').text
80 data_info.append(vulns.find('AttackClass').text)
81 data_info.append(vulns.find('CweId').text)
82 data_info.append(vulns.find('CAPEC').text)
83 data_info.append(vulns.find('DISSA_ASC').text)
84 data_info.append(vulns.find('OWASP2007').text)
85 data_info.append(vulns.find('OWASP2010').text)
86 data_info.append(vulns.find('OWASP2013').text)
87 data_info.append(vulns.find('OVAL').text)
88 data_info.append(vulns.find('WASC').text)
89
90 if severity == '1-Informational':
91 severity = 0
92 elif severity == '2-Low':
93 severity = 1
94 elif severity == '3-Medium':
95 severity = 2
96 elif severity == '4-High':
97 severity = 3
98 else:
99 severity = 10
100
101 str_data = f'AttackClass: {data_info[0]}, CweId: {data_info[1]}, CAPEC: {data_info[2]}, ' \
102 f'DISSA_ASC: {data_info[3]}, OWASP2007: {data_info[4]}, OWASP2010: {data_info[5]}, ' \
103 f'OWASP2013: {data_info[6]}, OVAL: {data_info[7]}, WASC: {data_info[8]}'
104
105 if vuln_run_date is None:
106 vuln_run_date = None
107 else:
108 vuln_run_date = datetime.strptime(vuln_run_date, '%Y-%m-%d %H:%M:%S')
109
110 self.createAndAddVulnToHost(host_id=host_id, name=vuln_name, desc=vuln_desc, ref=[vuln_ref],
111 severity=severity, resolution=vuln_resolution, run_date=vuln_run_date,
112 external_id=vuln_external_id, data=str_data)
113
114
115 def createPlugin():
116 return AppSpiderPlugin()
5454
5555 def getSystem(self, tree):
5656 system_tree = tree.find('system')
57 return System(system_tree)
57 if system_tree is None:
58 return System(tree, False)
59 else:
60 return System(system_tree, True)
5861
5962
6063 class Issue():
6164
6265 def __init__(self, issue_node):
63
6466 self.node = issue_node
6567 self.name = self.getDesc('name')
6668 self.severity = self.getDesc('severity')
130132 except:
131133 parameters = ''
132134
133
134135 return ' - '.join(result)
135136
136137 def getRequest(self):
160161
161162 class System():
162163
163 def __init__(self, node):
164
164 def __init__(self, node, tag_exists):
165165 self.node = node
166 self.user_agent = None
167 self.url = None
168 self.audited_elements = None
169 self.modules = ''
170 self.cookies = None
171
172 self.getOptions()
173
174 self.version = self.getDesc('version')
175 self.start_time = self.getDesc('start_datetime')
176 self.finish_time = self.getDesc('finish_datetime')
177
178 self.note = self.getNote()
166 if not tag_exists:
167 self.user_agent = 'Arachni'
168 self.url = self.getUrl()
169 self.modules = ''
170 self.version = self.node.find('version')
171 self.start_time = self.node.find('start_datetime')
172 self.finish_time = self.node.find('finish_datetime')
173 else:
174 self.user_agent = None
175 self.url = None
176 self.audited_elements = None
177 self.modules = ''
178 self.cookies = None
179 self.getOptions()
180 self.version = self.getDesc('version')
181 self.start_time = self.getDesc('start_datetime')
182 self.finish_time = self.getDesc('finish_datetime')
183
184 self.note = self.getNote()
185
186 def getUrl(self):
187 sitemap = self.node.find("sitemap/entry")
188 return sitemap.get('url')
179189
180190 def getOptions(self):
181191
182192 # Get values of options scan
183 options = self.node.find('options')
193 try:
194 options = self.node.find('options')
195 except:
196 options = False
184197 if options:
185198 options_string = options.text
186199 else:
187200 options_string = None
188201
189 self.user_agent = self.node.find('user_agent').text
202
203 try:
204 self.user_agent = self.node.find('user_agent').text
205 except:
206 self.user_agent = None
207
190208 self.url = self.node.find('url').text
191209 tags_audited_elements = self.node.find('audited_elements')
192210 element_text = []
363381 except Exception as e:
364382 self.logger.error("Error on delete file: (%s) [%s]", filename, e)
365383
366 def parseOutputString(self, output, debug=False):
384 def parseOutputString(self, output):
367385 """
368386 This method will discard the output the shell sends, it will read it
369387 from the xml where it expects it to be present.
378396 self.address = resolve_hostname(parser.plugins.ip)
379397
380398 # Create host and interface
381 host_id = self.createAndAddHost(self.address)
382
383 interface_id = self.createAndAddInterface(
399 host_id = self.createAndAddHost(self.address, hostnames=[self.hostname])
400
401 # Create service
402 service_id = self.createAndAddServiceToHost(
384403 host_id,
385 self.address,
386 ipv4_address=self.address,
387 hostname_resolution=[self.hostname])
388
389 # Create service
390 service_id = self.createAndAddServiceToInterface(
391 host_id,
392 interface_id,
393404 self.protocol,
394405 'tcp',
395406 ports=[self.port],
5353 if len(vals[0].split(".")) == 4:
5454
5555 host = vals[0]
56 h_id = self.createAndAddHost(host)
57 i_id = self.createAndAddInterface(h_id, host, ipv4_address=host, mac=vals[1])
56 h_id = self.createAndAddHost(host, mac=vals[1])
5857
5958 return True
6059
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 """
0 """
1 Faraday Penetration Test IDE
2 Copyright (C) 2020 Infobyte LLC (http://www.infobytesec.com/)
3 See the file 'doc/LICENSE' for the license information
4
5 """
6 import socket
7 import json
8 from datetime import datetime
9 import re
10 from faraday_plugins.plugins.plugin import PluginJsonFormat
11
12 __author__ = "Blas Moyano"
13 __copyright__ = "Copyright (c) 2020, Infobyte LLC"
14 __credits__ = ["Blas Moyano"]
15 __license__ = ""
16 __version__ = "0.0.1"
17 __maintainer__ = "Blas Moyano"
18 __email__ = "[email protected]"
19 __status__ = "Development"
20
21
22 class AwsProwlerJsonParser:
23
24 def __init__(self, json_output):
25 string_manipulate = json_output.replace("}", "} #")
26 string_manipulate = string_manipulate[:len(string_manipulate) - 2]
27 self.report_aws = string_manipulate.split("#")
28
29
30 class AwsProwlerPlugin(PluginJsonFormat):
31 """ Handle the AWS Prowler tool. Detects the output of the tool
32 and adds the information to Faraday.
33 """
34
35 def __init__(self):
36 super().__init__()
37 self.id = "awsprowler"
38 self.name = "AWS Prowler"
39 self.plugin_version = "0.1"
40 self.version = "0.0.1"
41 self.json_keys = set()
42
43 def report_belongs_to(self, **kwargs):
44 if super().report_belongs_to(**kwargs):
45 report_path = kwargs.get("report_path", "")
46 with open(report_path) as f:
47 output = f.readlines()
48 try:
49 for line in output:
50 check_line = json.loads(line)
51 if check_line.keys() >= {"Profile", "Account Number"}:
52 pass
53 else:
54 return False
55 except ValueError:
56 return False
57 return True
58 return False
59
60 def parseOutputString(self, output, debug=False):
61 parser = AwsProwlerJsonParser(output)
62 region_list = []
63 for region in parser.report_aws:
64 json_reg = json.loads(region)
65 region_list.append(json_reg.get('Region', 'Not Info'))
66
67 host_id = self.createAndAddHost(name=f'{self.name} - {region_list}', description="AWS Prowler")
68
69 for vuln in parser.report_aws:
70 json_vuln = json.loads(vuln)
71 vuln_name = json_vuln.get('Control', 'Not Info')
72 vuln_desc = json_vuln.get('Message', 'Not Info')
73 vuln_severity = json_vuln.get('Level', 'Not Info')
74 vuln_run_date = json_vuln.get('Timestamp', 'Not Info')
75 vuln_external_id = json_vuln.get('Control ID', 'Not Info')
76 vuln_policy = f'{vuln_name}:{vuln_external_id}'
77 vuln_run_date = vuln_run_date.replace('T', ' ')
78 vuln_run_date = vuln_run_date.replace('Z', '')
79 self.createAndAddVulnToHost(host_id=host_id, name=vuln_name, desc=vuln_desc,
80 severity=self.normalize_severity(vuln_severity),
81 run_date=datetime.strptime(vuln_run_date, '%Y-%m-%d %H:%M:%S'),
82 external_id=vuln_external_id, policyviolations=[vuln_policy])
83
84
85 def createPlugin():
86 return AwsProwlerPlugin()
3939 "Authkey", str, "c818c7798ae1da38b45a6406c8dd0d6d4d007098")
4040 self.addSetting("Enable", str, "0")
4141
42 def parseOutputString(self, output, debug=False):
42 def parseOutputString(self, output):
4343 """
4444 This method will discard the output the shell sends, it will read it from
4545 the xml where it expects it to be present.
2626 self._command_regex = re.compile(r'^(sudo brutexss|brutexss|sudo brutexss\.py|brutexss\.py|python brutexss\.py|'
2727 r'\.\/brutexss\.py)\s+.*?')
2828
29 def parseOutputString(self, output, debug=False):
29 def parseOutputString(self, output):
3030 lineas = output.split("\n")
3131 parametro = []
3232 found_vuln = False
4343 vuln_list = re.findall("\w+", linea)
4444 if vuln_list[2] == "Vulnerable":
4545 parametro.append(vuln_list[1])
46 found_vuln=len(parametro) > 0
47 host_id = self.createAndAddHost(url)
46 found_vuln = len(parametro) > 0
4847 address = resolve_hostname(url)
49 interface_id = self.createAndAddInterface(host_id, address, ipv4_address=address,
50 hostname_resolution=[url])
51 service_id = self.createAndAddServiceToInterface(host_id, interface_id, self.protocol, 'tcp',
52 ports=[port], status='Open', version="",
53 description="")
48 host_id = self.createAndAddHost(url, hostnames=[url])
49 service_id = self.createAndAddServiceToHost(host_id, self.protocol, 'tcp',
50 ports=[port], status='Open', version="",
51 description="")
5452 if found_vuln:
5553 self.createAndAddVulnWebToService(host_id, service_id, name="xss", desc="XSS", ref='', severity='med',
5654 website=url, path='', method='', pname='', params=''.join(parametro),
222222 self.target = None
223223
224224
225 def parseOutputString(self, output, debug=False):
225 def parseOutputString(self, output):
226226
227227 parser = BurpXmlParser(output)
228228 for item in parser.items:
229229
230 h_id = self.createAndAddHost(item.ip)
231
232 i_id = self.createAndAddInterface(
230 h_id = self.createAndAddHost(item.ip, hostnames=[item.host])
231 s_id = self.createAndAddServiceToHost(
233232 h_id,
234 item.ip,
235 ipv4_address=item.ip,
236 hostname_resolution=[item.host])
237
238 s_id = self.createAndAddServiceToInterface(
239 h_id,
240 i_id,
241233 item.protocol,
242234 "tcp",
243235 ports=[str(item.port)],
105105 else:
106106 port = 0
107107 project_name = 'ProjectName' in parser.cx_xml_results_attribs
108 if project_name:
109 host_id = self.createAndAddHost(url.hostname, hostnames=[url.hostname])
110 interface_id = self.createAndAddInterface(host_id, url.hostname, ipv4_address=url.hostname,
111 hostname_resolution=[url.netloc])
112 service_to_interface = self.createAndAddServiceToInterface(host_id, interface_id, name=url.scheme,
113 ports=port)
114 else:
115 host_id = self.createAndAddHost(url.hostname, hostnames=[url.hostname])
116 interface_id = self.createAndAddInterface(host_id, url.hostname, ipv4_address=url.hostname,
117 hostname_resolution=[url.netloc])
118 service_to_interface = self.createAndAddServiceToInterface(host_id, interface_id, name=url.scheme,
119 ports=port)
108 host_id = self.createAndAddHost(url.hostname, hostnames=[url.hostname, url.netloc])
109 service_to_interface = self.createAndAddServiceToHost(host_id, name=url.scheme, ports=port)
120110 for vulns in parser.query:
121111 refs = []
122112 categories = 'categories' in vulns.query_attrib
103103
104104 def createPlugin():
105105 return CobaltPlugin()
106
6666 ip_address = resolve_hostname(domain)
6767
6868 # Create host
69 host_id = self.createAndAddHost(ip_address)
70
71 # create interface (special if type "AAAA")
72 if result.get(u"type") == u"AAAA": # AAAA = IPv6 address
73 # TODO is there a function to dynamically update the paramter ipv6_address of an already-created interface?
74 ipv6_address = result.get(u"data")[0]
75 interface_id = self.createAndAddInterface(
76 host_id,
77 ip_address,
78 ipv4_address=ip_address,
79 ipv6_address=ipv6_address,
80 hostname_resolution=[domain])
81 else:
82 interface_id = self.createAndAddInterface(
83 host_id,
84 ip_address,
85 ipv4_address=ip_address,
86 hostname_resolution=[domain])
69 host_id = self.createAndAddHost(ip_address, hostnames=[domain])
8770
8871
8972 # all other TYPES that aren't 'A' and 'AAAA' are dealt here:
9174 mx_priority = result.get(u"data")[0]
9275 mx_record = result.get(u"data")[1]
9376
94 service_id = self.createAndAddServiceToInterface(
77 service_id = self.createAndAddServiceToHost(
9578 host_id=host_id,
96 interface_id=interface_id,
9779 name=mx_record,
9880 protocol="SMTP",
9981 ports=[25],
10890
10991 elif result.get(u"type") == u"NS": # Name server record
11092 ns_record = result.get(u"data")[0]
111 self.createAndAddServiceToInterface(
112 host_id=host_id,
113 interface_id=interface_id,
93 self.createAndAddServiceToHost(
11494 name=ns_record,
11595 protocol="DNS",
11696 ports=[53],
125105 upper_limit_time = result.get(u"data")[5]
126106 negative_result_ttl = result.get(u"data")[6]
127107
128 service_id = self.createAndAddServiceToInterface(
108 service_id = self.createAndAddServiceToHost(
129109 host_id=host_id,
130 interface_id=interface_id,
131110 name=ns_record,
132111 protocol="DNS",
133112 ports=[53],
8787 puerto = self.getPort(url.group(1), proto)
8888
8989 host_id = self.createAndAddHost(ip)
90 iface_id = self.createAndAddInterface(host_id, ip, ipv4_address = ip)
91
92 serv_id = self.createAndAddServiceToInterface(host_id, iface_id, proto, protocol=proto, ports=[puerto],
93 status=status)
94
90 serv_id = self.createAndAddServiceToHost(host_id, proto, protocol=proto, ports=[puerto], status=status)
9591 if len(self.text) > 0:
9692 self.createAndAddVulnWebToService(host_id, serv_id, 'Url Fuzzing', severity=0, desc=self.text,
9793 website=domain)
98
9994 if len(paths) > 0:
10095 self.createAndAddVulnWebToService(host_id, serv_id, "Directory Listing", severity="med", website=domain,
10196 request=paths, method="GET")
102
10397 return True
10498
10599 def processCommandString(self, username, current_path, command_string):
7777 try:
7878 data = json.loads(contents)
7979 except ValueError:
80 self.log('Error parsing report. Make sure the file has valid '
80 self.logger.error('Error parsing report. Make sure the file has valid '
8181 'JSON', 'ERROR')
8282 return
8383 for (base_url, items) in data.items():
8484 base_split = urlparse.urlsplit(base_url)
8585 ip = resolve_hostname(base_split.hostname)
86 h_id = self.createAndAddHost(ip)
87
88 i_id = self.createAndAddInterface(
86 h_id = self.createAndAddHost(ip, hostnames=[base_split.hostname])
87 s_id = self.createAndAddServiceToHost(
8988 h_id,
90 name=ip,
91 ipv4_address=ip,
92 hostname_resolution=[base_split.hostname])
93
94 s_id = self.createAndAddServiceToInterface(
95 h_id,
96 i_id,
9789 base_split.scheme,
9890 'tcp',
9991 [base_split.port],
163163 r'^(sudo dnsenum|dnsenum|sudo dnsenum\.pl|dnsenum\.pl|perl dnsenum\.pl|\.\/dnsenum\.pl)\s+.*?')
164164 self.xml_arg_re = re.compile(r"^.*(-o\s*[^\s]+).*$")
165165
166 def parseOutputString(self, output, debug=False):
166 def parseOutputString(self, output):
167167 """
168168 This method will discard the output the shell sends, it will read it from
169169 the xml where it expects it to be present.
175175 parser = DnsenumXmlParser(output)
176176
177177 for item in parser.items:
178 h_id = self.createAndAddHost(item.ip)
179 i_id = self.createAndAddInterface(
180 h_id,
181 item.ip,
182 ipv4_address=item.ip,
183 hostname_resolution=[item.hostname])
178 h_id = self.createAndAddHost(item.ip, hostnames=[item.hostname])
184179
185180 del parser
186181
110110 else:
111111 return False
112112
113 def parseOutputString(self, output, debug=False):
113 def parseOutputString(self, output):
114114 """
115115 This method will discard the output the shell sends, it will read it
116116 from the xml where it expects it to be present.
0 #!/usr/bin/env python
1 # -*- coding: utf-8 -*-
2
30 """
41 Faraday Penetration Test IDE
52 Copyright (C) 2013 Infobyte LLC (http://www.infobytesec.com/)
177174 hosts = list(filter(lambda h: h.type in valid_records, hosts))
178175 return hosts
179176
180 def parseOutputString(self, output, debug=False):
177 def parseOutputString(self, output):
181178 """
182179 This method will discard the output the shell sends, it will read it from
183180 the xml where it expects it to be present.
197194 elif host.type == "A":
198195 hostname = host.name
199196
200 h_id = self.createAndAddHost(host.address)
201
202 if self._isIPV4(str(host.address)):
203 i_id = self.createAndAddInterface(
197 h_id = self.createAndAddHost(host.address, hostnames=[hostname])
198 if host.type == "info":
199 s_id = self.createAndAddServiceToHost(
204200 h_id,
205 name=host.address,
206 ipv4_address=host.address,
207 hostname_resolution=[hostname])
208 else:
209 i_id = self.createAndAddInterface(
210 h_id,
211 name=host.address,
212 ipv6_address=host.address,
213 hostname_resolution=[hostname])
214
215 if host.type == "info":
216
217 s_id = self.createAndAddServiceToInterface(
218 h_id,
219 i_id,
220201 "domain",
221202 protocol="tcp",
222203 ports=["53"],
8686 else:
8787 return False
8888
89 def parseOutputString(self, output, debug=False):
89 def parseOutputString(self, output):
9090 """
9191 output is the shell output of command Dnswalk.
9292 """
9393 parser = DnswalkParser(output)
9494
9595 for item in parser.items:
96
9796 if item['type'] == "A":
98
99 h_id = self.createAndAddHost(item['ip'])
100 i_id = self.createAndAddInterface(
97 h_id = self.createAndAddHost(item['ip'], hostnames=[item['host']])
98 elif item['type'] == "info":
99 h_id = self.createAndAddHost(item['ip'], hostnames=[item['host']])
100 s_id = self.createAndAddServiceToHost(
101101 h_id,
102 item['ip'],
103 ipv4_address=item['ip'],
104 hostname_resolution=[item['host']])
105
106 elif item['type'] == "info":
107
108 h_id = self.createAndAddHost(item['ip'])
109
110 i_id = self.createAndAddInterface(
111 h_id,
112 item['ip'],
113 ipv4_address=item['ip'],
114 hostname_resolution=[item['host']])
115
116 s_id = self.createAndAddServiceToInterface(
117 h_id,
118 i_id,
119102 "domain",
120103 "tcp",
121104 ports=['53'])
122
123105 self.createAndAddVulnToService(
124106 h_id,
125107 s_id,
258258 with open(filename, **self.open_options) as output:
259259 self.parseOutputString(output)
260260
261 def parseOutputString(self, output, debug=False):
261 def parseOutputString(self, output):
262262 parser = CSVParser(output, self.logger)
263263
264264 for item in parser.items:
131131 pass
132132 return item
133133
134 def parseOutputString(self, output, debug=False):
134 def parseOutputString(self, output):
135135
136136 parser = FierceParser(output)
137137 for item in parser.items:
7373 severity=vuln_data['severity']
7474 )
7575
76 def parseOutputString(self, output, debug=False):
76 def parseOutputString(self, output):
7777 fp = FortifyParser(output)
7878 if fp.fvdl is not None:
7979 self._process_fvdl_vulns(fp)
5555 return 5
5656
5757 def createHostInterfaceVuln(self, ip_address, macaddress, hostname, desc, vuln_name, severity):
58 h_id = self.createAndAddHost(ip_address)
59 if self._isIPV4(ip_address):
60 i_id = self.createAndAddInterface(
61 h_id,
62 ip_address,
63 macaddress,
64 ipv4_address=ip_address,
65 hostname_resolution=[hostname]
66 )
67 else:
68 self.createAndAddInterface(
69 h_id, ip_address, ipv6_address=ip_address, hostname_resolution=[hostname])
58 h_id = self.createAndAddHost(ip_address, hostnames=[hostname])
7059
7160 self.createAndAddVulnToHost(
7261 h_id,
7665 severity=severity
7766 )
7867
79 def parseOutputString(self, output, debug=False):
68 def parseOutputString(self, output):
8069
8170 try:
8271 output = json.loads(output)
4343
4444
4545
46 def parseOutputString(self, output, debug=False):
46 def parseOutputString(self, output):
4747
4848 host_info = re.search(r"Connected to (.+)\.", output)
4949 banner = re.search("220?([\w\W]+)$", output)
5151 hostname = host_info.group(1)
5252 ip_address = resolve_hostname(hostname)
5353 self._version = banner.groups(0) if banner else ""
54 if debug:
55 print(ip_address)
56
57 h_id = self.createAndAddHost(ip_address)
58
59 i_id = self.createAndAddInterface(
54 h_id = self.createAndAddHost(ip_address, hostnames=[hostname])
55 s_id = self.createAndAddServiceToHost(
6056 h_id,
61 ip_address,
62 ipv4_address=ip_address,
63 hostname_resolution=[hostname])
64
65 s_id = self.createAndAddServiceToInterface(
66 h_id,
67 i_id,
6857 "ftp",
6958 "tcp",
7059 ports=[self._port],
7160 status="open")
72
73 if debug is True:
74 self.logger.info("Debug is active")
75
7661 return True
7762
7863 def processCommandString(self, username, current_path, command_string):
2828
2929 self._command_regex = re.compile(r'^(sudo hping3|hping3)\s+.*$')
3030
31 def parseOutputString(self, output, debug=False):
31 def parseOutputString(self, output):
3232
3333 regex_ipv4 = re.search(r"(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}"
3434 r"|2[0-4][0-9]|25[0-5])\)\:", output)
4040 return
4141
4242 hostname = output.split(" ")[1]
43 host_id = self.createAndAddHost(hostname)
44
45 i_id = self.createAndAddInterface(
46 host_id, ip_address, ipv4_address=ip_address, hostname_resolution=[hostname])
43 host_id = self.createAndAddHost(ip_address, hostnames=[hostname])
4744
4845 if re.match("HPING", output):
4946
5350 service = self.srv[sport.group(1)]
5451
5552 if reci.group(1) == "SA":
56 s_id = self.createAndAddServiceToInterface(
57 host_id, i_id, service, protocol="tcp", ports=ssport, status="open")
53 s_id = self.createAndAddServiceToHost(
54 host_id, service, protocol="tcp", ports=ssport, status="open")
5855
5956 lineas = output.split("\n")
6057
6663 port = [list[0]]
6764
6865 if list[2] == "S" and list[3] == "A":
69 s_id = self.createAndAddServiceToInterface(
70 host_id, i_id, service, protocol="tcp", ports=port, status="open")
66 s_id = self.createAndAddServiceToHost(
67 host_id, service, protocol="tcp", ports=port, status="open")
7168
7269
7370 def createPlugin():
33 See the file 'doc/LICENSE' for the license information
44 """
55 from faraday_plugins.plugins.plugin import PluginBase
6 from faraday_plugins.plugins.plugins_utils import resolve_hostname
67 import re
8 from collections import defaultdict
79
810 __author__ = "Francisco Amato"
911 __copyright__ = "Copyright (c) 2013, Infobyte LLC"
6062 self._temp_file_extension = "txt"
6163 self.xml_arg_re = re.compile(r"^.*(-o\s*[^\s]+).*$")
6264
63 def parseOutputString(self, output, debug=False):
65 def parseOutputString(self, output):
6466 """
6567 This method will discard the output the shell sends, it will read it from
6668 the xml where it expects it to be present.
7072 """
7173
7274 parser = HydraParser(output)
73
74 i = 0
75 hosts = {}
75 hosts = defaultdict(list)
7676 service = ''
7777 port = ''
7878
8080
8181 service = item['plugin']
8282 port = item['port']
83
84 if item['ip'] not in hosts:
85 hosts[item['ip']] = []
86
8783 hosts[item['ip']].append([item['login'], item['password']])
8884
8985 for k, v in hosts.items():
90
91 h_id = self.createAndAddHost(k)
92
93 if self._isIPV4(k):
94
95 i_id = self.createAndAddInterface(
96 h_id,
97 k,
98 ipv4_address=k)
99
86 ip = resolve_hostname(k)
87 if ip != k:
88 hostnames = [k]
10089 else:
101 i_id = self.createAndAddInterface(
102 h_id,
103 k,
104 ipv6_address=k)
105
106 s_id = self.createAndAddServiceToInterface(
90 hostnames = None
91 h_id = self.createAndAddHost(ip, hostnames=hostnames)
92 s_id = self.createAndAddServiceToHost(
10793 h_id,
108 i_id,
10994 service,
11095 ports=[port],
11196 protocol="tcp",
222222 self.framework_version = "1.0.0"
223223 self.options = None
224224
225 def parseOutputString(self, output, debug=False):
225 def parseOutputString(self, output):
226226 parser = ImpactXmlParser(output)
227227 mapped_services = {}
228228 mapped_ports = {}
229229 for item in parser.items:
230
231 h_id = self.createAndAddHost(
232 item.ip,
233 item.os + " " + item.arch)
234
235 i_id = self.createAndAddInterface(
236 h_id,
237 item.ip,
238 ipv4_address=item.ip,
239 hostname_resolution=[item.host])
230 os_string = f"{item.os} {item.arch }"
231 h_id = self.createAndAddHost(item.ip, os=os_string, hostnames=[item.host])
240232
241233 for service in item.services:
242 s_id = self.createAndAddServiceToInterface(
234 s_id = self.createAndAddServiceToHost(
243235 h_id,
244 i_id,
245236 service['name'],
246237 service['protocol'],
247238 ports=[service['port']],
281272 ref=v.ref)
282273
283274 for p in item.ports:
284 s_id = self.createAndAddServiceToInterface(
275 s_id = self.createAndAddServiceToHost(
285276 h_id,
286 i_id,
287277 p['port'],
288278 p['protocol'],
289279 ports=[p['port']],
7474 self.plugin_version = "0.0.1"
7575 self.options = None
7676
77 def parseOutputString(self, output, debug=False):
77 def parseOutputString(self, output):
7878
7979 parser = Ip360Parser(output)
8080 for host, interface, service, vulnerability in parser.parse():
81
82 h_id = self.createAndAddHost(host.get("name"), host.get("os"))
83
84 i_id = self.createAndAddInterface(
85 h_id,
86 interface.get("name"),
87 ipv4_address=interface.get("name"),
88 hostname_resolution=interface.get("hostname_resolution"),
89 network_segment=interface.get("network_segment"))
90
91
81 h_id = self.createAndAddHost(host.get("name"), host.get("os"), hostnames=interface.get("hostname_resolution"))
9282 if service.get("port") == "-":
9383 port = "0"
9484 protocol = "unknown"
9686 port = service.get("port").split("/")[0]
9787 protocol = service.get("port").split("/")[1]
9888
99 s_id = self.createAndAddServiceToInterface(
89 s_id = self.createAndAddServiceToHost(
10090 h_id,
101 i_id,
10291 service.get("port"),
10392 protocol=protocol,
10493 ports=[port])
131131 self.options = None
132132 self._current_output = None
133133
134 def parseOutputString(self, output, debug=False):
134 def parseOutputString(self, output):
135135
136136 parser = JunitXmlParser(output)
137137 for item in parser.items:
138138 h_id = self.createAndAddHost(item.host, os="Linux")
139 i_id = self.createAndAddInterface(h_id, item.host, ipv4_address=item.host)
140139 self.createAndAddVulnToHost(h_id, name=item.name, desc=item.message, ref=[], severity="High")
141140 del parser
142141
77 import os
88 import zipfile
99
10 from faraday_plugins.plugins.plugins_utils import resolve_hostname
11
1012 try:
1113 import xml.etree.cElementTree as ET
1214 import xml.etree.ElementTree as ET_ORIG
1719
1820 ETREE_VERSION = [int(i) for i in ETREE_VERSION.split(".")]
1921
20 current_path = os.path.abspath(os.getcwd())
2122
2223 __author__ = "Ezequiel Tavella"
2324 __copyright__ = "Copyright (c) 2015, Infobyte LLC"
5758
5859 if maltego_file_dns in mtgl_file.namelist():
5960 xml_dns = ET.parse(mtgl_file.open(maltego_file_dns))
60 check_files.update({"DNS": xml_dns})
61 check_files.update({"domain": xml_dns})
6162
6263 if maltego_file_domain in mtgl_file.namelist():
6364 xml_domain = ET.parse(mtgl_file.open(maltego_file_domain))
111112 def __init__(self):
112113 self.ip = ""
113114 self.node_id = ""
114 self.dns_name = ""
115 self.dns_name = set()
115116 self.website = ""
116117 self.netblock = ""
117118 self.location = ""
119120 self.ns_record = ""
120121
121122
122 class MaltegoMtgxParser():
123 class MaltegoParser():
123124
124125 def __init__(self, xml_file, extension):
125126
168169 entity = node.find(
169170 "{http://graphml.graphdrawing.org/xmlns}data/"
170171 "{http://maltego.paterva.com/xml/mtgx}MaltegoEntity")
172
173
171174 # Check if is IPv4Address
172 if entity.get("type") != "maltego.IPv4Address":
175 if entity.get("type") not in ("maltego.IPv4Address", "maltego.Domain", "maltego.Website"):
173176 return None
174177
175178 # Get IP value
177180 "{http://maltego.paterva.com/xml/mtgx}Properties/"
178181 "{http://maltego.paterva.com/xml/mtgx}Property/"
179182 "{http://maltego.paterva.com/xml/mtgx}Value")
180
181 return {"node_id": node_id, "ip": value.text}
183 if entity.get("type") in ("maltego.Domain", "maltego.Website"):
184 ip = resolve_hostname(value.text)
185 hostname = value.text
186 else:
187 ip = value.text
188 hostname = None
189 return {"node_id": node_id, "ip": ip, "hostname": hostname}
182190
183191 def getNode(self, node_id):
184192
323331 host = Host()
324332 host.ip = result.get("ip")
325333 host.node_id = result.get("node_id")
326
334 if result.get("hostname"):
335 host.dns_name.add(result.get("hostname"))
327336 # Get relations with other nodes
328337 node_relations = self.relations[host.node_id]
329338
334343 target_type = self.getType(target_node)
335344
336345 # Check type of node y add data to host...
337 if target_type == "maltego.DNSName":
338 host.dns_name = self.getValue(target_node)
346 if target_type in ("maltego.DNSName", "maltego.Domain"):
347 host.dns_name.add(self.getValue(target_node)['value'])
339348 elif target_type == "maltego.Website":
340349 host.website = self.getWebsite(target_node)
341350 elif target_type == "maltego.Netblock":
377386 "Entities/maltego.Person.entity", "Entities/maltego.PhoneNumber.entity",
378387 "Entities/maltego.Website.entity", "Entities/maltego.Hash.entity",
379388 "Entities/maltego.hashtag.entity", "Entities/maltego.TwitterUserList.entity"}
380 self.current_path = None
381 self.options = None
382 self._current_output = None
383 self._command_regex = re.compile(
384 r'^(sudo maltego|maltego|\.\/maltego).*?')
385 global current_path
386
387 def parseOutputString(self, output, debug=False):
388
389
390 def parseOutputString(self, output):
389391 if 'Graphs/Graph1.graphml' in output.namelist():
390 maltego_parser = MaltegoMtgxParser(output, self.extension[1])
391 if not maltego_parser.parse():
392 maltego_parser = MaltegoParser(output, self.extension[1])
393 hosts = maltego_parser.parse()
394 if not hosts:
395 self.logger.warning("No hosts data found in maltego report")
392396 pass
393397 else:
394 for host in maltego_parser.parse():
398 for host in hosts:
395399 if host.ip is None:
396400 ip = '0.0.0.0'
401 self.logger.warning("Unknown IP")
397402 else:
398403 ip = host.ip
399 host_id = self.createAndAddHost(name=ip)
400 # Create interface
401 try:
402 network_segment = host.netblock["ipv4_range"]
403 hostname_resolution = [host.dns_name["value"]]
404 except TypeError:
405 pass
406 network_segment = "unknown"
407 hostname_resolution = "unknown"
408 interface_id = self.createAndAddInterface(host_id=host_id, name=ip, ipv4_address=ip,
409 network_segment=network_segment,
410 hostname_resolution=[hostname_resolution])
411 # Create note with NetBlock information
412 if host.netblock:
413 try:
414 text = f'Network owner:\n {host.netblock["network_owner"]} ' \
415 f'Country:\n {host.netblock["country"]}'
416 except TypeError:
417 text = "unknown"
418
419 self.createAndAddNoteToHost(host_id=host_id, name="Netblock Information",
420 text=text.encode('ascii', 'ignore'))
421
422 # Create note with host location
423 if host.location:
424 try:
425 text = f'Location:\n {host.location["name"]} \nArea:\n {host.location["area"]} ' \
426 f'\nArea 2:\n {host.location["area_2"]} ' \
427 f'\nCountry_code:\n { host.location["country_code"]} ' \
428 f'\nLatitude:\n {host.location["latitude"]} \nLongitude:\n {host.location["longitude"]}'
429 except TypeError:
430 text = "unknown"
431
432 self.createAndAddNoteToHost(host_id=host_id, name="Location Information",
433 text=text.encode('ascii', 'ignore'))
434
435 # Create service web server
436 if host.website:
437 try:
438 description = f'SSL Enabled: {host.website["ssl_enabled"]}'
439 except TypeError:
440 description = "unknown"
441
442 service_id = self.createAndAddServiceToInterface(host_id=host_id, interface_id=interface_id,
443 name=host.website["name"], protocol="TCP:HTTP",
444 ports=[80], description=description)
445
446 try:
447 text = f'Urls: \n {host.website["urls"]}'
448 self.createAndAddNoteToService(host_id=host_id, service_id=service_id, name="URLs",
449 text=text.encode('ascii', 'ignore'))
450 except TypeError:
451 pass
452
453 if host.mx_record:
454 self.createAndAddServiceToInterface(host_id=host_id, interface_id=interface_id,
455 name=host.mx_record["value"], protocol="SMTP", ports=[25],
456 description="E-mail Server")
457
458 if host.ns_record:
459 self.createAndAddServiceToInterface(host_id=host_id, interface_id=interface_id,
460 name=host.ns_record["value"], protocol="DNS", ports=[53],
461 description="DNS Server")
404 host_id = self.createAndAddHost(ip, hostnames=list(host.dns_name))
405 # Create note with NetBlock information
406 if host.netblock:
407 try:
408 text = f'Network owner:\n {host.netblock["network_owner"]} ' \
409 f'Country:\n {host.netblock["country"]}'
410 except TypeError:
411 text = "unknown"
412
413 self.createAndAddNoteToHost(host_id=host_id, name="Netblock Information",
414 text=text.encode('ascii', 'ignore'))
415
416 # Create note with host location
417 if host.location:
418 try:
419 text = f'Location:\n {host.location["name"]} \nArea:\n {host.location["area"]} ' \
420 f'\nArea 2:\n {host.location["area_2"]} ' \
421 f'\nCountry_code:\n { host.location["country_code"]} ' \
422 f'\nLatitude:\n {host.location["latitude"]} \nLongitude:\n {host.location["longitude"]}'
423 except TypeError:
424 text = "unknown"
425
426 self.createAndAddNoteToHost(host_id=host_id, name="Location Information",
427 text=text.encode('ascii', 'ignore'))
428
429 # Create service web server
430 if host.website:
431 try:
432 description = f'SSL Enabled: {host.website["ssl_enabled"]}'
433 except TypeError:
434 description = "unknown"
435
436 service_id = self.createAndAddServiceToHost(host_id=host_id, name=host.website["name"],
437 protocol="TCP:HTTP", ports=[80],
438 description=description)
439
440 try:
441 text = f'Urls: \n {host.website["urls"]}'
442 self.createAndAddNoteToService(host_id=host_id, service_id=service_id, name="URLs",
443 text=text.encode('ascii', 'ignore'))
444 except TypeError:
445 pass
446
447 if host.mx_record:
448 self.createAndAddServiceToHost(host_id=host_id, name=host.mx_record["value"], protocol="SMTP",
449 ports=[25], description="E-mail Server")
450
451 if host.ns_record:
452 self.createAndAddServiceToHost(host_id=host_id, name=host.ns_record["value"], protocol="DNS",
453 ports=[53], description="DNS Server")
462454 else:
463 maltego_parser = MaltegoMtgxParser(output, self.extension[0])
455 maltego_parser = MaltegoParser(output, self.extension[0])
456 if not maltego_parser.xml.get('domain') or not maltego_parser.xml.get('ipv4'):
457 return
458 if maltego_parser.xml.get('domain'):
459 hostnames = maltego_parser.getInfoMtgl(maltego_parser.xml['domain'], 'fqdn')
460 else:
461 hostnames = None
464462 if maltego_parser.xml.get('ipv4'):
465463 host_ip = maltego_parser.getInfoMtgl(maltego_parser.xml['ipv4'], 'ipv4-address')
466 host_id = self.createAndAddHost(name=host_ip)
464 host_id = self.createAndAddHost(name=host_ip, hostnames=hostnames)
467465 else:
468 host_id = self.createAndAddHost(name=self.name)
469466 host_ip = '0.0.0.0'
470
471 if maltego_parser.xml.get('DNS'):
472 hostname_resolution = maltego_parser.getInfoMtgl(maltego_parser.xml['DNS'], 'fqdn')
473 interface_id = self.createAndAddInterface(host_id=host_id, name=host_ip, ipv4_address=host_ip,
474 hostname_resolution=[hostname_resolution])
475 else:
476 interface_id = self.createAndAddInterface(host_id=host_id, name=host_ip, ipv4_address=host_ip)
467 host_id = self.createAndAddHost(name=host_ip, hostnames=hostnames)
468
477469
478470 if maltego_parser.xml.get('location'):
479471 location_name = maltego_parser.getInfoMtgl(maltego_parser.xml['location'], 'location.name')
499491 web_ssh = maltego_parser.getInfoMtgl(maltego_parser.xml['web'], 'website.ssl-enabled')
500492 description = f'SSL Enabled: {web_ssh}'
501493
502 service_id = self.createAndAddServiceToInterface(host_id=host_id, interface_id=interface_id,
503 name=web_name, protocol="TCP:HTTP", ports=web_port,
504 description=description)
494 service_id = self.createAndAddServiceToHost(host_id=host_id, name=web_name, protocol="TCP:HTTP",
495 ports=web_port, description=description)
505496
506497 self.createAndAddNoteToService(host_id=host_id, service_id=service_id, name="URLs",
507498 text=text.encode('ascii', 'ignore'))
509500 if maltego_parser.xml.get('mxrecord'):
510501 mx_name = maltego_parser.getInfoMtgl(maltego_parser.xml['mxrecord'], 'fqdn')
511502
512 self.createAndAddServiceToInterface(host_id=host_id, interface_id=interface_id, name=mx_name,
513 protocol="SMTP", ports=[25], description="E-mail Server")
503 self.createAndAddServiceToHost(host_id=host_id, name=mx_name, protocol="SMTP", ports=[25],
504 description="E-mail Server")
514505
515506 if maltego_parser.xml.get('nsrecord'):
516507 ns_name = maltego_parser.getInfoMtgl(maltego_parser.xml['nsrecord'], 'fqdn')
517 self.createAndAddServiceToInterface(host_id=host_id, interface_id=interface_id, name=ns_name,
518 protocol="DNS", ports=[53], description="DNS Server")
508 self.createAndAddServiceToHost(host_id=host_id, name=ns_name, protocol="DNS", ports=[53],
509 description="DNS Server")
519510
520511
521512
8484
8585 for item in parser.items:
8686
87 h_id = self.createAndAddHost(item['ip'])
88 if self._isIPV4(item['ip']):
89 i_id = self.createAndAddInterface(
90 h_id,
91 item['ip'],
92 ipv4_address=item['ip'],
93 hostname_resolution=[item['host']])
94 else:
95 i_id = self.createAndAddInterface(
96 h_id,
97 item['ip'],
98 ipv6_address=item['ip'],
99 hostname_resolution=[item['host']])
87 h_id = self.createAndAddHost(item['ip'], hostnames=[item['host']])
10088
10189 port = self.port if self.port else item['port']
10290
103 s_id = self.createAndAddServiceToInterface(
91 s_id = self.createAndAddServiceToHost(
10492 h_id,
105 i_id,
10693 item['service'],
10794 ports=[port],
10895 protocol="tcp",
336336 self.target = None
337337
338338
339 def parseOutputString(self, output, debug=False):
339 def parseOutputString(self, output):
340340 """
341341 This method will discard the output the shell sends, it will read it from
342342 the xml where it expects it to be present.
343
344 NOTE: if 'debug' is true then it is being run from a test case and the
345 output being sent is valid.
346343 """
347344
348345 parser = MetasploitXmlParser(output)
116116 self.version = "1.0.0"
117117 self._command_regex = re.compile(r'^(sudo ndiff|ndiff)\s+.*?')
118118
119 def parseOutputString(self, output, debug=False):
119 def parseOutputString(self, output):
120120 parser = NdiffXmlParser(output)
121121 for host in parser.hostDiff:
122122 if host.ip is None:
4444
4545 def getPolicy(self, tree):
4646 policy_tree = tree.find('Policy')
47 return Policy(policy_tree)
47 if policy_tree:
48 return Policy(policy_tree)
49 else:
50 return None
4851
4952 def getReport(self, tree):
5053 report_tree = tree.find('Report')
190193 """
191194 try:
192195 parser = NessusParser(output)
193 except:
196 except Exception as e:
197 print(e)
194198 return None
195199
196200 if parser.report.report_json is not None:
220224 host_name = None
221225
222226 host_id = self.createAndAddHost(ip_host, os=os, hostnames=host_name, mac=mac)
223
224 interface_id = self.createAndAddInterface(host_id, ip, ipv6_address=ip, mac=mac)
225227 cve = []
226228 for serv in parser.report.report_json['serv'][set_info -1]:
227229 serv_name = serv[1]
266268 ref = []
267269
268270 policyviolations = []
271 tags_info = None
269272 if serv[6] == 'Policy Compliance':
270273 # This condition was added to support CIS Benchmark in policy violation field.
271274 risk_factor = 'info'
275 tags_info = "Passed Checks"
272276 bis_benchmark_data = serv[7].split('\n')
273277 policy_item = bis_benchmark_data[0]
274278
277281 ref.append(policy_check_data)
278282
279283 if 'FAILED' in policy_item:
280 risk_factor = 'high'
284 risk_factor = 'low'
285 tags_info = "Failed checks"
281286 policyviolations.append(policy_item)
282287
283288 vulnerability_name = f'{serv[6]} {vulnerability_name} {policy_item}'
284
285289 self.createAndAddVulnToHost(host_id,
286290 vulnerability_name,
287291 desc=desc,
291295 ref=ref,
292296 policyviolations=policyviolations,
293297 external_id=external_id,
294 run_date=run_date)
298 run_date=run_date,
299 tags=tags_info)
295300 else:
296301 data = serv[9]
297302 if not data:
331336 if 'xref' in data:
332337 ref.append(data['xref'])
333338
334 service_id = self.createAndAddServiceToInterface(host_id,
335 interface_id,
336 name=serv_name,
337 protocol=serv_protocol,
338 ports=serv_port)
339 service_id = self.createAndAddServiceToHost(host_id, name=serv_name, protocol=serv_protocol,
340 ports=serv_port)
339341
340342 if serv_name == 'www' or serv_name == 'http':
341343 self.createAndAddVulnWebToService(host_id,
362364 run_date=run_date)
363365 else:
364366 ip = '0.0.0.0'
365 host_id = self.createAndAddHost(ip, hostnames="Not Information")
366 interface_id = self.createAndAddInterface(host_id, ip)
367 service_id = self.createAndAddServiceToInterface(host_id, interface_id, name="Not Information")
368 self.createAndAddVulnToService(host_id,
369 service_id,
370 name=parser.policy.policy_name,
371 desc="No Description")
367 host_id = self.createAndAddHost(ip, hostnames=None)
368 service_id = self.createAndAddServiceToHost(host_id,name="Not Information")
369 self.createAndAddVulnToService(host_id, service_id, name=parser.policy.policy_name, desc="No Description")
372370
373371
374372 def createPlugin():
3333 ip_address = stdout[0]
3434 mac = stdout[2]
3535 hostname = stdout[6].strip()
36
37 h_id = self.createAndAddHost(ip_address)
38 self.createAndAddInterface(h_id, ip_address, ipv4_address=ip_address, mac=mac, hostname_resolution=[hostname])
39
36 h_id = self.createAndAddHost(ip_address, hostnames=[hostname])
4037 return True
4138
4239
6161 try:
6262 tree = ET.fromstring(xml_output)
6363 except SyntaxError as err:
64 self.devlog("SyntaxError: %s. %s" % (err, xml_output))
64 self.logger.error("SyntaxError: %s. %s" % (err, xml_output))
6565 return None
6666
6767 return tree
7070 try:
7171 tree = ET.fromstring(xml_output)
7272 except SyntaxError as err:
73 self.devlog("SyntaxError: %s. %s" % (err, xml_output))
73 self.logger.error("SyntaxError: %s. %s" % (err, xml_output))
7474 return None
7575 return tree
7676
189189 self.framework_version = "1.0.0"
190190 self.options = None
191191
192 def parseOutputString(self, output, debug=False):
192 def parseOutputString(self, output):
193193 parser = NetsparkerCloudXmlParser(output)
194194 first = True
195195 for i in parser.items:
196196 if first:
197197 ip = resolve_hostname(i.hostname)
198 h_id = self.createAndAddHost(ip)
199 i_id = self.createAndAddInterface(h_id, ip, ipv4_address=ip, hostname_resolution=[i.hostname])
200 s_id = self.createAndAddServiceToInterface(h_id, i_id, i.protocol, ports=[i.port], status="open")
201
198 h_id = self.createAndAddHost(ip, hostnames=[i.hostname])
199 s_id = self.createAndAddServiceToHost(h_id, i.protocol, ports=[i.port], status="open")
202200 first = False
203201 v_id = self.createAndAddVulnWebToService(h_id, s_id, i.name, ref=i.ref, website=i.hostname,
204202 severity=i.severity, desc=i.desc, path=i.url.path, method=i.method,
258258 self.framework_version = "1.0.0"
259259 self.options = None
260260
261 def parseOutputString(self, output, debug=False):
261 def parseOutputString(self, output):
262262
263263 parser = NexposeFullXmlParser(output)
264264
265265 for item in parser.items:
266 h_id = self.createAndAddHost(item['name'], item['os'], hostnames=item['hostnames'])
267266 pattern = '([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$'
268267 if not item['mac']:
269268 item['mac'] = '0000000000000000'
270 match = re.search(pattern, item['mac'])
269 match = re.search(pattern, item['mac'])
270 if match:
271 mac = item['mac']
271272 else:
272 match = re.search(pattern, item['mac'])
273 if match:
274 i_id = self.createAndAddInterface(
275 h_id,
276 item['name'],
277 mac=item['mac'],
278 ipv4_address=item['name'],
279 hostname_resolution=item['hostnames']
280 )
281 else:
282 i_id = self.createAndAddInterface(
283 h_id,
284 item['name'],
285 mac=':'.join(item['mac'][i:i + 2] for i in range(0, 12, 2)),
286 ipv4_address=item['name'],
287 hostname_resolution=item['hostnames'])
288
273 mac = ':'.join(item['mac'][i:i + 2] for i in range(0, 12, 2))
274 h_id = self.createAndAddHost(item['name'], item['os'], hostnames=item['hostnames'], mac=mac)
289275 for v in item['vulns']:
290276 v['data'] = {"vulnerable_since": v['vulnerable_since'], "scan_id": v['scan_id'], "PCI": v['pci']}
291277 v_id = self.createAndAddVulnToHost(
300286 for s in item['services']:
301287 web = False
302288 version = s.get("version", "")
303
304 s_id = self.createAndAddServiceToInterface(
289 s_id = self.createAndAddServiceToHost(
305290 h_id,
306 i_id,
307291 s['name'],
308292 s['protocol'],
309293 ports=[str(s['port'])],
302302
303303
304304
305 def parseOutputString(self, output, debug=False):
305 def parseOutputString(self, output):
306306 """
307307 This method will discard the output the shell sends, it will read it from
308308 the xml where it expects it to be present.
44
55 """
66
7 from faraday_plugins.plugins.plugin import PluginXMLFormat
87 import re
98 import os
10
9 from io import BytesIO
1110
1211 try:
1312 import xml.etree.cElementTree as ET
1615 except ImportError:
1716 import xml.etree.ElementTree as ET
1817 ETREE_VERSION = ET.VERSION
18 from lxml import etree
19 from lxml.etree import XMLParser
20 from faraday_plugins.plugins.plugin import PluginXMLFormat
1921
2022 ETREE_VERSION = [int(i) for i in ETREE_VERSION.split(".")]
21
2223 current_path = os.path.abspath(os.getcwd())
24
2325
2426
2527 class NmapXmlParser:
5456 """
5557
5658 try:
57 return ET.fromstring(xml_output)
59 magical_parser = XMLParser(recover=True)
60 return etree.parse(BytesIO(xml_output), magical_parser)
5861 except SyntaxError as err:
5962 #logger.error("SyntaxError: %s." % (err))
6063 return None
443446 self.xml_arg_re = re.compile(r"^.*(-oX\s*[^\s]+).*$")
444447 self.addSetting("Scan Technique", str, "-sS")
445448
446 def parseOutputString(self, output, debug=False):
449 def parseOutputString(self, output):
447450 """
448451 This method will discard the output the shell sends, it will read it
449452 from the xml where it expects it to be present.
463466
464467 if host.ipv4_address != 'unknown':
465468 minterfase = host.ipv4_address
466 h_id = self.createAndAddHost(minterfase, host.os)
467 i_id = self.createAndAddInterface(
468 h_id,
469 minterfase,
470 host.mac_address,
471 ipv4_address=host.ipv4_address,
472 hostname_resolution=host.hostnames)
473469 else:
474470 minterfase = host.ipv6_address
475 h_id = self.createAndAddHost(minterfase, host.os)
476 i_id = self.createAndAddInterface(
477 h_id,
478 minterfase,
479 host.mac_address,
480 ipv6_address=host.ipv6_address,
481 hostname_resolution=host.hostnames)
471 h_id = self.createAndAddHost(minterfase, host.os, mac=host.mac_address, hostnames=host.hostnames)
482472
483473 for v in host.vulns:
484474 desc = v.desc
501491 srvversion = port.service.product if port.service.product != "unknown" else ""
502492 srvversion += " " + port.service.version if port.service.version != "unknown" else ""
503493
504 s_id = self.createAndAddServiceToInterface(
494 s_id = self.createAndAddServiceToHost(
505495 h_id,
506 i_id,
507496 srvname,
508497 port.protocol,
509498 ports=[port.number],
334334 report_path = kwargs.get("report_path", "")
335335 with open(report_path) as f:
336336 output = f.read()
337 return re.search("OpenVAS", output) is not None or re.search('<omp>', output) is not None
337 return re.search("OpenVAS", output) is not None \
338 or re.search('<omp>', output) is not None\
339 or re.search('<owner>', output) is not None
338340 return False
339341
340 def parseOutputString(self, output, debug=False):
342 def parseOutputString(self, output):
341343 """
342344 This method will discard the output the shell sends, it will read it
343345 from the xml where it expects it to be present.
344
345 NOTE: if 'debug' is true then it is being run from a test case and the
346 output being sent is valid.
347346 """
348347 parser = OpenvasXmlParser(output, self.logger)
349348 web = False
443442 else:
444443 return False
445444
446
447445 def setHost(self):
448446 pass
449447
4444 return
4545 # Configuration initial.
4646 hostId = self.createAndAddHost("pasteAnalyzer")
47 interfaceId = self.createAndAddInterface(hostId, "Results")
48 serviceId = self.createAndAddServiceToInterface(
47 serviceId = self.createAndAddServiceToHost(
4948 hostId,
50 interfaceId,
5149 "Web",
5250 "TcpHTTP",
5351 ['80']
5050 url_parsed = urlparse(url)
5151 address = resolve_hostname(url_parsed.netloc)
5252 host = self.createAndAddHost(address)
53 iface = self.createAndAddInterface(
54 host, address, ipv4_address=address)
55 service = self.createAndAddServiceToInterface(host, iface, "http", protocol="tcp", ports=[80])
53 service = self.createAndAddServiceToHost(host, "http", protocol="tcp", ports=[80])
5654 self.createAndAddNoteToService(
5755 host,
5856 service,
3030 self.version = "1.0.0"
3131 self._command_regex = re.compile(r'^(sudo ping|ping|sudo ping6|ping6)\s+.*?')
3232
33 def parseOutputString(self, output, debug=False):
33 def parseOutputString(self, output):
3434
3535 reg = re.search(r"PING ([\w\.-:]+)( |)\(([\w\.:]+)\)", output)
3636 if re.search("0 received|unknown host", output) is None and reg is not None:
3737
3838 ip_address = reg.group(3)
3939 hostname = reg.group(1)
40
41 h_id = self.createAndAddHost(ip_address)
42 if self._isIPV4(ip_address):
43 i_id = self.createAndAddInterface(
44 h_id, ip_address, ipv4_address=ip_address, hostname_resolution=[hostname])
45 else:
46 self.createAndAddInterface(
47 h_id, ip_address, ipv6_address=ip_address, hostname_resolution=[hostname])
48
40 h_id = self.createAndAddHost(ip_address, hostnames=[hostname])
4941 return True
5042
5143 def _isIPV4(self, ip):
3737 self._host_ip = None
3838 self._port = "23"
3939
40 def parseOutputString(self, output, debug=False):
40 def parseOutputString(self, output):
4141
4242 host_info = re.search(
4343 r"(\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b)", output)
4848 for host in output.splitlines():
4949 if host != "":
5050 h_id = self.createAndAddHost(host)
51 i_id = self.createAndAddInterface(
52 h_id, host, ipv4_address=host)
53 s_id = self.createAndAddServiceToInterface(h_id, i_id, str(self._port),
54 "tcp",
55 ports=[self._port],
56 status="open",
57 version="",
58 description="")
59 if debug is True:
60 self.logger.info("Debug is active")
61
51 s_id = self.createAndAddServiceToHost(h_id, str(self._port), "tcp", ports=[self._port],
52 status="open", version="", description="")
6253 return True
6354
6455 def processCommandString(self, username, current_path, command_string):
345345 self.options = None
346346 self.open_options = {"mode": "r", "encoding": "utf-8"}
347347
348 def parseOutputString(self, output, debug=False):
348 def parseOutputString(self, output):
349349
350350 parser = QualysguardXmlParser(output)
351351
5454 for self.results_tags in tree.find('VULNERABILITY_LIST'):
5555 yield Results(self.results_tags)
5656
57
5758 class Appendix():
5859 def __init__(self, appendix_tags):
5960 if appendix_tags.tag == 'SCAN_LIST':
6061 self.lista_scan = self.get_scan(appendix_tags.find('SCAN'))
62
6163 elif appendix_tags.tag == 'WEBAPP':
6264 self.lista_webapp = self.get_webapp(appendix_tags)
6365
123125 for host_create in parser.info_appendix:
124126 self.scan_list_result.append(host_create)
125127
126 self.credential = self.scan_list_result[0].lista_scan.get('AUTHENTICATION_RECORD')
127 os = self.scan_list_result[1].lista_webapp.get('OPERATING_SYSTEM')
128
129 if self.scan_list_result[1].lista_webapp.get('URL'):
130 initial_url = self.scan_list_result[1].lista_webapp.get('URL')
131 parsed_url = urlparse(initial_url)
132 hostnames = [parsed_url.netloc]
128 for k in self.scan_list_result:
129 if 'result_scan' in k.__dict__:
130 self.credential = k.lista_scan.get('AUTHENTICATION_RECORD')
131 elif 'result_webapp' in k.__dict__:
132 operating_system = k.lista_webapp.get('OPERATING_SYSTEM')
133 if k.lista_webapp.get('URL'):
134 initial_url = k.lista_webapp.get('URL')
135 parsed_url = urlparse(initial_url)
136 hostnames = [parsed_url.netloc]
133137
134138 glossary = []
135139 for glossary_qid in parser.info_glossary:
138142 for v in parser.info_results:
139143 url = urlparse(v.dict_result_vul.get('URL'))
140144
141 host_id = self.createAndAddHost(name=url.netloc, os=os, hostnames=hostnames)
145 host_id = self.createAndAddHost(name=url.netloc, os=operating_system, hostnames=hostnames)
142146
143147 vuln_scan_id = v.dict_result_vul.get('QID')
144148
150154 raw_severity = int(vuln_data.get('SEVERITY', 0))
151155 vuln_severity = raw_severity - 1
152156
153 run_date = parse(v.dict_result_vul.get('FIRST_TIME_DETECTED'))
157 if not v.dict_result_vul.get('FIRST_TIME_DETECTED'):
158 run_date = ''
159 else:
160 run_date = parse(v.dict_result_vul.get('FIRST_TIME_DETECTED'))
161
154162 vuln_resolution = vuln_data.get('SOLUTION')
155163
156164 vuln_ref = []
0 import re
1 from collections import defaultdict
2
3 from faraday_plugins.plugins.plugin import PluginBase
4 from faraday_plugins.plugins.plugins_utils import resolve_hostname
5
6
7 class RDPScanPlugin(PluginBase):
8
9 def __init__(self):
10 super().__init__()
11 self.identifier_tag = "rdpscan"
12 self.id = "rdpscan"
13 self.name = "rdpscan"
14 self._command_regex = re.compile(r'^(sudo rdpscan|rdpscan|\.\/rdpscan)\s+.*?')
15
16 def parseOutputString(self, output):
17 services = defaultdict(set)
18 for info in output.split('\n'):
19 if info:
20 ip, status, data = info.split('-', 2)
21 ip = ip.strip()
22 status = status.strip()
23 data = data.strip()
24 if status.lower() == 'unknown':
25 continue
26
27 host_id = self.createAndAddHost(ip)
28 service_id = self.createAndAddServiceToHost(
29 host_id=host_id,
30 name='rdp',
31 ports=3389,
32 protocol='tcp',
33 )
34 if status.lower() == 'vulnerable':
35 description = "A remote code execution vulnerability exists in Remote Desktop Services formerly known as Terminal Services when an unauthenticated attacker connects to the target system using RDP and sends specially crafted requests, aka 'Remote Desktop Services Remote Code Execution Vulnerability'. "
36 self.createAndAddVulnToService(
37 host_id=host_id,
38 service_id=service_id,
39 name='Remote Desktop Services Remote Code Execution Vulnerability',
40 desc=description,
41 ref=['CVE-2019-0708']
42 )
43
44
45 def createPlugin():
46 return RDPScanPlugin()
182182 self.options = None
183183
184184
185 def parseOutputString(self, output, debug=False):
185 def parseOutputString(self, output):
186186
187187 parser = RetinaXmlParser(output)
188188 for item in parser.items:
189 h_id = self.createAndAddHost(item.ip, item.os)
190 hostname = item.hostname if item.hostname else item.ip
191 i_id = self.createAndAddInterface(
192 h_id, item.ip, ipv4_address=item.ip, hostname_resolution=[hostname])
189 hostname = item.hostname if item.hostname else None
190 h_id = self.createAndAddHost(item.ip, item.os,hostnames=[hostname])
193191
194192 if not item.netbiosname == 'N/A':
195193 self.createAndAddNoteToHost(
203201 if k:
204202 for v in vulns:
205203 web = False
206 s_id = self.createAndAddServiceToInterface(h_id, i_id, 'unknown',
207 v.protocol.lower(),
208 ports=[str(v.port)],
209 status="open")
204 s_id = self.createAndAddServiceToHost(h_id, 'unknown', v.protocol.lower(), ports=[str(v.port)],
205 status="open")
210206 if v.port in ['80', '443'] or re.search("ssl|http", v.name.lower()):
211207 web = True
212208 else:
7373 parser = ReverseraiderParser(output)
7474 for item in parser.items:
7575 h_id = self.createAndAddHost(item['ip'])
76 i_id = self.createAndAddInterface(h_id, item['ip'], ipv4_address=item['ip'])
7776 del parser
7877
7978
165165
166166 ip = resolve_hostname(host)
167167
168 h_id = self.createAndAddHost(ip)
169 i_id = self.createAndAddInterface(
170 h_id,
171 ip,
172 ipv4_address=ip,
173 hostname_resolution=[host])
174
175 s_id = self.createAndAddServiceToInterface(
176 h_id,
177 i_id,
178 "http",
179 "tcp",
180 ports=[port],
181 status="open")
168 h_id = self.createAndAddHost(ip, hostnames=[host])
169 s_id = self.createAndAddServiceToHost(h_id, "http", "tcp", ports=[port], status="open")
182170
183171 hostc[sample["url"]] = {
184172 'h_id': h_id,
186174 'port': port,
187175 'host': host,
188176 'protocol': protocol,
189 'i_id': i_id,
190177 's_id': s_id}
191178
192179 try:
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 # I'm Py3
0 """
1 Faraday Penetration Test IDE
2 Copyright (C) 2019 Infobyte LLC (http://www.infobytesec.com/)
3 See the file 'doc/LICENSE' for the license information
4
5 """
6 import json
7 from faraday_plugins.plugins.plugin import PluginJsonFormat
8 from urllib.parse import urlparse
9 import os
10
11
12 __author__ = "Blas Moyano"
13 __copyright__ = "Copyright (c) 2019, Infobyte LLC"
14 __credits__ = ["Blas Moyano"]
15 __license__ = ""
16 __version__ = "0.0.1"
17 __maintainer__ = "Blas Moyano"
18 __email__ = "[email protected]"
19 __status__ = "Development"
20
21
22 class SourceclearJsonParser:
23 def __init__(self, json_output):
24 self.json_data = json.loads(json_output)
25
26 def parse_url(self, url):
27 url_parse = urlparse(url)
28 protocol = url_parse.scheme
29 hostname = url_parse.netloc
30 port = url_parse.port
31
32 if port is None:
33 if protocol == 'https':
34 port = 443
35 elif protocol == 'http':
36 if not port:
37 port = 80
38
39 return {'protocol': protocol, 'hostname': hostname, 'port': port}
40
41
42 class SourceclearPlugin(PluginJsonFormat):
43 """ Handle the Sourceclear tool. Detects the output of the tool
44 and adds the information to Faraday.
45 """
46
47 def __init__(self):
48 super().__init__()
49 self.id = "sourceclear"
50 self.name = "Sourceclear"
51 self.plugin_version = "0.1"
52 self.version = "0.0.1"
53 self.json_keys = {"metadata", "records"}
54
55 def parseOutputString(self, output, debug=False):
56 parser = SourceclearJsonParser(output)
57
58 for records in parser.json_data['records']:
59 vulns = records['vulnerabilities']
60 libraries = records['libraries']
61
62 for vuln in vulns:
63 v_name = vuln['title']
64 v_desc = vuln['overview']
65 v_ref = "CVSS: {}".format(vuln['cvssScore'])
66 v_data = vuln['libraries']
67 v_website = vuln['_links']['html']
68 url_data = parser.parse_url(v_website)
69 for refs in vuln['libraries']:
70 ref = refs['_links']['ref']
71 num_versions = ref.find("/versions")
72 _, num_libraries = os.path.split(ref[:num_versions])
73 name_librarie = libraries[int(num_libraries)]['name']
74 version_librarie = libraries[int(num_libraries)]['versions'][0]['version']
75 host_name = f'{name_librarie}{version_librarie}'
76
77 h_id = self.createAndAddHost(name=host_name, scan_template=records['metadata']['recordType'])
78 s_id = self.createAndAddServiceToHost(h_id, "Sourceclear", protocol=url_data['protocol'],
79 ports=url_data['port'], status='open')
80 self.createAndAddVulnWebToService(h_id, s_id, name=v_name, desc=v_desc, ref=[v_ref], data=v_data,
81 website=v_website)
82
83
84 def createPlugin():
85 return SourceclearPlugin()
3838 if output_rexeg_match:
3939 credentials, address = line.split("@")
4040 host = self.createAndAddHost(address)
41 iface = self.createAndAddInterface(
42 host, address, ipv4_address=address)
43 service = self.createAndAddServiceToInterface(
44 host, iface, "ssh", protocol="tcp", ports=[22]
45 )
41 service = self.createAndAddServiceToHost(host, "ssh", protocol="tcp", ports=[22])
4642 username, password = credentials.split(":")
4743 cred = self.createAndAddCredToService(
4844 host, service, username, password)
0 """
1 Faraday Penetration Test IDE
2 Copyright (C) 2020 Infobyte LLC (http://www.infobytesec.com/)
3 See the file 'doc/LICENSE' for the license information
4
5 """
6 import re
7 import json
8 from urllib.parse import urlparse
9 from faraday_plugins.plugins.plugin import PluginJsonFormat
10 from faraday_plugins.plugins.plugins_utils import resolve_hostname
11
12 __author__ = "Blas Moyano"
13 __copyright__ = "Copyright (c) 2020, Infobyte LLC"
14 __credits__ = ["Blas Moyano"]
15 __license__ = ""
16 __version__ = "0.0.1"
17 __maintainer__ = "Blas Moyano"
18 __email__ = "[email protected]"
19 __status__ = "Development"
20
21
22 class SslLabsJsonParser:
23
24 def __init__(self, json_output):
25 list_data = json.loads(json_output)
26 self.json_data = list_data[0]
27
28 def host_info(self, data):
29 host_information = {
30 "url": data.get('host', 'Not Info'),
31 "description_host": "SSL Labs",
32 "port": data.get('port', 0),
33 "protocol": data.get('protocol', 'Not Info'),
34 "status": data.get('status', 'Not Info'),
35 "version": data.get('engineVersion', '0.0.0'),
36 "run_date": data.get('startTime', 'Not Info')
37 }
38 return host_information
39
40 def get_ip(self, data):
41 for ip in data:
42 return ip.get('ipAddress', '0.0.0.0')
43
44 def get_vulns(self, data):
45 chain = data.get('chain', None)
46 vuln_list = []
47 policies_list = [data.get('hstsPolicy', 'No Information'),
48 data.get('hpkpPolicy', 'No Information'),
49 data.get('hpkpRoPolicy', 'No Information')]
50
51 for vulns in chain['certs']:
52 vuln = {
53 "name": vulns.get('issuerLabel', 'No Information'),
54 "desc": vulns.get('issuerSubject', 'No Information'),
55 "data": f'SHA1HASH: {vulns.get("sha1Hash", "No Information")}'
56 f'PINSHA256: {vulns.get("pinSha256", "No Information")}'
57 f'RAW: {vulns.get("raw", "No Information")}',
58 "policy": policies_list
59 }
60 vuln_list.append(vuln)
61 return vuln_list
62
63
64 class SslLabsPlugin(PluginJsonFormat):
65 """ Handle the SSL Labs tool. Detects the output of the tool
66 and adds the information to Faraday.
67 """
68
69 def __init__(self):
70 super().__init__()
71 self.id = "ssllabs"
72 self.name = "SSL Labs"
73 self.plugin_version = "0.1"
74 self.version = "3.4.5"
75 self.json_keys = set()
76
77 def report_belongs_to(self, **kwargs):
78 result = False
79 if super().report_belongs_to(**kwargs):
80 report_path = kwargs.get("report_path", "")
81 with open(report_path) as f:
82 output = f.readlines()
83 for line in output:
84 check = line.find('"criteriaVersion":')
85 if check > 0:
86 result = True
87 return result
88
89 def parseOutputString(self, output):
90 parser = SslLabsJsonParser(output)
91 host = parser.host_info(parser.json_data)
92
93 host_id = self.createAndAddHost(
94 name=parser.get_ip(parser.json_data['endpoints']),
95 hostnames=[host['url']],
96 description=host['description_host'])
97
98 service_id = self.createAndAddServiceToHost(
99 host_id=host_id,
100 name=host['url'],
101 protocol=host['protocol'],
102 ports=host['port'],
103 status=host['status'],
104 version=host['version'])
105
106 vulns = parser.get_vulns(parser.json_data['endpoints'][0]['details'])
107
108 for vuln in vulns:
109 policy_info = f"Long max age: {vuln['policy'][0]['LONG_MAX_AGE']}" \
110 f"Status: {vuln['policy'][0]['status']} | {vuln['policy'][1]['status']} | {vuln['policy'][2]['status']} " \
111 f"directives: {vuln['policy'][0]['directives']} | {vuln['policy'][1]['directives']} | {vuln['policy'][2]['directives']}" \
112 f"pins: {vuln['policy'][1]['directives']} | {vuln['policy'][2]['directives']} " \
113 f"matchedPins: {vuln['policy'][1]['matchedPins']} | {vuln['policy'][2]['matchedPins']} "
114
115 self.createAndAddVulnToService(host_id,
116 service_id=service_id,
117 name=vuln['name'],
118 desc=vuln['desc'],
119 policyviolations=[policy_info],
120 data=vuln['data'])
121
122
123 def createPlugin():
124 return SslLabsPlugin()
107107 return re.search("SSLyzeVersion", output) is not None
108108 return False
109109
110 def parseOutputString(self, output, debug=False):
110 def parseOutputString(self, output):
111111 parser = SslyzeXmlParser(output)
112112 host = parser.target[0].attrib['host']
113113 ip = parser.target[0].attrib['ip']
5555
5656
5757
58 def parseOutputString(self, output, debug=False):
58 def parseOutputString(self, output):
5959
6060 host_info = re.search(r"Connected to (.+)\.", output)
6161
6363 ip_address = resolve_hostname(hostname)
6464
6565 if host_info is not None:
66 h_id = self.createAndAddHost(ip_address)
67 i_id = self.createAndAddInterface(
68 h_id, ip_address, ipv4_address=ip_address, hostname_resolution=[hostname])
69 s_id = self.createAndAddServiceToInterface(h_id, i_id, self._port,
70 "tcp",
71 ports=[self._port],
72 status="open")
66 h_id = self.createAndAddHost(ip_address, hostnames=[hostname])
67 s_id = self.createAndAddServiceToHost(h_id, self._port, "tcp", ports=[self._port], status="open")
7368 return True
7469
7570 def processCommandString(self, username, current_path, command_string):
9999 }
100100
101101
102 def parseOutputString(self, output, debug=False):
102 def parseOutputString(self, output):
103103 """
104104 This method will discard the output the shell sends, it will read it from
105105 the xml where it expects it to be present.
106
107 NOTE: if 'debug' is true then it is being run from a test case and the
108 output being sent is valid.
109106 """
110
111 print("este es el output (%s)" % output)
112
113 if debug:
114 parser = TheharvesterParser(output)
115 else:
116
117 parser = TheharvesterParser(output)
118
119 print(len(parser.items))
120 for item in parser.items:
121 host = []
122 if item['host'] != item['ip']:
123 host = [item['host']]
124 h_id = self.createAndAddHost(item['ip'])
125 i_id = self.createAndAddInterface(h_id, item['ip'], ipv4_address=item[
126 'ip'], hostname_resolution=host)
127
107 parser = TheharvesterParser(output)
108 for item in parser.items:
109 host = []
110 if item['host'] != item['ip']:
111 host = [item['host']]
112 h_id = self.createAndAddHost(item['ip'], hostnames=host)
128113 del parser
129114
130115
2323 self.command_string = ""
2424 self._command_regex = re.compile(r'^(traceroute|traceroute6)\s+.*?')
2525
26 def parseOutputString(self, output, debug=False):
26 def parseOutputString(self, output):
2727
2828 print("[*]Parsing Output...")
2929
224224 "-h": "Display this help message.",
225225 }
226226
227 def parseOutputString(self, output, debug=False):
227 def parseOutputString(self, output):
228228
229229 parser = W3afXmlParser(output)
230230 ip = resolve_hostname(parser.host)
231 h_id = self.createAndAddHost(ip)
232 i_id = self.createAndAddInterface(h_id, ip, ipv4_address=ip, hostname_resolution=[parser.host])
233 s_id = self.createAndAddServiceToInterface(h_id, i_id, "http", "tcp", ports=[parser.port], status="open")
231 h_id = self.createAndAddHost(ip, hostnames=[parser.host])
232 s_id = self.createAndAddServiceToHost(h_id, "http", "tcp", ports=[parser.port], status="open")
234233
235234 for item in parser.items:
236235 v_id = self.createAndAddVulnWebToService(h_id, s_id, item.name,
240239 del parser
241240
242241
243 def setHost(self):
244 pass
245
246242
247243 def createPlugin():
248244 return W3afPlugin()
104104 host = parser.scaninfo[file]['host']
105105 port = parser.scaninfo[file]['port']
106106 h_id = self.createAndAddHost(host)
107 if(re.match("(^[2][0-5][0-5]|^[1]{0,1}[0-9]{1,2})\.([0-2][0-5][0-5]|[1]{0,1}[0-9]{1,2})\.([0-2][0-5][0-5]|[1]{0,1}[0-9]{1,2})\.([0-2][0-5][0-5]|[1]{0,1}[0-9]{1,2})$", host)):
108 i_id = self.createAndAddInterface(h_id,
109 host,
110 ipv4_address=host)
111 else:
112 i_id = self.createAndAddInterface(h_id,
113 host,
114 ipv6_address=host)
115
116 s_id = self.createAndAddServiceToInterface(
117 h_id, i_id, "http", protocol="tcp", ports=port)
107 s_id = self.createAndAddServiceToHost(h_id, "http", protocol="tcp", ports=port)
118108 for vuln in parser.result[file]:
119109 if parser.scaninfo[file]['type'] == "phpini":
120110 vuln_name = f"{parser.scaninfo[file]['file']}: {vuln}"
9797
9898 self._output_path = None
9999
100 def parseOutputString(self, output, debug=False):
100 def parseOutputString(self, output):
101101 """
102102 This method will discard the output the shell sends, it will read it from
103103 the xml where it expects it to be present.
104
105 NOTE: if 'debug' is true then it is being run from a test case and the
106 output being sent is valid.
107104 """
108105
109106 if self._output_path is None:
113110 return False
114111
115112 parser = WebfuzzerParser(self._output_path)
116
117 h_id = self.createAndAddHost(parser.ipaddress)
118
119 i_id = self.createAndAddInterface(
120 h_id, parser.ipaddress, ipv4_address=parser.ipaddress, hostname_resolution=[parser.hostname])
121
113 h_id = self.createAndAddHost(parser.ipaddress, hostnames=[parser.hostname])
122114 first = True
123115 for item in parser.items:
124116 if first:
125 s_id = self.createAndAddServiceToInterface(h_id, i_id, parser.port,
126 "tcp",
127 ports=[parser.port])
117 s_id = self.createAndAddServiceToHost(h_id, parser.port, "tcp", ports=[parser.port])
128118 first = False
129
130 v_id = self.createAndAddVulnWebToService(h_id, s_id, name=item['desc'],
131 path=item['url'], response=item[
132 'resp'],
133 method=item['method'], website=parser.hostname)
119 v_id = self.createAndAddVulnWebToService(h_id, s_id, name=item['desc'],path=item['url'],
120 response=item['resp'], method=item['method'],
121 website=parser.hostname)
134122
135123 del parser
136124
131131
132132 for vuln in vulns:
133133
134 host_id = self.createAndAddHost(
135 vuln.get("Host").get("name"))
136
137 interface_id = self.createAndAddInterface(
138 host_id, vuln.get("Host").get("name"))
139
140 service_id = self.createAndAddServiceToInterface(
141 host_id, interface_id,
142 vuln.get("Service").get("name"),
143 protocol=vuln.get("Service").get("name"),
144 ports=[vuln.get("Service").get("port")])
134 host_id = self.createAndAddHost(vuln.get("Host").get("name"))
135 service_id = self.createAndAddServiceToHost(host_id, vuln.get("Service").get("name"),
136 protocol=vuln.get("Service").get("name"),
137 ports=[vuln.get("Service").get("port")])
145138
146139 self.createAndAddVulnWebToService(
147140 host_id, service_id,
5151
5252 return data
5353
54 def parseOutputString(self, output, debug=False):
54 def parseOutputString(self, output):
5555 output_list = output.split('\n')
5656 info = self.parseData(output_list)
5757
2929 self.version = "3.4.5"
3030 self.json_keys = {"vulnerabilities"}
3131
32 def parseOutputString(self, output, debug=False):
32 def parseOutputString(self, output):
3333 parser = json.loads(output)
3434 if parser.get('vulnerabilities'):
3535 for vulnerability in parser['vulnerabilities']:
6969
7070
7171
72 def parseOutputString(self, output, debug=False):
72 def parseOutputString(self, output):
7373 matches = re.findall("Name Server:\s*(.*)\s*", output)
7474 for m in matches:
7575 m = m.strip()
7676 ip = resolve_hostname(m)
77 h_id = self.createAndAddHost(ip, "os unknown")
78 i_id = self.createAndAddInterface(
79 h_id, ip, "00:00:00:00:00:00", ip, hostname_resolution=[m])
77 h_id = self.createAndAddHost(ip, "os unknown", hostnames=[m])
8078 return True
8179
8280
5656 self.version = "3.4.5"
5757 self.json_keys = {"target_url", "effective_url", "interesting_findings"}
5858
59 def parseOutputString(self, output, debug=False):
59 def parseOutputString(self, output):
6060 parser = WPScanJsonParser(output)
6161 url_data = parser.parse_url(parser.json_data['target_url'])
6262 host_id = self.createAndAddHost(url_data['address'], hostnames=[url_data['hostname']])
168168
169169
170170
171 def parseOutputString(self, output, debug=False):
171 def parseOutputString(self, output):
172172
173173 parser = X1XmlParser(output)
174174 for item in parser.items:
175 h_id = self.createAndAddHost(item.host, item.name)
176 i_id = self.createAndAddInterface(
177 h_id, item.host, ipv4_address=item.host, hostname_resolution=[item.vclass])
178 s_id = self.createAndAddServiceToInterface(h_id, i_id, item.srvname,
179 item.protocol,
180 ports=[str(item.port)],
181 status="open")
175 h_id = self.createAndAddHost(item.host, item.name, hostnames=[item.vclass])
176 s_id = self.createAndAddServiceToHost(h_id, item.srvname, item.protocol, ports=[str(item.port)],
177 status="open")
182178 for v in item.results:
183179 desc = v.description
184180 v_id = self.createAndAddVulnToService(h_id, s_id, v.name, desc=desc,
2525 self._command_regex = re.compile(r'^(sudo xsssniper|xsssniper|sudo xsssniper\.py|xsssniper\.py|sudo python'
2626 r'xsssniper\.py|.\/xsssniper\.py|python xsssniper\.py)\s+')
2727
28 def parseOutputString(self, output, debug=False):
28 def parseOutputString(self, output):
2929 parametro = []
3030 lineas = output.split("\n")
3131 aux = 0
3535 linea = linea.lower()
3636 if ((linea.find("target:")>0)):
3737 url = re.findall('(?:[-\w.]|(?:%[\da-fA-F]{2}))+', linea)
38 print(url)
39 host_id = self.createAndAddHost(url[3])
4038 address = resolve_hostname(url[3])
41 interface_id = self.createAndAddInterface(host_id,address,ipv4_address=address,hostname_resolution=url[3])
39 host_id = self.createAndAddHost(address, hostnames=url[3])
4240 if ((linea.find("method")>0)):
4341 list_a = re.findall("\w+", linea)
4442 metodo= list_a[1]
4846 if ((linea.find("param:")>0)):
4947 list2 = re.findall("\w+",linea)
5048 parametro.append(list2[1])
51 service_id = self.createAndAddServiceToInterface(host_id, interface_id, self.protocol, 'tcp',
52 ports=['80'], status='Open', version="", description="")
49 service_id = self.createAndAddServiceToHost(host_id, self.protocol, 'tcp', ports=['80'], status='Open',
50 version="", description="")
5351 if aux != 0:
5452 self.createAndAddVulnWebToService(host_id, service_id, name="xss", desc="XSS", ref='', severity='med',
5553 website=url[0], path='', method=metodo, pname='',
182182
183183 for elem in arr:
184184 uri = elem.find('uri').text
185 self.parse_uri(uri)
186
187 self.requests = "\n".join([i['uri'] for i in self.items])
188
189 def parse_uri(self, uri):
190
191 url_parse = urlparse(uri)
192 protocol = url_parse.scheme
193 host = url_parse.netloc
194 port = url_parse.port
185 method_element = elem.find('method')
186 if method_element:
187 method = elem.find('method').text
188 else:
189 method = ""
190 self.parse_uri(uri, method)
191
192 def parse_uri(self, uri, method):
193
194 parsed_url = urlparse(uri)
195 protocol = parsed_url.scheme
196 host = parsed_url.netloc
197 port = parsed_url.port
195198
196199 try:
197200 params = [i.split('=')[0]
203206 'uri': uri,
204207 'params': ', '.join(params),
205208 'host': host,
209 'website': f"{protocol}://{host}",
206210 'protocol': protocol,
207 'port': port
211 'port': port,
212 'method': method,
213 'path': parsed_url.path,
214 'query': parsed_url.query
208215 }
209216 self.items.append(item)
210217
237244 self.options = None
238245
239246
240 def parseOutputString(self, output, debug=False):
247 def parseOutputString(self, output):
241248 """
242249 This method will discard the output the shell sends, it will read it
243250 from the xml where it expects it to be present.
244
245 NOTE: if 'debug' is true then it is being run from a test case and the
246 output being sent is valid.
247251 """
248252
249253 parser = ZapXmlParser(output)
254258 if site.host != site.ip:
255259 host = [site.host]
256260
257 h_id = self.createAndAddHost(site.ip)
258
259 i_id = self.createAndAddInterface(
260 h_id,
261 site.ip,
262 ipv4_address=site.ip,
263 hostname_resolution=host
264 )
265
266 s_id = self.createAndAddServiceToInterface(
267 h_id,
268 i_id,
269 "http",
270 "tcp",
271 ports=[site.port],
272 status='open'
273 )
261 h_id = self.createAndAddHost(site.ip, hostnames=host)
262
263 s_id = self.createAndAddServiceToHost(h_id, "http", "tcp", ports=[site.port], status='open')
274264
275265 for item in site.items:
276 self.createAndAddVulnWebToService(
277 h_id,
278 s_id,
279 item.name,
280 item.desc,
281 website=site.host,
282 severity=item.severity,
283 path=item.items[0]['uri'],
284 params=item.items[0]['params'],
285 request=item.requests,
286 ref=item.ref,
287 resolution=item.resolution
288 )
266 for instance in item.items:
267 self.createAndAddVulnWebToService(
268 h_id,
269 s_id,
270 item.name,
271 item.desc,
272 website=instance['website'],
273 query=instance['query'],
274 severity=item.severity,
275 path=instance['path'],
276 params=instance['params'],
277 method=instance['method'],
278 ref=item.ref,
279 resolution=item.resolution
280 )
289281
290282 del parser
291283
3636
3737 @click.command()
3838 @click.option('--force', is_flag=True)
39 def generate_reports_tests(force):
39 @click.option('--debug', is_flag=False)
40 def generate_reports_tests(force, debug):
4041 generated_summaries = 0
4142 analysed_reports = 0
4243 click.echo(f"{colorama.Fore.GREEN}Generate Faraday Plugins Tests Summary")
4344 plugins_manager = PluginsManager()
4445 analyzer = ReportAnalyzer(plugins_manager)
4546 for report_file_path in list_report_files():
47 if debug:
48 click.echo(f"File: {report_file_path}")
4649 plugin: PluginBase = analyzer.get_plugin(report_file_path)
4750 if not plugin:
4851 click.echo(f"{colorama.Fore.YELLOW}Plugin for file: ({report_file_path}) not found")
0 import json
1 import os
2 import re
3 from tempfile import NamedTemporaryFile
4 from click.testing import CliRunner
5 from faraday_plugins.commands import list_plugins, detect_command, process_command, detect_report, process_report
6
7
8 def test_list_plugins():
9 runner = CliRunner()
10 result = runner.invoke(list_plugins)
11 assert result.exit_code == 0
12 loaded_plugins = re.search(r'Loaded Plugins: (?P<loaded_plugins>\d+)', result.output)
13 assert loaded_plugins
14 assert int(loaded_plugins.groupdict().get('loaded_plugins', 0)) > 0
15
16
17 def test_detect_invalid_command():
18 runner = CliRunner()
19 result = runner.invoke(detect_command, args=['invalid_command'])
20 assert result.exit_code == 0
21 assert result.output.strip() == "Failed to detect command: invalid_command"
22
23
24 def test_detect_command():
25 runner = CliRunner()
26 result = runner.invoke(detect_command, args=['ping -c 1 www.google.com'])
27 assert result.exit_code == 0
28 assert result.output.strip() == "Faraday Plugin: ping"
29
30
31 def test_process_command():
32 runner = CliRunner()
33 result = runner.invoke(process_command, args=['ping -c 1 www.google.com', '--summary'])
34 assert result.exit_code == 0
35 summary = json.loads(result.output.strip())
36 assert summary['hosts'] == 1
37
38
39 def test_process_command_to_file():
40 runner = CliRunner()
41 with runner.isolated_filesystem() as file_system:
42 output_file = os.path.join(file_system, "test.json")
43 result = runner.invoke(process_command, args=['ping -c 1 www.google.com', '-o', output_file])
44 assert result.exit_code == 0
45 assert os.path.isfile(output_file)
46 with open(output_file) as f:
47 vuln_json = json.load(f)
48 assert len(vuln_json['hosts']) == 1
49
50
51 def test_detect_report():
52 report_file = os.path.join('./report-collection', 'faraday_plugins_tests', 'Nmap', 'nmap_5.21.xml')
53 runner = CliRunner()
54 result = runner.invoke(detect_report, args=[report_file])
55 assert result.exit_code == 0
56 assert "Faraday Plugin: Nmap" == result.output.strip()
57
58
59 def test_detect_report_dont_exists():
60 report_file = os.path.join('./report-collection', 'faraday_plugins_tests', 'Nmap', 'invalid_report.xml')
61 runner = CliRunner()
62 result = runner.invoke(detect_report, args=[report_file])
63 assert result.exit_code == 0
64 assert "Don't Exists" in result.output.strip()
65
66
67 def test_process_report_summary():
68 report_file = os.path.join('./report-collection', 'faraday_plugins_tests', 'Nmap', 'nmap_5.21.xml')
69 summary_file = os.path.join('./report-collection', 'faraday_plugins_tests', 'Nmap', 'nmap_5.21_summary.json')
70 runner = CliRunner()
71 result = runner.invoke(process_report, args=[report_file, '--summary'])
72 assert result.exit_code == 0
73 summary = json.loads(result.output.strip())
74 with open(summary_file) as f:
75 saved_summary = json.load(f)
76 vuln_hashes = set(summary['vuln_hashes'])
77 saved_vuln_hashes = set(saved_summary.get('vuln_hashes', []))
78 assert summary['hosts'] == saved_summary['hosts']
79 assert summary['services'] == saved_summary['services']
80 assert summary['hosts_vulns'] == saved_summary['hosts_vulns']
81 assert summary['services_vulns'] == saved_summary['services_vulns']
82 assert summary['severity_vulns'] == saved_summary['severity_vulns']
83 assert vuln_hashes == saved_vuln_hashes
84
106106 if plugin_json:
107107 serializer = BulkCreateSchema()
108108 res = serializer.loads(json.dumps(plugin_json))
109 assert not res.errors
109 assert set(res.keys()) == {'hosts', 'command'}
110
111
110112
111113
112114 @pytest.mark.skip(reason="Skip validate ip format")