Merge branch 'upstream' into kali/master
Sophie Brun
6 years ago
6 | 6 | |
7 | 7 | New features in the latest update |
8 | 8 | ===================================== |
9 | ||
10 | ||
11 | November 5, 2017: | |
12 | --- | |
13 | * Added "Last modified" and "Created" in Hosts view | |
14 | * Fixed bug when trying to run Faraday as second process and closing the terminal (&!) | |
15 | * Fixed bug where it asked for dependencies eternally when you have a different version than the one required | |
16 | * Fixed small bug in the update_from_document method | |
17 | * Fixed bug, makes the python library dependencies specific to the desired version | |
18 | * Fixed GitHub language bar to reflect real code percentage | |
19 | * Merge PR #195: Create gentoo_requirements_extras.txt (New Github wiki page) | |
20 | * Merge PR #225: Add references to found vulnerabilities in nmap plugin | |
21 | * New plugin: Netsparker cloud | |
22 | * New plugin: Lynis (Winner of Faraday Challenge 2017) | |
23 | * New Fplugin: changes the status of all vulnerabilities of an specific workspace to closed | |
24 | * New Fplugin: combines the "create_interface" and "create_host" scripts into one (create_interface_and_host script) | |
25 | * New Fplugin: import_csv , now you can import Faraday objects from a CSV | |
9 | 26 | |
10 | 27 | August 11, 2017: |
11 | 28 | --- |
0 | #!/usr/bin/env python2.7 | |
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 __future__ import print_function | |
8 | from persistence.server.server_io_exceptions import ResourceDoesNotExist | |
9 | from persistence.server import models | |
10 | from utils.user_input import query_yes_no | |
11 | ||
12 | __description__ = 'Changes Vulns Status (to closed)' | |
13 | __prettyname__ = 'Change Vulns Status (to closed)' | |
14 | ||
15 | def main(workspace='', args=None, parser=None): | |
16 | ||
17 | parser.add_argument('-y', '--yes', action="store_true") | |
18 | parsed_args = parser.parse_args(args) | |
19 | ||
20 | try: | |
21 | vulns = models.get_all_vulns(workspace) | |
22 | except ResourceDoesNotExist: | |
23 | print ("Invalid workspace name: ", workspace) | |
24 | return 1, None | |
25 | ||
26 | if not parsed_args.yes: | |
27 | if not query_yes_no("Are you sure you want to change the status to closed of all the vulns in workspace %s" % workspace, default='no'): | |
28 | return 1, None | |
29 | ||
30 | count = 0 | |
31 | for vuln in vulns: | |
32 | old_status = vuln.status | |
33 | ||
34 | # Valid status | |
35 | if vuln.status != "closed": | |
36 | ||
37 | vuln.status = "closed" | |
38 | count += 1 | |
39 | ||
40 | if vuln.class_signature == "Vulnerability": | |
41 | models.update_vuln(workspace, vuln) | |
42 | ||
43 | elif vuln.class_signature == "VulnerabilityWeb": | |
44 | models.update_vuln_web(workspace, vuln) | |
45 | ||
46 | print (vuln.name, ": Status changed from", old_status,"to closed successfully") | |
47 | ||
48 | print ("End of process:", count, "vulnerabilities changed to closed") | |
49 | return 0, None |
0 | #!/usr/bin/env python2.7 | |
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 | ||
8 | from model.common import factory | |
9 | from persistence.server import models | |
10 | ||
11 | __description__ = 'Creates a new host in current workspace' | |
12 | __prettyname__ = 'Create Host' | |
13 | ||
14 | ||
15 | def main(workspace='', args=None, parser=None): | |
16 | parser.add_argument('name', help='Host name') | |
17 | parser.add_argument('os', help='OS') | |
18 | ||
19 | parser.add_argument('--dry-run', action='store_true', help='Do not touch the database. Only print the object ID') | |
20 | ||
21 | parsed_args = parser.parse_args(args) | |
22 | ||
23 | obj = factory.createModelObject(models.Host.class_signature, parsed_args.name, | |
24 | workspace, os=parsed_args.os, parent_id=None) | |
25 | ||
26 | old = models.get_host(workspace, obj.getID()) | |
27 | ||
28 | if old is None: | |
29 | if not parsed_args.dry_run: | |
30 | models.create_host(workspace, obj) | |
31 | else: | |
32 | print "A host with ID %s already exists!" % obj.getID() | |
33 | return 2, None | |
34 | ||
35 | return 0, obj.getID() |
0 | #!/usr/bin/env python2.7 | |
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 | ||
8 | from model.common import factory | |
9 | from persistence.server import models | |
10 | ||
11 | __description__ = 'Creates a new host and interface in current workspace' | |
12 | __prettyname__ = 'Create Host and Interface' | |
13 | ||
14 | ||
15 | def main(workspace='', args=None, parser=None): | |
16 | parser.add_argument('host_name', help='Host name') | |
17 | parser.add_argument('os', help='OS') | |
18 | ||
19 | parser.add_argument('interface_name', help='Interface Name') | |
20 | parser.add_argument('mac', help='Interface MAC Address') | |
21 | ||
22 | parser.add_argument('--ipv4address', help='IPV4 Address', default='0.0.0.0') | |
23 | parser.add_argument('--ipv4gateway', help='IPV4 Gateway', default='0.0.0.0') | |
24 | parser.add_argument('--ipv4mask', help='IPV4 Mask', default='0.0.0.0') | |
25 | parser.add_argument('--ipv4dns', help='IPV4 DNS, as a comma separated list', default='[]') | |
26 | ||
27 | parser.add_argument('--ipv6address', help='IPV6 Address', default='0000:0000:0000:0000:0000:0000:0000:0000') | |
28 | parser.add_argument('--ipv6prefix', help='IPV6 Prefix', default='00') | |
29 | parser.add_argument('--ipv6gateway', help='IPV4 Gateway', default='0000:0000:0000:0000:0000:0000:0000:0000') | |
30 | parser.add_argument('--ipv6dns', help='IPV6 DNS, as a comma separated list', default='') | |
31 | ||
32 | parser.add_argument('--netsegment', help='Network Segment', default='') | |
33 | parser.add_argument('--hostres', help='Hostname Resolution', default='') | |
34 | ||
35 | ||
36 | parser.add_argument('--dry-run', action='store_true', help='Do not touch the database. Only print the object ID') | |
37 | ||
38 | parsed_args = parser.parse_args(args) | |
39 | ||
40 | obj_host = factory.createModelObject(models.Host.class_signature, parsed_args.host_name, | |
41 | workspace, os=parsed_args.os, parent_id=None) | |
42 | ||
43 | ||
44 | old_host = models.get_host(workspace, obj_host.getID()) | |
45 | ||
46 | if old_host is None: | |
47 | if not parsed_args.dry_run: | |
48 | models.create_host(workspace, obj_host) | |
49 | else: | |
50 | print "A host with ID %s already exists!" % obj_host.getID() | |
51 | return 2, None | |
52 | ||
53 | ||
54 | ||
55 | obj_interface = factory.createModelObject(models.Interface.class_signature, parsed_args.interface_name, workspace, | |
56 | mac=parsed_args.mac, | |
57 | ipv4_address=parsed_args.ipv4address, | |
58 | ipv4_mask=parsed_args.ipv4mask, | |
59 | ipv4_gateway=parsed_args.ipv4gateway, | |
60 | ipv4_dns=parsed_args.ipv4dns, | |
61 | ipv6_address=parsed_args.ipv6address, | |
62 | ipv6_prefix=parsed_args.ipv6prefix, | |
63 | ipv6_gateway=parsed_args.ipv6gateway, | |
64 | ipv6_dns=parsed_args.ipv6dns, | |
65 | network_segment=parsed_args.netsegment, | |
66 | hostname_resolution=parsed_args.hostres, | |
67 | parent_id= obj_host.getID() ) | |
68 | ||
69 | old_interface = models.get_interface(workspace, obj_interface.getID()) | |
70 | ||
71 | if old_interface is None: | |
72 | if not parsed_args.dry_run: | |
73 | models.create_interface(workspace, obj_interface) | |
74 | else: | |
75 | print "An interface with ID %s already exists!" % obj_interface.getID() | |
76 | return 2, None | |
77 | ||
78 | return 0, obj_interface.getID() |
0 | #!/usr/bin/env python2.7 | |
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 | ||
8 | from model.common import factory | |
9 | from persistence.server import models | |
10 | ||
11 | __description__ = 'Creates a new interface in a specified host' | |
12 | __prettyname__ = 'Create Interface' | |
13 | ||
14 | ||
15 | def main(workspace='', args=None, parser=None): | |
16 | parser.add_argument('host_id', help='Host ID') | |
17 | parser.add_argument('name', help='Interface Name') | |
18 | parser.add_argument('mac', help='Interface MAC Address') | |
19 | ||
20 | parser.add_argument('--ipv4address', help='IPV4 Address', default='0.0.0.0') | |
21 | parser.add_argument('--ipv4gateway', help='IPV4 Gateway', default='0.0.0.0') | |
22 | parser.add_argument('--ipv4mask', help='IPV4 Mask', default='0.0.0.0') | |
23 | parser.add_argument('--ipv4dns', help='IPV4 DNS, as a comma separated list', default='') | |
24 | ||
25 | parser.add_argument('--ipv6address', help='IPV6 Address', default='0000:0000:0000:0000:0000:0000:0000:0000') | |
26 | parser.add_argument('--ipv6prefix', help='IPV6 Prefix', default='00') | |
27 | parser.add_argument('--ipv6gateway', help='IPV4 Gateway', default='0000:0000:0000:0000:0000:0000:0000:0000') | |
28 | parser.add_argument('--ipv6dns', help='IPV6 DNS, as a comma separated list', default='') | |
29 | ||
30 | parser.add_argument('--netsegment', help='Network Segment', default='') | |
31 | parser.add_argument('--hostres', help='Hostname Resolution', default='') | |
32 | ||
33 | parser.add_argument('--dry-run', action='store_true', help='Do not touch the database. Only print the object ID') | |
34 | ||
35 | parsed_args = parser.parse_args(args) | |
36 | ||
37 | ipv4_dns = filter(None, parsed_args.ipv4dns.split(',')) | |
38 | ipv6_dns = filter(None, parsed_args.ipv6dns.split(',')) | |
39 | ||
40 | obj = factory.createModelObject(models.Interface.class_signature, parsed_args.name, workspace, | |
41 | mac=parsed_args.mac, | |
42 | ipv4_address=parsed_args.ipv4address, | |
43 | ipv4_mask=parsed_args.ipv4mask, | |
44 | ipv4_gateway=parsed_args.ipv4gateway, | |
45 | ipv4_dns=ipv4_dns, | |
46 | ipv6_address=parsed_args.ipv6address, | |
47 | ipv6_prefix=parsed_args.ipv6prefix, | |
48 | ipv6_gateway=parsed_args.ipv6gateway, | |
49 | ipv6_dns=ipv6_dns, | |
50 | network_segment=parsed_args.netsegment, | |
51 | hostname_resolution=parsed_args.hostres, | |
52 | parent_id=parsed_args.host_id) | |
53 | ||
54 | old = models.get_interface(workspace, obj.getID()) | |
55 | ||
56 | if old is None: | |
57 | if not parsed_args.dry_run: | |
58 | models.create_interface(workspace, obj) | |
59 | else: | |
60 | print "An interface with ID %s already exists!" % obj.getID() | |
61 | return 2, None | |
62 | ||
63 | return 0, obj.getID() |
0 | #!/usr/bin/env python2.7 | |
1 | ||
2 | """ | |
3 | Faraday Penetration Test IDE | |
4 | Copyright (C) 2017 Infobyte LLC (http://www.infobytesec.com/) | |
5 | See the file "doc/LICENSE" for the license information | |
6 | """ | |
7 | ||
8 | import csv | |
9 | from persistence.server import models | |
10 | ||
11 | WORKSPACE = "" | |
12 | __description__ = "Import Faraday objects from CSV file" | |
13 | __prettyname__ = "Import objects from CSV" | |
14 | ||
15 | VULN_SEVERITIES = ["info", "low", "med", "high", "critical"] | |
16 | VULN_STATUS = ["opened", "closed", "re-opened", "risk-accepted"] | |
17 | SERVICE_STATUS = ["open", "filtered", "close"] | |
18 | ||
19 | ||
20 | def parse_register(register): | |
21 | ||
22 | host = parse_host(register) | |
23 | interface = parse_interface(register) | |
24 | service = parse_service(register) | |
25 | vulnerability = parse_vulnerability(register) | |
26 | vulnerability_web = parse_vulnerability_web(register) | |
27 | ||
28 | return host, interface, service, vulnerability, vulnerability_web | |
29 | ||
30 | ||
31 | def transform_dict_to_object(columns, register): | |
32 | ||
33 | """ | |
34 | Iterate over all columns and create a new obj with default data | |
35 | and values with the real key for Faraday objects. | |
36 | """ | |
37 | ||
38 | obj = {} | |
39 | ||
40 | for key, val in columns.iteritems(): | |
41 | ||
42 | # Default data | |
43 | value = {val : ""} | |
44 | ||
45 | if val == "owned" or val == "confirmed": | |
46 | value[val] = False | |
47 | ||
48 | elif val == "ports" or val == "hostnames" or val == "refs" or val == "policyviolations": | |
49 | value[val] = [] | |
50 | ||
51 | elif key == "service_status": | |
52 | value[val] = "open" | |
53 | ||
54 | elif key == "vulnerability_status" or key == "vulnerability_web_status": | |
55 | value[val] = "opened" | |
56 | ||
57 | elif key == "vulnerability_severity" or key == "vulnerability_web_severity": | |
58 | value[val] = "info" | |
59 | ||
60 | # Copy data to new object | |
61 | if key in register: | |
62 | ||
63 | if val == "ports": | |
64 | value[val] = [register[key]] | |
65 | ||
66 | elif val == "owned" or val == "confirmed": | |
67 | if register[key] == "true": | |
68 | value[val] = True | |
69 | ||
70 | elif val == "desc": | |
71 | value["description"] = register[key] | |
72 | value["desc"] = register[key] | |
73 | ||
74 | elif val == "refs" or val == "hostnames" or val == "policyviolations": | |
75 | value[val] = register[key].split(",") | |
76 | ||
77 | elif key == "service_status": | |
78 | if register[key].lower() in SERVICE_STATUS: | |
79 | value[val] = register[key] | |
80 | ||
81 | elif key == "vulnerability_status" or key =="vulnerability_web_status": | |
82 | if register[key].lower() in VULN_STATUS: | |
83 | value[val] = register[key] | |
84 | ||
85 | elif key == "vulnerability_severity" or key == "vulnerability_web_severity": | |
86 | if register[key].lower() in VULN_SEVERITIES: | |
87 | value[val] = register[key] | |
88 | else: | |
89 | value[val] = register[key] | |
90 | ||
91 | # Append new value to new object. | |
92 | obj.update(value) | |
93 | ||
94 | # Check if obj is Invalid, return None | |
95 | for key, val in obj.iteritems(): | |
96 | if val != [""] and val != [] and val != "" and val != False and val != "info" and val != "opened" and val != "open": | |
97 | return obj | |
98 | ||
99 | return None | |
100 | ||
101 | ||
102 | def parse_host(register): | |
103 | ||
104 | columns = { | |
105 | "host_name" : "name", | |
106 | "host_description" : "description", | |
107 | "host_owned" : "owned", #boolean | |
108 | "host_os" : "os" | |
109 | } | |
110 | ||
111 | obj = transform_dict_to_object(columns, register) | |
112 | if obj is None: | |
113 | return None | |
114 | host = models.Host(obj, WORKSPACE) | |
115 | return host | |
116 | ||
117 | ||
118 | def parse_interface(register): | |
119 | ||
120 | columns = { | |
121 | "interface_name" : "name", | |
122 | "interface_description" : "description", | |
123 | "interface_hostnames" : "hostnames", #list | |
124 | "interface_mac" : "mac", | |
125 | "interface_network_segment" : "network_segment", | |
126 | "interface_ipv4_address" : "ipv4_address", | |
127 | "interface_ipv4_gateway" : "ipv4_gateway", | |
128 | "interface_ipv4_mask" : "ipv4_mask", | |
129 | "interface_ipv4_dns" : "ipv4_dns", | |
130 | "interface_ipv6_address" : "ipv6_address", | |
131 | "interface_ipv6_gateway" : "ipv6_gateway", | |
132 | "interface_ipv6_prefix" : "ipv6_prefix", | |
133 | "interface_ipv6_dns" : "ipv6_dns" | |
134 | } | |
135 | ||
136 | obj = transform_dict_to_object(columns, register) | |
137 | if obj is None: | |
138 | return None | |
139 | interface = models.Interface(obj, WORKSPACE) | |
140 | return interface | |
141 | ||
142 | ||
143 | def parse_service(register): | |
144 | ||
145 | columns = { | |
146 | "service_name" : "name", | |
147 | "service_description" : "description", | |
148 | "service_owned" : "owned", #boolean | |
149 | "service_port" : "ports", #list | |
150 | "service_protocol": "protocol", | |
151 | "service_version" : "version", | |
152 | "service_status" : "status" | |
153 | } | |
154 | ||
155 | obj = transform_dict_to_object(columns, register) | |
156 | if obj is None: | |
157 | return None | |
158 | service = models.Service(obj, WORKSPACE) | |
159 | return service | |
160 | ||
161 | ||
162 | def parse_vulnerability(register): | |
163 | ||
164 | columns = { | |
165 | "vulnerability_name" : "name", | |
166 | "vulnerability_desc" : "desc", | |
167 | "vulnerability_data" : "data", | |
168 | "vulnerability_severity" : "severity", | |
169 | "vulnerability_refs" : "refs", #list | |
170 | "vulnerability_confirmed" : "confirmed", #boolean | |
171 | "vulnerability_resolution" : "resolution", | |
172 | "vulnerability_status" : "status", | |
173 | "vulnerability_policyviolations" : "policyviolations" #list | |
174 | ||
175 | } | |
176 | ||
177 | obj = transform_dict_to_object(columns, register) | |
178 | if obj is None: | |
179 | return None | |
180 | vulnerability = models.Vuln(obj, WORKSPACE) | |
181 | return vulnerability | |
182 | ||
183 | ||
184 | def parse_vulnerability_web(register): | |
185 | ||
186 | columns = { | |
187 | "vulnerability_web_name" : "name", | |
188 | "vulnerability_web_desc" : "desc", | |
189 | "vulnerability_web_data" : "data", | |
190 | "vulnerability_web_severity" : "severity", | |
191 | "vulnerability_web_refs" : "refs", #list | |
192 | "vulnerability_web_confirmed" : "confirmed", #boolean | |
193 | "vulnerability_web_status" : "status", | |
194 | "vulnerability_web_website" : "website", | |
195 | "vulnerability_web_request" : "request", | |
196 | "vulnerability_web_response" : "response", | |
197 | "vulnerability_web_method" : "method", | |
198 | "vulnerability_web_pname" : "pname", | |
199 | "vulnerability_web_params" : "params", | |
200 | "vulnerability_web_query" : "query", | |
201 | "vulnerability_web_resolution" : "resolution", | |
202 | "vulnerability_web_policyviolations" : "policyviolations", #list | |
203 | "vulnerability_web_path" : "path" | |
204 | } | |
205 | ||
206 | obj = transform_dict_to_object(columns, register) | |
207 | if obj is None: | |
208 | return None | |
209 | vulnerability_web = models.VulnWeb(obj, WORKSPACE) | |
210 | return vulnerability_web | |
211 | ||
212 | ||
213 | def main(workspace="", args=None, parser=None): | |
214 | ||
215 | WORKSPACE = workspace | |
216 | ||
217 | parser.add_argument("--csv", help="Csv file to import") | |
218 | parsed_args = parser.parse_args(args) | |
219 | ||
220 | if not parsed_args.csv: | |
221 | print "Error: Give a CSV file to import with --csv" | |
222 | return 2, None | |
223 | ||
224 | try: | |
225 | file_csv = open(parsed_args.csv, "r") | |
226 | except: | |
227 | print "Error: Unreadeable CSV file, check the path" | |
228 | raise | |
229 | ||
230 | counter = 0 | |
231 | csv_reader = csv.DictReader(file_csv, delimiter=",", quotechar='"') | |
232 | for register in csv_reader: | |
233 | ||
234 | host, interface, service, vulnerability, vulnerability_web = parse_register(register) | |
235 | ||
236 | # Set all IDs and create objects | |
237 | if host is not None: | |
238 | ||
239 | host.setID(None) | |
240 | if not models.get_host(WORKSPACE, host.getID()): | |
241 | ||
242 | counter += 1 | |
243 | print "New host: " + host.getName() | |
244 | models.create_host(WORKSPACE, host) | |
245 | ||
246 | if interface is not None: | |
247 | ||
248 | interface.setID(host.getID()) | |
249 | if not models.get_interface(WORKSPACE, interface.getID()): | |
250 | ||
251 | counter += 1 | |
252 | print "New interface: " + interface.getName() | |
253 | models.create_interface(WORKSPACE, interface) | |
254 | ||
255 | if service is not None: | |
256 | ||
257 | service.setID(interface.getID()) | |
258 | if not models.get_service(WORKSPACE, service.getID()): | |
259 | ||
260 | counter += 1 | |
261 | print "New service: " + service.getName() | |
262 | models.create_service(WORKSPACE, service) | |
263 | ||
264 | # Check if Service exist, then create the vuln with parent Service. | |
265 | # If not exist the Service, create the vuln with parent Host. | |
266 | if vulnerability is not None: | |
267 | ||
268 | if service is None: | |
269 | vulnerability.setID(host.getID()) | |
270 | else: | |
271 | vulnerability.setID(service.getID()) | |
272 | if not models.get_vuln(WORKSPACE, vulnerability.getID()): | |
273 | ||
274 | counter += 1 | |
275 | print "New vulnerability: " + vulnerability.getName() | |
276 | models.create_vuln(WORKSPACE, vulnerability) | |
277 | ||
278 | elif vulnerability_web is not None: | |
279 | ||
280 | vulnerability_web.setID(service.getID()) | |
281 | if not models.get_web_vuln(WORKSPACE, vulnerability_web.getID()): | |
282 | ||
283 | counter += 1 | |
284 | print "New web vulnerability: " + vulnerability_web.getName() | |
285 | models.create_vuln_web(WORKSPACE, vulnerability_web) | |
286 | ||
287 | print "[*]", counter, "new Faraday objects created." | |
288 | file_csv.close() | |
289 | return 0, None |
1 | 1 | <faraday> |
2 | 2 | |
3 | 3 | <appname>Faraday - Penetration Test IDE</appname> |
4 | <version>2.6.3</version> | |
4 | <version>2.7</version> | |
5 | 5 | <debug_status>0</debug_status> |
6 | 6 | <font>-Misc-Fixed-medium-r-normal-*-12-100-100-100-c-70-iso8859-1</font> |
7 | 7 | <home_path>~/</home_path> |
40 | 40 | else: |
41 | 41 | logger.error("Dependencies not met. Please refer to the documentation in order to install them. [%s]", |
42 | 42 | ", ".join(missing_deps)) |
43 | sys.exit(1) | |
44 | 43 | |
45 | 44 | logger.info("Dependencies met") |
46 | 45 |
222 | 222 | |
223 | 223 | signatures = { |
224 | 224 | "\x50\x4B": "zip", |
225 | "\x3C\x3F\x78\x6D\x6C": "xml" | |
225 | "\x3C\x3F\x78\x6D\x6C": "xml", | |
226 | "# Lynis Re": "dat", | |
226 | 227 | } |
227 | 228 | |
228 | 229 | try: |
262 | 263 | # Find root tag based in report_type |
263 | 264 | if report_type == "zip": |
264 | 265 | result = "maltego" |
265 | ||
266 | elif report_type == "dat": | |
267 | result = 'lynis' | |
266 | 268 | else: |
267 | 269 | |
268 | 270 | try: |
336 | 338 | return "Retina" |
337 | 339 | elif "netsparker" == tag: |
338 | 340 | return "Netsparker" |
341 | elif "netsparker-cloud" == tag: | |
342 | return "NetsparkerCloud" | |
339 | 343 | elif "maltego" == tag: |
340 | 344 | return "Maltego" |
345 | elif "lynis" == tag: | |
346 | return "Lynis" | |
341 | 347 | else: |
342 | 348 | return None |
50 | 50 | server_url = _conf().getCouchURI() |
51 | 51 | else: |
52 | 52 | server_url = SERVER_URL |
53 | return server_url | |
53 | return server_url[:-1] if server_url[-1] == "/" else server_url | |
54 | 54 | |
55 | 55 | |
56 | 56 | def _create_server_api_url(): |
1013 | 1013 | |
1014 | 1014 | def create_vuln(workspace_name, id, name, description, owned=None, owner="", |
1015 | 1015 | confirmed=False, data="", refs=None, severity="info", resolution="", |
1016 | desc="", metadata=None, status=None): | |
1016 | desc="", metadata=None, status=None, policyviolations=[]): | |
1017 | 1017 | """Creates a vuln. |
1018 | 1018 | |
1019 | 1019 | Args: |
1033 | 1033 | status (str): the service's status |
1034 | 1034 | metadata: a collection of metadata. If you don't know the metada. leave |
1035 | 1035 | on None, it will be created automatically. |
1036 | policyviolations (lst) : the policy violations | |
1036 | 1037 | |
1037 | 1038 | Returns: |
1038 | 1039 | A dictionary with the server's response. |
1051 | 1052 | desc=desc, |
1052 | 1053 | type="Vulnerability", |
1053 | 1054 | status=status, |
1054 | metadata=metadata) | |
1055 | metadata=metadata, | |
1056 | policyviolations=policyviolations) | |
1055 | 1057 | |
1056 | 1058 | def update_vuln(workspace_name, id, name, description, owned=None, owner="", |
1057 | 1059 | confirmed=False, data="", refs=None, severity="info", resolution="", |
1058 | desc="", metadata=None, status=None): | |
1060 | desc="", metadata=None, status=None, policyviolations=[]): | |
1059 | 1061 | """Updates a vuln. |
1060 | 1062 | |
1061 | 1063 | Args: |
1075 | 1077 | status (str): the service's status |
1076 | 1078 | metadata: a collection of metadata. If you don't know the metada. leave |
1077 | 1079 | on None, it will be created automatically. |
1080 | policyviolations (lst) : the policy violations | |
1078 | 1081 | |
1079 | 1082 | Returns: |
1080 | 1083 | A dictionary with the server's response. |
1093 | 1096 | desc=desc, |
1094 | 1097 | type="Vulnerability", |
1095 | 1098 | status=status, |
1096 | metadata=metadata) | |
1099 | metadata=metadata, | |
1100 | policyviolations=policyviolations) | |
1097 | 1101 | |
1098 | 1102 | def create_vuln_web(workspace_name, id, name, description, owned=None, owner="", |
1099 | 1103 | confirmed=False, data="", refs=None, severity="info", resolution="", |
1100 | 1104 | desc="", metadata=None, method=None, params="", path=None, pname=None, |
1101 | 1105 | query=None, request=None, response=None, category="", website=None, |
1102 | status=None): | |
1106 | status=None, policyviolations=[]): | |
1103 | 1107 | """Creates a vuln web. |
1104 | 1108 | |
1105 | 1109 | Args: |
1126 | 1130 | category (str): a category for the web vuln's |
1127 | 1131 | website (str): the website where the vuln was found |
1128 | 1132 | status (str): the web vulns's status |
1133 | policyviolations (lst) : the policy violations | |
1129 | 1134 | |
1130 | 1135 | Returns: |
1131 | 1136 | A dictionary with the server's response. |
1153 | 1158 | website=website, |
1154 | 1159 | category=category, |
1155 | 1160 | status=status, |
1156 | type='VulnerabilityWeb') | |
1161 | type='VulnerabilityWeb', | |
1162 | policyviolations=policyviolations) | |
1157 | 1163 | |
1158 | 1164 | def update_vuln_web(workspace_name, id, name, description, owned=None, owner="", |
1159 | 1165 | confirmed=False, data="", refs=None, severity="info", resolution="", |
1160 | 1166 | desc="", metadata=None, method=None, params="", path=None, pname=None, |
1161 | 1167 | query=None, request=None, response=None, category="", website=None, |
1162 | status=None): | |
1168 | status=None, policyviolations=[]): | |
1163 | 1169 | """Creates a vuln web. |
1164 | 1170 | |
1165 | 1171 | Args: |
1186 | 1192 | category (str): a category for the web vuln's |
1187 | 1193 | website (str): the website where the vuln was found |
1188 | 1194 | status (str): the web vulns's status |
1195 | policyviolations (lst) : the policy violations | |
1189 | 1196 | |
1190 | 1197 | Returns: |
1191 | 1198 | A dictionary with the server's response. |
1213 | 1220 | website=website, |
1214 | 1221 | category=category, |
1215 | 1222 | status=status, |
1216 | type='VulnerabilityWeb') | |
1223 | type='VulnerabilityWeb', | |
1224 | policyviolations=policyviolations) | |
1217 | 1225 | |
1218 | 1226 | def create_note(workspace_name, id, name, text, owned=None, owner="", |
1219 | 1227 | description="", metadata=None): |
70 | 70 | 'severity': vuln.getSeverity(), |
71 | 71 | 'resolution': vuln.getResolution(), |
72 | 72 | 'desc': vuln.getDesc(), |
73 | 'status': vuln.getStatus()} | |
73 | 'status': vuln.getStatus(), | |
74 | 'policyviolations': vuln.getPolicyViolations()} | |
74 | 75 | vuln_dict.update(get_object_properties(vuln)) |
75 | 76 | return vuln_dict |
76 | 77 |
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 -*- | |
2 | ||
3 | ''' | |
4 | Faraday Penetration Test IDE | |
5 | Copyright (C) 2017 Infobyte LLC (http://www.infobytesec.com/) | |
6 | See the file 'doc/LICENSE' for the license information | |
7 | ''' | |
8 | ||
9 | from __future__ import with_statement | |
10 | import re | |
11 | import os | |
12 | import random | |
13 | from collections import defaultdict | |
14 | ||
15 | from plugins import core | |
16 | ||
17 | ||
18 | current_path = os.path.abspath(os.getcwd()) | |
19 | ||
20 | ||
21 | class LynisLogDataExtracter(): | |
22 | def __init__(self, datfile=None, output=None): | |
23 | self.services = defaultdict(list) | |
24 | if datfile and os.path.exists(datfile): | |
25 | with open(datfile) as f: | |
26 | self.rawcontents = f.read() | |
27 | ||
28 | if output: | |
29 | self.rawcontents = output | |
30 | ||
31 | def _svcHelper(self, ip, port, protocol, name): | |
32 | self.services[ip].append({'port': port, 'protocol': protocol, 'name': name}) | |
33 | ||
34 | def hostname(self): | |
35 | m = re.search('^hostname=(.+)$', self.rawcontents, re.MULTILINE) | |
36 | return(m.group(1).strip()) | |
37 | ||
38 | def osfullname(self): | |
39 | m = re.search('^os_fullname=(.+)$', self.rawcontents, re.MULTILINE) | |
40 | return(m.group(1).strip()) | |
41 | ||
42 | def interfaces(self): | |
43 | interfaces = [] | |
44 | m = re.findall('^network_interface\[\]=(.+)$', | |
45 | self.rawcontents, re.MULTILINE) | |
46 | for iname in m: | |
47 | # Yeah, lynis doesnt relate interface to mac to ip... | |
48 | interfaces.append(iname) | |
49 | return(interfaces) | |
50 | ||
51 | def macs(self): | |
52 | macs = [] | |
53 | m = re.findall('^network_mac_address\[\]=(.+)$', | |
54 | self.rawcontents, re.MULTILINE) | |
55 | for mac in m: | |
56 | macs.append(mac) | |
57 | return(macs) | |
58 | ||
59 | def ipv4(self): | |
60 | ipv4addrs = [] | |
61 | m = re.findall('^network_ipv4_address\[\]=(.+)$', | |
62 | self.rawcontents, re.MULTILINE) | |
63 | for ipv4 in m: | |
64 | ipv4addrs.append(ipv4) | |
65 | return(ipv4addrs) | |
66 | ||
67 | def ipv6(self): | |
68 | ipv6addrs = [] | |
69 | m = re.findall('^network_ipv6_address\[\]=(.+)$', | |
70 | self.rawcontents, re.MULTILINE) | |
71 | for ipv6 in m: | |
72 | ipv6addrs.append(ipv6) | |
73 | return(ipv6addrs) | |
74 | ||
75 | def kernelVersion(self): | |
76 | m = re.search('^os_kernel_version_full=(.+)$', | |
77 | self.rawcontents, re.MULTILINE) | |
78 | return(m.group(1).strip()) | |
79 | ||
80 | def listeningservices(self): | |
81 | ||
82 | line = re.findall('^network_listen_port\[\]=(.+)$', | |
83 | self.rawcontents, re.MULTILINE) | |
84 | ||
85 | for combo in line: | |
86 | if combo.find("|") > 0: | |
87 | ||
88 | items_service = combo.split('|') | |
89 | elements_ip_port = items_service[0].split(':') | |
90 | count = items_service[0].count(':') | |
91 | protocol = items_service[1] | |
92 | name = items_service[2] | |
93 | ||
94 | if name == '-': | |
95 | name = 'Unknown' | |
96 | ||
97 | else: | |
98 | items_service = combo | |
99 | count = items_service.count(':') | |
100 | elements_ip_port = items_service.split(':') | |
101 | protocol = "Unknown" | |
102 | name = "Unknown" | |
103 | ||
104 | #Ipv4 | |
105 | if count == 1: | |
106 | ip, port = elements_ip_port | |
107 | ||
108 | #Ipv6 | |
109 | elif count == 3: | |
110 | port = elements_ip_port[3] | |
111 | ip = '::' | |
112 | ||
113 | #Ipv6 | |
114 | elif count == 5: | |
115 | port = elements_ip_port[5] | |
116 | ip = items_service[0].replace(':{}'.format(port), '') | |
117 | ||
118 | self._svcHelper(ip, port, protocol, name) | |
119 | ||
120 | return self.services | |
121 | ||
122 | ||
123 | def suggestions(self): | |
124 | sugs = {} | |
125 | m = re.findall('^suggestion\[\]=(.+)$', self.rawcontents, re.MULTILINE) | |
126 | for combo in m: | |
127 | x = combo.split('|') | |
128 | sugs[x[0]] = x[1] | |
129 | return(sugs) | |
130 | ||
131 | def warnings(self): | |
132 | warns = {} | |
133 | m = re.findall('^warning\[\]=(.+)$', self.rawcontents, re.MULTILINE) | |
134 | for combo in m: | |
135 | x = combo.split('|') | |
136 | warns[x[0]] = x[1] | |
137 | return(warns) | |
138 | ||
139 | ||
140 | class LynisPlugin(core.PluginBase): | |
141 | """ Simple example plugin to parse lynis' lynis-report.dat file.""" | |
142 | ||
143 | def __init__(self): | |
144 | core.PluginBase.__init__(self) | |
145 | self.id = "Lynis" | |
146 | self.name = "Lynis DAT Output Plugin" | |
147 | self.plugin_version = "0.0.3" | |
148 | self.version = "2.5.5" | |
149 | self.options = None | |
150 | self._current_output = None | |
151 | rr = r'^(lynis|sudo lynis|\.\/lynis|sudo \.\/lynis).*?' | |
152 | self._command_regex = re.compile(rr) | |
153 | self._hosts = [] | |
154 | ||
155 | global current_path | |
156 | ||
157 | def parseOutputString(self, output, debug=False): | |
158 | datpath = self.getDatPath(output) | |
159 | ||
160 | if datpath: | |
161 | lde = LynisLogDataExtracter(datfile=datpath) | |
162 | elif '# Lynis Report' in output: | |
163 | lde = LynisLogDataExtracter(output=output) | |
164 | ||
165 | h_id = self.createAndAddHost(name=lde.hostname(), | |
166 | os=lde.osfullname()) | |
167 | ||
168 | self.createAndAddVulnToHost( | |
169 | host_id=h_id, | |
170 | name="Kernel Version", | |
171 | severity='info', | |
172 | desc=lde.kernelVersion() | |
173 | ) | |
174 | ||
175 | interfaces = lde.interfaces() | |
176 | macs = lde.macs() | |
177 | ipv4s = lde.ipv4() | |
178 | ipv6s = lde.ipv6() | |
179 | svcs = lde.listeningservices() | |
180 | ||
181 | for ipv4 in ipv4s: | |
182 | i_id = self.createAndAddInterface(host_id=h_id, | |
183 | ipv4_address=ipv4) | |
184 | for service_data in svcs[ipv4]: | |
185 | self.createAndAddServiceToInterface(host_id=h_id, | |
186 | interface_id=i_id, | |
187 | name=service_data['name'], | |
188 | protocol=service_data['protocol'], | |
189 | ports=[service_data['port']]) | |
190 | for ipv6 in ipv6s: | |
191 | i_id = self.createAndAddInterface(host_id=h_id, | |
192 | ipv6_address=ipv6) | |
193 | for service_data in svcs[ipv6]: | |
194 | self.createAndAddServiceToInterface(host_id=h_id, | |
195 | interface_id=i_id, | |
196 | name=service_data['name'], | |
197 | protocol=service_data['protocol'], | |
198 | ports=[service_data['port']]) | |
199 | sugs = lde.suggestions() | |
200 | for sug in sugs: | |
201 | self.createAndAddVulnToHost( | |
202 | host_id=h_id, | |
203 | name=sug, | |
204 | severity='med', | |
205 | desc=sugs[sug] | |
206 | ) | |
207 | ||
208 | warns = lde.warnings() | |
209 | for warn in warns: | |
210 | self.createAndAddVulnToHost( | |
211 | host_id=h_id, | |
212 | name=sug, | |
213 | severity='high', | |
214 | desc=warns[warn] | |
215 | ) | |
216 | ||
217 | def processCommandString(self, username, current_path, command_string): | |
218 | """ | |
219 | Lynis does not have a means to specify the location for the | |
220 | DAT file, which by default goes to /var/log/lynis-report.dat | |
221 | or /tmp/lynis-report.dat, depending on privileges. | |
222 | Because of that, we will extract the DAT location off | |
223 | lynis' output via parseOutputString(). | |
224 | """ | |
225 | return | |
226 | ||
227 | def getDatPath(self, output): | |
228 | m = re.search('(\/.+\.dat)$', output, re.MULTILINE) | |
229 | if m: | |
230 | return(m.group(0).strip()) | |
231 | ||
232 | ||
233 | def createPlugin(): | |
234 | return LynisPlugin() |
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 | #!/usr/bin/env python | |
1 | # -*- coding: utf-8 -*- | |
2 | ||
3 | ''' | |
4 | Faraday Penetration Test IDE | |
5 | Copyright (C) 2013 Infobyte LLC (http://www.infobytesec.com/) | |
6 | See the file 'doc/LICENSE' for the license information | |
7 | ||
8 | ''' | |
9 | from __future__ import with_statement | |
10 | from plugins import core | |
11 | from model import api | |
12 | import re | |
13 | import os | |
14 | import sys | |
15 | import socket | |
16 | import urllib | |
17 | ||
18 | try: | |
19 | import xml.etree.cElementTree as ET | |
20 | import xml.etree.ElementTree as ET_ORIG | |
21 | ETREE_VERSION = ET_ORIG.VERSION | |
22 | except ImportError: | |
23 | import xml.etree.ElementTree as ET | |
24 | ETREE_VERSION = ET.VERSION | |
25 | ||
26 | ETREE_VERSION = [int(i) for i in ETREE_VERSION.split(".")] | |
27 | ||
28 | current_path = os.path.abspath(os.getcwd()) | |
29 | ||
30 | __author__ = "Francisco Amato" | |
31 | __copyright__ = "Copyright (c) 2013, Infobyte LLC" | |
32 | __credits__ = ["Francisco Amato"] | |
33 | __license__ = "" | |
34 | __version__ = "1.0.0" | |
35 | __maintainer__ = "Francisco Amato" | |
36 | __email__ = "[email protected]" | |
37 | __status__ = "Development" | |
38 | ||
39 | def cleaner_unicode(string): | |
40 | if string is not None: | |
41 | return string.encode('ascii', errors='backslashreplace') | |
42 | else: | |
43 | return string | |
44 | ||
45 | def cleaner_results(string): | |
46 | ||
47 | try: | |
48 | q = re.compile(r'<.*?>', re.IGNORECASE) | |
49 | return re.sub(q, '', string) | |
50 | ||
51 | except: | |
52 | return '' | |
53 | ||
54 | def get_urls(string): | |
55 | urls = re.findall(r'href=[\'"]?([^\'" >]+)', string) | |
56 | return urls | |
57 | ||
58 | ||
59 | class NetsparkerCloudXmlParser(object): | |
60 | """ | |
61 | The objective of this class is to parse an xml file generated by the netsparkercloud tool. | |
62 | ||
63 | TODO: Handle errors. | |
64 | TODO: Test netsparkercloud output version. Handle what happens if the parser doesn't support it. | |
65 | TODO: Test cases. | |
66 | ||
67 | @param netsparkercloud_xml_filepath A proper xml generated by netsparkercloud | |
68 | """ | |
69 | ||
70 | def __init__(self, xml_output): | |
71 | self.filepath = xml_output | |
72 | ||
73 | tree = self.parse_xml(xml_output) | |
74 | if tree: | |
75 | self.items = [data for data in self.get_items(tree)] | |
76 | else: | |
77 | self.items = [] | |
78 | ||
79 | def parse_xml(self, xml_output): | |
80 | """ | |
81 | Open and parse an xml file. | |
82 | ||
83 | TODO: Write custom parser to just read the nodes that we need instead of | |
84 | reading the whole file. | |
85 | ||
86 | @return xml_tree An xml tree instance. None if error. | |
87 | """ | |
88 | try: | |
89 | tree = ET.fromstring(xml_output) | |
90 | except SyntaxError, err: | |
91 | self.devlog("SyntaxError: %s. %s" % (err, xml_output)) | |
92 | return None | |
93 | ||
94 | return tree | |
95 | ||
96 | def get_items(self, tree): | |
97 | """ | |
98 | @return items A list of Host instances | |
99 | """ | |
100 | for node in tree.findall("vulnerabilities/vulnerability"): | |
101 | yield Item(node) | |
102 | ||
103 | ||
104 | class Item(object): | |
105 | """ | |
106 | An abstract representation of a Item | |
107 | ||
108 | ||
109 | @param item_node A item_node taken from an netsparkercloud xml tree | |
110 | """ | |
111 | ||
112 | def __init__(self, item_node): | |
113 | self.node = item_node | |
114 | self.url = self.get_text_from_subnode("url") | |
115 | ||
116 | host = re.search( | |
117 | "(http|https|ftp)\://([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))[\:]*([0-9]+)*([/]*($|[a-zA-Z0-9\.\,\?\'\\\+&%\$#\=~_\-]+)).*?$", self.url) | |
118 | ||
119 | self.protocol = host.group(1) | |
120 | self.hostname = host.group(4) | |
121 | self.port = 80 | |
122 | ||
123 | if self.protocol == 'https': | |
124 | self.port = 443 | |
125 | if host.group(11) is not None: | |
126 | self.port = host.group(11) | |
127 | ||
128 | self.type = self.get_text_from_subnode("type") | |
129 | self.name = self.get_text_from_subnode("name") | |
130 | self.severity = self.get_text_from_subnode("severity") | |
131 | self.certainty = self.get_text_from_subnode("certainty") | |
132 | ||
133 | ||
134 | self.node = item_node.find("http-request") | |
135 | self.method = self.get_text_from_subnode("method") | |
136 | self.request = self.get_text_from_subnode("content") | |
137 | ||
138 | #print self.node | |
139 | self.param = "" | |
140 | self.paramval = "" | |
141 | for p in self.node.findall("parameters/parameter"): | |
142 | self.param = p.get('name') | |
143 | self.paramval = p.get('value') | |
144 | ||
145 | self.node = item_node.find("http-response") | |
146 | self.response = self.get_text_from_subnode("content") | |
147 | ||
148 | self.extra = [] | |
149 | for v in item_node.findall("extra-information/info"): | |
150 | self.extra.append(v.get('name') + ":" + v.get('value') ) | |
151 | ||
152 | self.node = item_node.find("classification") | |
153 | self.owasp = self.get_text_from_subnode("owasp") | |
154 | self.wasc = self.get_text_from_subnode("wasc") | |
155 | self.cwe = self.get_text_from_subnode("cwe") | |
156 | self.capec = self.get_text_from_subnode("capec") | |
157 | self.pci = self.get_text_from_subnode("pci31") | |
158 | self.pci2 = self.get_text_from_subnode("pci32") | |
159 | self.hipaa = self.get_text_from_subnode("hipaa") | |
160 | ||
161 | self.ref = [] | |
162 | if self.cwe: | |
163 | self.ref.append("CWE-" + self.cwe) | |
164 | if self.owasp: | |
165 | self.ref.append("OWASP-" + self.owasp) | |
166 | ||
167 | self.node = item_node | |
168 | self.remedyreferences = self.get_text_from_subnode("remedy-references") | |
169 | self.externalreferences = self.get_text_from_subnode("external-references") | |
170 | if self.remedyreferences: | |
171 | for u in get_urls(self.remedyreferences): | |
172 | self.ref.append(u) | |
173 | if self.externalreferences: | |
174 | for u in get_urls(self.externalreferences): | |
175 | self.ref.append(u) | |
176 | ||
177 | self.impact = cleaner_results(self.get_text_from_subnode("impact")) | |
178 | self.remedialprocedure = cleaner_results(self.get_text_from_subnode("remedial-procedure")) | |
179 | self.remedialactions = cleaner_results(self.get_text_from_subnode("remedial-actions")) | |
180 | self.exploitationskills = cleaner_results(self.get_text_from_subnode("exploitation-skills")) | |
181 | self.proofofconcept = cleaner_results(self.get_text_from_subnode("proof-of-concept")) | |
182 | ||
183 | self.resolution = self.remedialprocedure | |
184 | self.resolution += "\nRemedial Actions: " + self.remedialactions if self.remedialactions is not None else "" | |
185 | ||
186 | ||
187 | self.desc = cleaner_results(self.get_text_from_subnode("description")) | |
188 | self.desc += "\nImpact: " + self.impact if self.impact else "" | |
189 | self.desc += "\nExploitation Skills: " + self.exploitationskills if self.exploitationskills else "" | |
190 | self.desc += "\nProof of concept: " + self.proofofconcept if self.proofofconcept else "" | |
191 | self.desc += "\nWASC: " + self.wasc if self.wasc else "" | |
192 | self.desc += "\nPCI31: " + self.pci if self.pci else "" | |
193 | self.desc += "\nPCI32: " + self.pci2 if self.pci2 else "" | |
194 | self.desc += "\nCAPEC: " + self.capec if self.capec else "" | |
195 | self.desc += "\nHIPA: " + self.hipaa if self.hipaa else "" | |
196 | self.desc += "\nExtra: " + "\n".join(self.extra) if self.extra else "" | |
197 | ||
198 | def get_text_from_subnode(self, subnode_xpath_expr): | |
199 | """ | |
200 | Finds a subnode in the host node and the retrieves a value from it. | |
201 | ||
202 | @return An attribute value | |
203 | """ | |
204 | if self.node: | |
205 | sub_node = self.node.find(subnode_xpath_expr) | |
206 | if sub_node is not None: | |
207 | if sub_node.text is not None: | |
208 | return cleaner_unicode(sub_node.text) | |
209 | ||
210 | return "" | |
211 | ||
212 | ||
213 | class NetsparkerCloudPlugin(core.PluginBase): | |
214 | """ | |
215 | Example plugin to parse netsparkercloud output. | |
216 | """ | |
217 | ||
218 | def __init__(self): | |
219 | core.PluginBase.__init__(self) | |
220 | self.id = "NetsparkerCloud" | |
221 | self.name = "NetsparkerCloud XML Output Plugin" | |
222 | self.plugin_version = "0.0.1" | |
223 | self.version = "NetsparkerCloud" | |
224 | self.framework_version = "1.0.0" | |
225 | self.options = None | |
226 | self._current_output = None | |
227 | self._command_regex = re.compile( | |
228 | r'^(sudo netsparkercloud|\.\/netsparkercloud).*?') | |
229 | ||
230 | global current_path | |
231 | self._output_file_path = os.path.join(self.data_path, | |
232 | "netsparkercloud_output-%s.xml" % self._rid) | |
233 | ||
234 | def resolve(self, host): | |
235 | try: | |
236 | return socket.gethostbyname(host) | |
237 | except: | |
238 | pass | |
239 | return host | |
240 | ||
241 | def parseOutputString(self, output, debug=False): | |
242 | ||
243 | parser = NetsparkerCloudXmlParser(output) | |
244 | first = True | |
245 | for i in parser.items: | |
246 | if first: | |
247 | ip = self.resolve(i.hostname) | |
248 | h_id = self.createAndAddHost(ip) | |
249 | i_id = self.createAndAddInterface( | |
250 | h_id, ip, ipv4_address=ip, hostname_resolution=i.hostname) | |
251 | ||
252 | s_id = self.createAndAddServiceToInterface(h_id, i_id, str(i.port), | |
253 | str(i.protocol), | |
254 | ports=[str(i.port)], | |
255 | status="open") | |
256 | ||
257 | n_id = self.createAndAddNoteToService( | |
258 | h_id, s_id, "website", "") | |
259 | n2_id = self.createAndAddNoteToNote( | |
260 | h_id, s_id, n_id, i.hostname, "") | |
261 | first = False | |
262 | ||
263 | v_id = self.createAndAddVulnWebToService(h_id, s_id, i.name, ref=i.ref, website=i.hostname, | |
264 | severity=i.severity, desc=i.desc, path=i.url, method=i.method, | |
265 | request=i.request, response=i.response, resolution=i.resolution, pname=i.param) | |
266 | ||
267 | del parser | |
268 | ||
269 | def processCommandString(self, username, current_path, command_string): | |
270 | return None | |
271 | ||
272 | def setHost(self): | |
273 | pass | |
274 | ||
275 | ||
276 | def createPlugin(): | |
277 | return NetsparkerCloudPlugin() | |
278 | ||
279 | if __name__ == '__main__': | |
280 | parser = NetsparkerCloudXmlParser(sys.argv[1]) | |
281 | for item in parser.items: | |
282 | if item.status == 'up': | |
283 | print item |
361 | 361 | @param script_node A script_node taken from an nmap xml tree |
362 | 362 | """ |
363 | 363 | |
364 | def parse_output(self, output): | |
365 | block_re = re.compile('^\s{4}References:((?:.|[\r\n])+[\r\n](?:\s{4}\w|\s*$))', re.MULTILINE) | |
366 | m1 = block_re.findall(output) | |
367 | if len(m1) > 0: | |
368 | links_re = re.compile('[ \t]+([^ \t\n\r]+)[ \t]*') | |
369 | m2 = links_re.findall(m1[0]) | |
370 | return m2 | |
371 | return [] | |
372 | ||
373 | ||
374 | ||
364 | 375 | def __init__(self, script_node): |
365 | 376 | self.node = script_node |
366 | 377 | |
367 | 378 | self.name = script_node.get("id") |
368 | 379 | self.desc = script_node.get("output") |
380 | self.refs = self.parse_output(self.desc) | |
369 | 381 | self.response = "" |
370 | 382 | for k in script_node.findall("elem"): |
371 | 383 | self.response += "\n" + str(k.get('key')) + ": " + str(k.text) |
473 | 485 | h_id, |
474 | 486 | v.name, |
475 | 487 | desc=v.desc, |
488 | ref=v.refs, | |
476 | 489 | severity=0) |
477 | 490 | |
478 | 491 | for port in host.ports: |
498 | 511 | for v in port.vulns: |
499 | 512 | severity = 0 |
500 | 513 | desc = v.desc |
514 | refs = v.refs | |
501 | 515 | desc += "\nOutput: " + v.response if v.response else "" |
502 | 516 | |
503 | 517 | if re.search(r"VULNERABLE", desc): |
527 | 541 | s_id, |
528 | 542 | v.name, |
529 | 543 | desc=desc, |
544 | ref=refs, | |
530 | 545 | severity=severity, |
531 | 546 | website=minterfase) |
532 | 547 | else: |
535 | 550 | s_id, |
536 | 551 | v.name, |
537 | 552 | desc=v.desc, |
553 | ref=refs, | |
538 | 554 | severity=severity) |
539 | 555 | del parser |
540 | 556 | return True |
0 | couchdbkit | |
1 | mockito | |
2 | whoosh | |
3 | argparse | |
4 | IPy | |
5 | restkit | |
6 | requests | |
7 | tornado | |
8 | flask | |
9 | colorama | |
0 | couchdbkit>=0.6.5 | |
1 | mockito>=1.0.12 | |
2 | whoosh>=2.7.4 | |
3 | IPy>=0.83 | |
4 | restkit>=4.2.2 | |
5 | requests>=2.18.4 | |
6 | tornado>=4.5.1 | |
7 | flask>=0.12.2 | |
8 | colorama>=0.3.9⏎ |
0 | beautifulsoup4 | |
1 | psycopg2 | |
2 | w3af_api_client | |
0 | beautifulsoup4>=4.6.0 | |
1 | psycopg2>=2.7.3 | |
2 | w3af_api_client>=1.1.7⏎ |
0 | 0 | couchdbkit>=0.6.5 |
1 | 1 | restkit>=4.2.2 |
2 | requests>=2.10.0 | |
3 | flask>=0.10.1 | |
4 | twisted>=16.1.1 | |
5 | sqlalchemy>=1.0.12 | |
6 | pyopenssl>=16.0.0 | |
7 | service_identity>=16.0.0 | |
8 | pyasn1-modules | |
2 | requests>=2.18.4 | |
3 | flask>=0.12.2 | |
4 | twisted>=17.5.0 | |
5 | sqlalchemy>=1.1.13 | |
6 | pyopenssl>=17.2.0 | |
7 | service_identity>=17.0.0 | |
8 | pyasn1-modules>=0.0.11⏎ |
101 | 101 | # Apply pagination, sorting and filtering options to the query |
102 | 102 | query = self.__specialized_sort(query, order_by, order_dir) |
103 | 103 | query = apply_search_filter(query, self.COLUMNS_MAP, search, vuln_filter, self.STRICT_FILTERING) |
104 | count = get_count(query) | |
104 | count = get_count(query,count_col=Vulnerability.id) | |
105 | 105 | |
106 | 106 | if page_size: |
107 | 107 | query = paginate(query, page, page_size) |
133 | 133 | flush_changes() |
134 | 134 | |
135 | 135 | def _show_progress(msg, percentage): |
136 | sys.stdout.write('{}: {}%\r'.format(msg, percentage)) | |
137 | sys.stdout.flush() | |
138 | ||
136 | try: | |
137 | sys.stdout.write('{}: {}%\r'.format(msg, percentage)) | |
138 | sys.stdout.flush() | |
139 | except IOError: | |
140 | logger.warning("Unable to write progress to stdout") |
8 | 8 | from sqlalchemy.ext.declarative import declarative_base |
9 | 9 | |
10 | 10 | |
11 | SCHEMA_VERSION = 'W.2.6.3' | |
11 | SCHEMA_VERSION = 'W.2.7' | |
12 | 12 | |
13 | 13 | Base = declarative_base() |
14 | 14 | |
200 | 200 | self.description=document.get('description') |
201 | 201 | self.mac=document.get('mac') |
202 | 202 | self.owned=document.get('owned', False) |
203 | self.hostnames=u','.join(document.get('hostnames')) | |
203 | self.hostnames=u','.join(document.get('hostnames') or []) | |
204 | 204 | self.network_segment=document.get('network_segment') |
205 | 205 | self.ipv4_address=document.get('ipv4').get('address') |
206 | 206 | self.ipv4_gateway=document.get('ipv4').get('gateway') |
60 | 60 | <a href="" ng-click="toggleSort('vulns')">Vulns</a> |
61 | 61 | </th> |
62 | 62 | <th> |
63 | <a href="" ng-click="toggleSort('credentials')">Credentials</a> | |
64 | </th> | |
65 | <th> | |
63 | 66 | <a href="" ng-click="toggleSort('os')">OS</a> |
64 | 67 | </th> |
65 | 68 | <th> |
66 | 69 | <a href="" ng-click="toggleSort('owned')">Owned</a> |
67 | 70 | </th> |
68 | 71 | <th> |
69 | <a href="" ng-click="toggleSort('credentials')">Credentials</a> | |
72 | <a href="" ng-click="toggleSort('metadata.update_time')">Last modified</a> | |
70 | 73 | </th> |
71 | 74 | </tr> |
72 | 75 | </thead> |
84 | 87 | <td><a ng-href="#/host/ws/{{workspace}}/hid/{{host._id}}" ng-bind="host.services || '-'"></a></td> |
85 | 88 | <td><a ng-href="#/status/ws/{{workspace}}/search/target={{host.name}}" ng-bind="host.vulns"></a></td> |
86 | 89 | <td> |
90 | <a ng-href="#/credentials/ws/{{workspace}}/hid/{{host._id}}">{{host.credentials}}</a> | |
91 | </td> | |
92 | <td> | |
87 | 93 | <a ng-href="#/hosts/ws/{{workspace}}/search/os={{host.os}}"> |
88 | 94 | <img ng-if="host.icon != undefined" ng-src="images/{{host.icon}}.png" uib-tooltip="{{host.os}}"/> |
89 | 95 | <span ng-if="host.icon == undefined" class="fa fa-laptop" uib-tooltip="{{host.os}}"></span> |
90 | 96 | </a> |
91 | 97 | </td> |
92 | 98 | <td> |
93 | <i class="fa fa-exclamation-triangle" aria-hidden="true" ng-if="host.owned"> owned</i> | |
99 | <span class="fa fa-exclamation-triangle" aria-hidden="true" ng-if="host.owned"></span> | |
100 | <span ng-if="host.owned"> owned</span> | |
94 | 101 | <span ng-if="!host.owned">not yet</span> |
95 | 102 | </td> |
96 | 103 | <td> |
97 | <a ng-href="#/credentials/ws/{{workspace}}/hid/{{host._id}}">{{host.credentials}}</a> | |
104 | <span am-time-ago="host.metadata.update_time * 1000"></span> | |
105 | <span ng-if="!host.metadata.update_time" am-time-ago="host.metadata.create_time * 1000"></span> | |
98 | 106 | </td> |
99 | 107 | </tr> |
100 | 108 | </tbody> |
149 | 149 | </span> |
150 | 150 | </h3> |
151 | 151 | <div class="form-horizontal"> |
152 | <div class="form-group" ng-class="{'has-error': !host.name }"> | |
152 | <div class="form-group" ng-class="{'has-error': !host.name}"> | |
153 | 153 | <div class="col-md-12"> |
154 | 154 | <strong ng-if="!editing">Name</strong> |
155 | 155 | <h5 ng-if="editing">Name</h5> |
156 | 156 | <label class="sr-only" for="name">Name</label> |
157 | 157 | <input type="text" class="form-control" id="name" placeholder="Name" ng-model="host.name" ng-if="editing" required/> |
158 | <p ng-if="!editing">{{host.name}}</p> | |
158 | <br ng-if="!editing"> | |
159 | <span ng-if="!editing">{{host.name}}</span> | |
159 | 160 | <span class="help-block normal-size" ng-if="editing"> |
160 | 161 | Example: 192.168.0.1 |
161 | 162 | </span> |
163 | 164 | </div> |
164 | 165 | <div class="form-group"> |
165 | 166 | <div class="col-md-6" style="margin-bottom: 15px"> |
166 | <div class="checkbox"> | |
167 | <label> | |
168 | <input type="checkbox" id="owned" ng-model="host.owned" ng-disabled="!editing"/> | |
169 | <span class="normal-size">Owned</span> | |
170 | </label> | |
171 | </div><!-- .checkbox --> | |
167 | <span>Owned:</span> | |
168 | <input class="form-check-input" type="checkbox" id="owned" ng-model="host.owned" ng-disabled="!editing"></input> | |
172 | 169 | </div> |
173 | 170 | <div class="col-md-12"> |
174 | 171 | <strong ng-if="!editing">Operating System</strong> |
226 | 223 | <textarea class="form-control" id="description" placeholder="Description" ng-model="host.description" ng-if="editing"></textarea> |
227 | 224 | <p ng-if="!editing">{{host.description}}</p> |
228 | 225 | </div> |
226 | <div class="col-md-12"> | |
227 | <i ng-if="!editing"> | |
228 | </br> | |
229 | <span class="fa fa-clock-o"></span> | |
230 | <span> Created</span> | |
231 | <span am-time-ago="host.metadata.create_time * 1000"></span> | |
232 | <span ng-if="!host.metadata.create_time" am-time-ago="host.metadata.update_time * 1000"></span> | |
233 | </i> | |
234 | </div> | |
229 | 235 | </div><!-- .form-group --> |
230 | 236 | </div> |
231 | 237 | <div style="float: right"> |
0 | import os | |
1 | import sys | |
2 | import json | |
3 | import unittest | |
4 | sys.path.append(os.path.abspath(os.getcwd())) | |
5 | ||
6 | from server.models import Interface | |
7 | ||
8 | INTERFACE_TEST_CASE_1 = {"network_segment": "", "description": "", "_rev": "1-ffffffffffffffffbcb43323dfeeeeee", "owned": False, "mac": "00:00:00:00:00:00", "hostnames": None, "owner": "", "name": "192.168.1.1", "ipv4": {"mask": "0.0.0.0", "gateway": "0.0.0.0", "DNS": [], "address": "192.168.1.1"}, "ipv6": {"prefix": "00", "gateway": "0000:0000:0000:0000:0000:0000:0000:0000", "DNS": [], "address": "0000:0000:0000:0000:0000:0000:0000:0000"}, "_id": "90aa44756bd2f4fc2390f903a6f25f43216b0790.0e9d8e8deab983df5e8af607f00901e089174881", "type": "Interface", "metadata": {"update_time": 1498579348.26915, "update_user": "leonardo", "update_action": 0, "creator": "Metasploit", "create_time": 1498579348.26915, "update_controller_action": "No model controller call", "owner": "leonardo", "command_id": "f09ea09db5264f2185a6d142ecd794f2"}} | |
9 | ||
10 | ||
11 | class ModelsTest(unittest.TestCase): | |
12 | ||
13 | def test_(self): | |
14 | interface = Interface(INTERFACE_TEST_CASE_1) | |
15 | interface.update_from_document(INTERFACE_TEST_CASE_1) | |
16 | self.assertEquals(interface.hostname, '') | |
17 | ||
18 | ||
19 | if __name__ == '__main__': | |
20 | unittest.main() |
3 | 3 | See the file 'doc/LICENSE' for the license information |
4 | 4 | |
5 | 5 | ''' |
6 | ||
6 | import sys | |
7 | import pip | |
7 | 8 | import pkg_resources |
8 | import pip | |
9 | 9 | |
10 | 10 | |
11 | 11 | def check_dependencies(requirements_file='requirements.txt'): |
28 | 28 | |
29 | 29 | def install_packages(packages): |
30 | 30 | for package in packages: |
31 | pip.main(['install', package, '--user']) | |
31 | pip_cmd = ['install', package, '-U'] | |
32 | if not hasattr(sys, 'real_prefix'): | |
33 | pip_cmd.append('--user') | |
34 | pip.main(pip_cmd) |