Codebase list python-faraday / ee6b778
New upstream version 3.7.0 Sophie Brun 5 years ago
32 changed file(s) with 2003 addition(s) and 373 deletion(s). Raw diff Collapse all Expand all
1515 * Micaela Ranea Sánchez
1616 * Sebastian Kulesz
1717 * Eric Horvat
18 * Jorge Luis González Iznaga
19 * Javier Montilva
1820
1921 Project contributors
2022
(New empty file)
0 * Add vulnerability preview to status report
1 * Update Fierce Plugin. Import can be done from GTK console.
2 * Update Goohost plugin and now Faraday imports Goohost .txt report.
3 * Update plugin for support WPScan v-3.4.5
4 * Update Qualysguard plugin to its 8.17.1.0.2 version
5 * Update custom fields with Searcher
6 * Update Recon-ng Plugin so that it accepts XML reports
7 * Add postres version to status-change command
8 * Couchdb configuration section will not be added anymore
9 * Add unit test for config/default.xml
66
77 New features in the latest update
88 =====================================
9
10
11 3.7 [Apr 3rd, 2019]:
12 ---
13 * New feature vulnerability preview to view vulnerability data.
14 * Update Fierce Plugin. Import can be done from GTK console.
15 * Update Goohost plugin and now Faraday imports Goohost .txt report.
16 * Update plugin for support WPScan v-3.4.5
17 * Update Qualysguard plugin to its 8.17.1.0.2 version
18 * Update custom fields with Searcher
19 * Update Recon-ng Plugin so that it accepts XML reports
20 * Add postres version to status-change command
21 * Couchdb configuration section will not be added anymore
22 * Add unit test for config/default.xml
923
1024
1125 3.6 [Feb 21th, 2019]:
66
77 New features in the latest update
88 =====================================
9
10
11 3.7 [Apr 3rd, 2019]:
12 ---
13 * New feature vulnerability preview to view vulnerability data.
14 * Update Fierce Plugin. Import can be done from GTK console.
15 * Update Goohost plugin and now Faraday imports Goohost .txt report.
16 * Update plugin for support WPScan v-3.4.5
17 * Update Qualysguard plugin to its 8.17.1.0.2 version
18 * Update custom fields with Searcher
19 * Update Recon-ng Plugin so that it accepts XML reports
20 * Add postres version to status-change command
21 * Couchdb configuration section will not be added anymore
22 * Add unit test for config/default.xml
923
1024
1125 3.6 [Feb 21th, 2019]:
0 3.6.0
0 3.7.0
11 <faraday>
22
33 <appname>Faraday - Penetration Test IDE</appname>
4 <version>3.6.0</version>
4 <version>3.7.0</version>
55 <debug_status>0</debug_status>
66 <font>-Misc-Fixed-medium-r-normal-*-12-100-100-100-c-70-iso8859-1</font>
77 <home_path>~/</home_path>
0 """add markdown column to exectuive reports
1
2 Revision ID: 5272b3f5a820
3 Revises: 2ca03a8feef5
4 Create Date: 2019-03-27 19:26:28.354078+00:00
5
6 """
7 from alembic import op
8 import sqlalchemy as sa
9
10
11 # revision identifiers, used by Alembic.
12 revision = '5272b3f5a820'
13 down_revision = '2ca03a8feef5'
14 branch_labels = None
15 depends_on = None
16
17
18 def upgrade():
19 op.add_column('executive_report', sa.Column('markdown', sa.Boolean(), nullable=False, server_default='False'))
20
21
22 def downgrade():
23 op.drop_column('executive_report', 'markdown')
1111 import re
1212 import os
1313 import sys
14 import random
1415
1516 current_path = os.path.abspath(os.getcwd())
1617
4041 """
4142
4243 def __init__(self, output):
43
4444 self.target = None
4545 self.items = []
4646
47 r = re.search(
48 "DNS Servers for ([\w\.-]+):\r\n([^$]+)Trying zone transfer first...",
47 regex = re.search(
48 "DNS Servers for ([\w\.-]+):\n([^$]+)Trying zone transfer first...",
4949 output)
5050
51 if r is not None:
52 self.target = r.group(1)
53 mstr = re.sub("\t", "", r.group(2))
54 self.dns = mstr.split()
55
56 r = re.search(
57 "Now performing [\d]+ test\(s\)...\r\n([^$]+)\x0D\nSubnets found ",
51 if regex is not None:
52 self.target = regex.group(1)
53 mstr = re.sub("\t", "", regex.group(2))
54 self.dns = filter(None, mstr.splitlines())
55
56 regex = re.search(
57 "Now performing [\d]+ test\(s\)...\n([^$]+)\nSubnets found ",
5858 output)
59
60 if r is not None:
61 list = r.group(1).split("\r\n")
62 for i in list:
59 if regex is not None:
60 hosts_list = regex.group(1).splitlines()
61 for i in hosts_list:
6362 if i != "":
6463 mstr = i.split("\t")
65 item = {'host': mstr[1], 'type': "A", 'ip': mstr[0]}
66 self.items.append(item)
64 host = mstr[1]
65 record = "A"
66 ip = mstr[0]
67 self.add_host_info_to_items(ip, host, record)
6768
6869 self.isZoneVuln = False
69 output= output.replace('\\$', '')
70 r = re.search(
70 output = output.replace('\\$', '')
71 regex = re.search(
7172 "Whoah, it worked - misconfigured DNS server found:([^$]+)\There isn't much point continuing, you have everything.", output)
7273
73 if r is not None:
74
74 if regex is not None:
7575 self.isZoneVuln = True
76 list = r.group(1).split("\n")
77 for i in list:
78
76 dns_list = regex.group(1).splitlines()
77 for i in dns_list:
7978 if i != "":
8079 mstr = i.split()
8180 if (mstr and mstr[0] != "" and len(mstr) > 3 and mstr[3] in valid_records):
82 item = {'host': mstr[0],
83 'type': mstr[3], 'ip': mstr[4]}
84 self.items.append(item)
81 host = mstr[0]
82 record = mstr[3]
83 ip = mstr[4]
84 self.add_host_info_to_items(ip, host, record)
85
86 def add_host_info_to_items(self, ip_address, hostname, record):
87 data = {}
88 exists = False
89 for item in self.items:
90 if ip_address in item['ip']:
91 item['hosts'].append(hostname)
92 exists = True
93
94 if not exists:
95 data['ip'] = ip_address
96 data['hosts'] = [hostname]
97 data['record'] = record
98 self.items.append(data)
8599
86100
87101 class FiercePlugin(core.PluginBase):
102116 r'^(sudo fierce|fierce|sudo fierce\.pl|fierce\.pl|perl fierce\.pl|\.\/fierce\.pl).*?')
103117 global current_path
104118
119 self.xml_arg_re = re.compile(r"^.*(>\s*[^\s]+).*$")
120
105121 def canParseCommandString(self, current_input):
106122 if self._command_regex.match(current_input.strip()):
107123 return True
110126
111127 def resolveCNAME(self, item, items):
112128 for i in items:
113 if (i['host'] == item['ip']):
129 if (item['ip'] in i['hosts']):
114130 item['ip'] = i['ip']
115131 return item
116132 try:
121137
122138 def resolveNS(self, item, items):
123139 try:
124 item['host'] = item['ip']
140 item['hosts'][0] = item['ip']
125141 item['ip'] = socket.gethostbyname(item['ip'])
126142 except:
127143 pass
134150
135151 item['isResolver'] = False
136152 item['isZoneVuln'] = False
137 if (item['type'] == "CNAME"):
153 if (item['record'] == "CNAME"):
138154 self.resolveCNAME(item, parser.items)
139 if (item['type'] == "NS"):
155 if (item['record'] == "NS"):
140156 self.resolveNS(item, parser.items)
141157 item['isResolver'] = True
142158 item['isZoneVuln'] = parser.isZoneVuln
148164 item['ip'] = ''
149165
150166 for item in parser.items:
151
152167 if item['ip'] == "127.0.0.1" or item['ip'] == '':
153168 continue
154 h_id = self.createAndAddHost(item['ip'])
155 i_id = self.createAndAddInterface(
156 h_id,
169 h_id = self.createAndAddHost(
157170 item['ip'],
158 ipv4_address=item['ip'],
159 hostname_resolution=[item['host']])
171 hostnames=item['hosts'])
160172
161173 if item['isResolver']:
162 s_id = self.createAndAddServiceToInterface(
174 s_id = self.createAndAddServiceToHost(
163175 h_id,
164 i_id,
165176 "domain",
166177 "tcp",
167178 ports=['53'])
175186 ref=["CVE-1999-0532"])
176187
177188 def processCommandString(self, username, current_path, command_string):
178 return None
189 self._output_file_path = os.path.join(
190 self.data_path,
191 "%s_%s_output-%s.txt" % (
192 self.get_ws(),
193 self.id,
194 random.uniform(1, 10))
195 )
196
197 arg_match = self.xml_arg_re.match(command_string)
198
199 if arg_match is None:
200 return "%s > %s" % (command_string, self._output_file_path)
201 else:
202 return re.sub(arg_match.group(1),
203 r"> %s" % self._output_file_path,
204 command_string)
179205
180206
181207 def createPlugin():
3333 TODO: Test goohost output version. Handle what happens if the parser doesn't support it.
3434 TODO: Test cases.
3535
36 @param goohost_filepath A proper simple report generated by goohost
3736 @param goohost_scantype You could select scan type ip, mail or host
3837 """
3938
40 def __init__(self, goohost_filepath, goohost_scantype):
41 self.filepath = goohost_filepath
42 self.scantype = goohost_scantype
39 def __init__(self, output, goohost_scantype):
4340
44 with open(self.filepath, "r") as f:
45
46 line = f.readline()
47 self.items = []
48 while line:
49 if self.scantype == 'ip':
50 minfo = line.split()
51 item = {'host': minfo[0], 'ip': minfo[1]}
52 elif self.scantype == 'host':
53 line = line.strip()
54 item = {'host': line, 'ip': self.resolve(line)}
55 else:
56 item = {'data': line}
57
58 self.items.append(item)
59 line = f.readline()
41 self.items = []
42 lines = filter(None, output.split('\n'))
43 for line in lines:
44 if goohost_scantype == 'ip':
45 data = line.split()
46 item = {'host': data[0], 'ip': data[1]}
47 self.add_host_info_to_items(item['ip'], item['host'])
48 elif goohost_scantype == 'host':
49 data = line.strip()
50 item = {'host': data, 'ip': self.resolve(data)}
51 self.add_host_info_to_items(item['ip'], item['host'])
52 else:
53 item = {'data': line}
6054
6155 def resolve(self, host):
6256 try:
6458 except:
6559 pass
6660 return host
61
62 def add_host_info_to_items(self, ip_address, hostname):
63 data = {}
64 exists = False
65 for item in self.items:
66 if ip_address in item['ip']:
67 item['hosts'].append(hostname)
68 exists = True
69
70 if not exists:
71 data['ip'] = ip_address
72 data['hosts'] = [hostname]
73 self.items.append(data)
6774
6875
6976 class GoohostPlugin(core.PluginBase):
8289 self._current_path = None
8390 self._command_regex = re.compile(
8491 r'^(sudo goohost\.sh|goohost\.sh|sh goohost\.sh|\.\/goohost\.sh).*?')
85 self.scantype = "host"
8692 self.host = None
8793
8894 global current_path
8995 self.output_path = None
96 self._command_string = None
9097
9198 def parseOutputString(self, output, debug=False):
9299 """
93 This method will discard the output the shell sends, it will read it from
94 the xml where it expects it to be present.
100 This method will check if the import was made through the console or by importing a Goohost report.
101
102 Import from Console:The method will take the path of the report generated by Goohost from the output the shell sends and will read
103 the information from the txt where it expects it to be present.
104
105 Import from Report: The method receives the output of the txt report as parameter.
106
107 self.scantype defines the method used to generate the Goohost report
95108
96109 NOTE: if 'debug' is true then it is being run from a test case and the
97110 output being sent is valid.
98111 """
99112
100 if self.output_path is None:
101 mypath = re.search("Results saved in file (\S+)", output)
102 if mypath is not None:
103 self.output_path = self._current_path + "/" + mypath.group(1)
104 else:
105 return False
113 if self._command_string:
114 # Import from console
115 self.scantype = self.define_scantype_by_command(self._command_string)
116 report_output = output
117 output = self.read_output_file(report_output)
118 else:
119 # Import from report
120 self.scantype = self.define_scantype_by_output(output)
106121
107122 if debug:
108123 parser = GoohostParser(output, self.scantype)
109124 else:
110 if not os.path.exists(self.output_path):
111 return False
112
113 parser = GoohostParser(self.output_path, self.scantype)
114
125 parser = GoohostParser(output, self.scantype)
115126 if self.scantype == 'host' or self.scantype == 'ip':
116127 for item in parser.items:
117 h_id = self.createAndAddHost(item['ip'])
118 i_id = self.createAndAddInterface(
119 h_id,
128 h_id = self.createAndAddHost(
120129 item['ip'],
121 ipv4_address=item['ip'],
122 hostname_resolution=item['host'])
130 hostnames=item['hosts'])
123131
124132 del parser
125133
128136 Set output path for parser...
129137 """
130138 self._current_path = current_path
139 self._command_string = command_string
131140
132 def setHost(self):
133 pass
141 def define_scantype_by_command(self, command):
142 method_regex = re.compile(r'-m (mail|host|ip)')
143 method = method_regex.search(command)
144 if method:
145 return method.group(1)
146
147 return 'host'
148
149 def define_scantype_by_output(self, output):
150 lines = output.split('\n')
151 line = lines[0].split(' ')
152
153 if len(line) == 1:
154 return 'host'
155 elif len(line) == 2:
156 return 'ip'
157
158 def read_output_file(self, report_path):
159 mypath = re.search("Results saved in file (\S+)", report_path)
160 if not mypath:
161 return False
162 else:
163 self.output_path = self._current_path + "/" + mypath.group(1)
164 if not os.path.exists(self.output_path):
165 return False
166 with open(self.output_path, 'r') as report:
167 output = report.read()
168
169 return output
134170
135171
136172 def createPlugin():
137173 return GoohostPlugin()
138174
139175 if __name__ == '__main__':
140 parser = GoohostParser(sys.argv[1])
176 with open('/home/javier/Plugins/goohost/report-10071-google.com.txt','r') as report:
177 output = report.read()
178 parser = GoohostPlugin()
179 parser.parseOutputString(output)
141180 for item in parser.items:
142181 if item.status == 'up':
143182 print item
1010 import re
1111 import os
1212 import sys
13 import logging
1314
1415 try:
1516
2122 ETREE_VERSION = ET.VERSION
2223
2324 ETREE_VERSION = [int(i) for i in ETREE_VERSION.split('.')]
25
26 logger = logging.getLogger(__name__)
2427
2528 current_path = os.path.abspath(os.getcwd())
2629
6871 """
6972
7073 def __init__(self, xml_output):
71
7274 tree, type_report = self.parse_xml(xml_output)
7375
7476 if not tree or type_report is None:
104106 type_report = None
105107
106108 except SyntaxError, err:
107 self.devlog('SyntaxError: %s. %s' % (err, xml_output))
109 logger.error('SyntaxError: %s.' % (err))
108110 return None, None
109111
110112 return tree, type_report
253255 self.node = item_node
254256 self.ip = item_node.get('value')
255257 self.os = self.get_text_from_subnode('OS')
256
258 self.hostname = self.get_hostname(item_node)
257259 self.vulns = self.getResults(item_node)
258260
259261 def getResults(self, tree):
266268 for self.issues in tree.findall('INFOS/CAT'):
267269 for v in self.issues.findall('INFO'):
268270 yield ResultsScanReport(v, self.issues)
271 for self.issues in tree.findall('SERVICES/CAT'):
272 for v in self.issues.findall('SERVICE'):
273 yield ResultsScanReport(v, self.issues)
274 for self.issues in tree.findall('PRACTICES/CAT'):
275 for v in self.issues.findall('PRACTICE'):
276 yield ResultsScanReport(v, self.issues)
269277
270278 def get_text_from_subnode(self, subnode_xpath_expr):
271279 """
278286 return sub_node.text
279287
280288 return None
289
290 def get_hostname(self, node):
291 hostname = node.get('name')
292
293 if hostname == 'No registered hostname':
294 return ""
295
296 return hostname
281297
282298
283299 class ResultsScanReport():
293309 self.severity = self.node.get('severity')
294310 self.title = self.get_text_from_subnode('TITLE')
295311 self.cvss = self.get_text_from_subnode('CVSS_BASE')
296 self.pci = self.get_text_from_subnode('PCI_FLAG')
297312 self.diagnosis = self.get_text_from_subnode('DIAGNOSIS')
298313 self.solution = self.get_text_from_subnode('SOLUTION')
299314 self.result = self.get_text_from_subnode('RESULT')
315 self.consequence = self.get_text_from_subnode('CONSEQUENCE')
300316
301317 self.desc = cleaner_results(self.diagnosis)
302318 if self.result:
303319 self.desc += '\nResult: ' + cleaner_results(self.result)
320 else:
321 self.desc += ''
322
323 if self.consequence:
324 self.desc += '\nConsequence: ' + cleaner_results(self.consequence)
304325 else:
305326 self.desc += ''
306327
312333 self.node = r
313334 self.ref.append('bid-' + self.get_text_from_subnode('ID'))
314335
336 if self.cvss:
337 self.ref.append('CVSS BASE: ' + self.cvss)
338
315339 def get_text_from_subnode(self, subnode_xpath_expr):
316340 """
317341 Finds a subnode in the host node and the retrieves a value from it.
336360 self.id = 'Qualysguard'
337361 self.name = 'Qualysguard XML Output Plugin'
338362 self.plugin_version = '0.0.2'
339 self.version = 'Qualysguard 2016 March '
363 self.version = 'Qualysguard 8.17.1.0.2'
340364 self.framework_version = '1.0.0'
341365 self.options = None
342366 self._current_output = None
353377 parser = QualysguardXmlParser(output)
354378
355379 for item in parser.items:
356
357380 h_id = self.createAndAddHost(
358381 item.ip,
359 item.os)
360
361 i_id = self.createAndAddInterface(
362 h_id,
363 item.ip,
364 ipv4_address=item.ip,
365 hostname_resolution=item.ip)
382 item.os,
383 hostnames=[item.hostname])
366384
367385 for v in item.vulns:
368
369386 if v.port is None:
370387 self.createAndAddVulnToHost(
371388 h_id,
378395 else:
379396
380397 web = False
381 s_id = self.createAndAddServiceToInterface(
398 s_id = self.createAndAddServiceToHost(
382399 h_id,
383 i_id,
384400 v.port,
385401 v.protocol,
386402 ports=[str(v.port)],
402418 desc=v.desc,
403419 resolution=v.solution if v.solution else '')
404420
405 n_id = self.createAndAddNoteToService(
406 h_id,
407 s_id,
408 'website',
409 '')
410
411 self.createAndAddNoteToNote(
412 h_id,
413 s_id,
414 n_id,
415 item.ip,
416 '')
417
418421 else:
419422 self.createAndAddVulnToService(
420423 h_id,
66 '''
77 import re
88 import json
9 import socket
910 import logging
11 try:
12 from lxml import etree as ET
13 except ImportError:
14 import xml.etree.ElementTree as ET
1015
1116 from plugins.core import PluginBase
1217
2227 logger = logging.getLogger(__name__)
2328
2429
30 class ReconngParser(object):
31 def __init__(self, output):
32 self._format = self.report_format(output)
33 self.hosts = []
34 self.vulns = []
35
36 if self._format == 'xml':
37 self.parsable_tree = self.get_parseable_xml_output(output)
38 self.parse_xml_report(self.parsable_tree)
39
40 elif self._format == 'json':
41 self.parse_json_report(output)
42
43 def report_format(self, output):
44 xml_format_regex = re.compile(r'^<(.*?)>')
45 json_format_regex = re.compile(r'(^{)')
46
47 if xml_format_regex.match(output):
48 output_format = 'xml'
49 elif json_format_regex.match(output):
50 output_format = 'json'
51 else:
52 return False
53
54 return output_format
55
56 def get_parseable_xml_output(self, xml_output):
57 try:
58 tree = ET.fromstring(xml_output)
59 return tree
60 except IndexError:
61 print "Syntax error"
62 return None
63
64 def parse_xml_report(self, tree):
65 hosts_items = tree.xpath('//hosts/item')
66 self.hosts_from_report(hosts_items)
67
68 vulnerabilities_items = tree.xpath('//vulnerabilities/item')
69 self.vulns_from_report(vulnerabilities_items)
70
71 def parse_json_report(self, output):
72 reconng_data = json.loads(output)
73 hosts_items = reconng_data.get('hosts', '')
74 self.hosts_from_report(hosts_items)
75
76 vulns_items = reconng_data.get('vulnerabilities','')
77 self.vulns_from_report(vulns_items)
78
79 def hosts_from_report(self, hosts_items):
80 for host in hosts_items:
81 host_info = self.get_info_from_host_element(host)
82 self.hosts.append(host_info)
83
84 def vulns_from_report(self, vulns_items):
85 for vuln in vulns_items:
86 vuln_info = self.get_info_from_vuln_element(vuln)
87 self.vulns.append(vuln_info)
88
89 def get_info_from_host_element(self, element):
90 info = {}
91 if self._format == 'xml':
92 info['host'] = element.find('host').text
93 info['ip'] = element.find('ip_address').text
94
95 elif self._format == 'json':
96 info['host'] = element['host']
97 info['ip'] = element['ip_address']
98
99 return info
100
101 def get_info_from_vuln_element(self, element):
102 info = {}
103 if self._format == 'xml':
104 info['host'] = element.find('host').text
105 info['reference'] = element.find('reference').text
106 info['module'] = element.find('module').text
107 info['example'] = element.find('example').text
108 info['category'] = element.find('category').text
109 elif self._format == 'json':
110 info['category'] = element['category']
111 info['host'] = element['host']
112 info['module'] = element['module']
113 info['reference'] = element['reference']
114 info['example'] = element['example']
115
116 if 'XSS' in info['category']:
117 info['severity'] = 'high'
118 elif 'SSL' in info['category']:
119 info['severity'] = 'med'
120 else:
121 info['severity'] = 'info'
122
123 return info
124
125
25126 class ReconngPlugin(PluginBase):
26127 """
27128 Example plugin to parse qualysguard output.
32133 PluginBase.__init__(self)
33134 self.id = 'Reconng'
34135 self.name = 'Reconng XML Output Plugin'
35 self.plugin_version = '0.0.2'
136 self.plugin_version = '0.0.3'
36137 self.version = ''
37138 self.framework_version = ''
38139 self.options = None
39140 self._current_output = None
40141 self._command_regex = re.compile(
41142 r'records added to')
42 self.importing_report = True
43143
44 def load_from_report(self, output):
45 # TODO: add credentials and ports
46 reconng_data = json.loads(output)
47 hosts_id_mapper = {}
48 for host in reconng_data.get('hosts', []):
144 self.host_mapper = {}
145
146 def parseOutputString(self, output):
147 parser = ReconngParser(output)
148
149 for host in parser.hosts:
49150 h_id = self.createAndAddHost(
50 host['ip_address'] or host['host']
151 host['ip'],
152 hostnames=[host['host']]
51153 )
52 hosts_id_mapper[host['host']] = h_id
154 self.host_mapper[host['host']] = h_id
155 for vuln in parser.vulns:
156 if vuln['host'] not in self.host_mapper.keys():
157 ip = self.resolve_host(vuln['host'])
158 h_id = self.createAndAddHost(
159 ip,
160 hostnames=[vuln['host']]
161 )
162 self.host_mapper[vuln['host']] = h_id
163 else:
164 h_id = self.host_mapper[vuln['host']]
53165
54 severity_mapper = {
55 'Information Disclosure': 'informational'
56 }
57 for vulnerability in reconng_data.get('vulnerabilities', []):
58 if vulnerability['host'] not in hosts_id_mapper:
59 logger.warn('Could not find host_id, skipping vulnerability')
60 continue
61 severity = 'info'
62 if 'SSL' in vulnerability['category']:
63 severity = 'med'
64166 self.createAndAddVulnToHost(
65 name='Recon-ng found: ' + vulnerability['example'],
66 desc='Found by module: ' + vulnerability['module'],
67 severity=severity,
68 ref=[vulnerability['reference']],
69 host_id=hosts_id_mapper[vulnerability['host']]
167 name='Recon-ng found: ' + vuln['category'] + ' vulnerability',
168 desc='Found by module: ' + vuln['module'],
169 severity=vuln['severity'],
170 ref=[vuln['reference']],
171 host_id=h_id,
172 data=vuln['example']
70173 )
71174
72 def load_from_shell(self, output):
73 pass
175 def processCommandString(self, username, current_path, command_string):
176 return
74177
75 def parseOutputString(self, output):
76 if self.importing_report:
77 self.load_from_report(output)
78 else:
79 self.load_from_shell(output)
178 def resolve_host(self, host):
179 try:
180 return socket.gethostbyname(host)
181 except:
182 pass
183 return host
80184
81 def parseCommandString(self, username, current_path, command_string):
82 self.importing_report = False
83185
84186 def createPlugin():
85 return ReconngPlugin()
187 return ReconngPlugin()
188
189 if __name__ == '__main__':
190 with open("~/results_hosts_vulns.xml", "r") as report:
191 parser = ReconngParser(report.read())
192 # for item in parser.items:
193 # if item.status == 'up':
194 # print item
99
1010 from plugins import core
1111 import re
12 import os
1213 import socket
1314 import json
1415
3536 core.PluginBase.__init__(self)
3637 self.id = "wpscan"
3738 self.name = "WPscan"
38 self.plugin_version = "0.0.1"
39 self.version = "2.9.1"
39 self.plugin_version = "0.2"
40 self.version = "3.4.5"
4041 self._command_regex = re.compile(
4142 r"^((sudo )?(ruby )?(\.\/)?(wpscan)(.rb)?)")
42 self.addSetting("WPscan path", str, "~/wpscan")
43 self.wpPath = self.getSetting("WPscan path")
44 self.themes = {}
45 self.plugins = {}
46 self.wpversion = ''
47 self.risks = {'AUTHBYPASS' : 'high',
48 'BYPASS' : 'med',
49 'CSRF' : 'med',
50 'DOS' : 'med',
51 'FPD' : 'info',
52 'LFI' : 'high',
53 'MULTI' : 'unclassified',
54 'PRIVESC' : 'high',
55 'RCE' : 'critical',
56 'REDIRECT' : 'low',
57 'RFI' : 'critical',
58 'SQLI' : 'high',
59 'SSRF' : 'med',
60 'UNKNOWN' : 'unclassified',
61 'UPLOAD' : 'critical',
62 'XSS' : 'high',
63 'XXE' : 'high'
64 }
43 self.wpPath = self.get_wpscan_filepath()
44 self.addSetting("WPscan path", str, self.wpPath)
45 self.themes = {}
46 self.plugins = {}
47 self.wpversion = ''
48 self.risks = {'AUTHBYPASS': 'high',
49 'BYPASS': 'med',
50 'CSRF': 'med',
51 'DOS': 'med',
52 'FPD': 'info',
53 'LFI': 'high',
54 'MULTI': 'unclassified',
55 'OBJECTINJECTION': 'med',
56 'PRIVESC': 'high',
57 'RCE': 'critical',
58 'REDIRECT': 'low',
59 'RFI': 'critical',
60 'SQLI': 'high',
61 'SSRF': 'med',
62 'UNKNOWN': 'unclassified',
63 'UPLOAD': 'critical',
64 'XSS': 'high',
65 'XXE': 'high'}
66
67 def get_wpscan_filepath(self):
68 home = os.path.expanduser("~")
69
70 wpscan_path = os.path.join(home, '.wpscan')
71 if os.path.exists(wpscan_path):
72 return wpscan_path
73 else:
74 return None
75
76 def search_file_in_wpscan_folder(self, wp_file):
77 db_path = os.path.join(self.wpPath, 'db', wp_file)
78 data_path = os.path.join(self.wpPath, 'data', wp_file)
79 if os.path.exists(db_path):
80 return db_path
81 elif os.path.exists(data_path):
82 return data_path
6583
6684 def getPort(self, host, proto):
6785 p = re.search(r"\:([0-9]+)\/", host)
7088 elif proto == 'https':
7189 return 443
7290 else:
73 return 80
74
91 return 80
7592
7693 def parseOutputWpscan(self, output):
77 sp = output.split('0m Name:') #cut by name
78 for e in sp:
79 if 'Title:' in e:
94 sp = output.split('0m Name:') # cut by name
95 for e in sp:
96 if 'Title:' in e:
8097 if 'WordPress version' in e:
81 r = re.search(r'WordPress version (\d.\w)', e) #get wordpress version
98 r = re.search(r'WordPress version (\d.\w)', e) # get wordpress version
8299 self.wpversion = r.group(1)
83100
84101 elif 'wp-content/themes/' in e:
85 name = re.findall(r"Location: .+themes\/(.+)\/", e) # get theme name
86 title = re.findall(r"Title: (.+)", e) # get vulnerabilities title
87 self.themes[name[0]] = title #insert theme in dicc {'themeName' : ['titles', 'titles']}
102 name = re.findall(r"Location: .+themes\/(.+)\/", e) # get theme name
103 title = re.findall(r"Title: (.+)", e) # get vulnerabilities title
104 self.themes[name[0]] = title # insert theme in dicc {'themeName' : ['titles', 'titles']}
88105
89106 else:
90 name = re.findall(r"Location: .+plugins\/(.+)\/", e) #get plugin name
91 title = re.findall(r"Title: (.+)", e) #get vulnerabilities title
92 self.plugins[name[0]] = title #insert plugin in dicc {'plugin' : ['titles', 'titles']}
93
94 def addThemesOrPluginsVulns(self, db, dic, host_id, serv_id, domain, wp_url, name):
95 with open(self.wpPath+'/data/'+db, "r") as data:
107 name = re.findall(r"Location: .+plugins\/(.+)\/", e) # get plugin name
108 title = re.findall(r"Title: (.+)", e) # get vulnerabilities title
109 self.plugins[name[0]] = title # insert plugin in dicc {'plugin' : ['titles', 'titles']}
110
111 def addThemesOrPluginsVulns(self, wpscan_db_filename, dic, host_id, serv_id, domain, wp_url, name):
112 db_file_path = self.search_file_in_wpscan_folder(wpscan_db_filename)
113 with open(db_file_path, "r") as data:
96114 j = json.load(data)
97115 for p in dic:
98116 for title in dic[p]:
99 for vuln in j[p]['vulnerabilities']: #iter vulnerabilities
100 if vuln['title'] == title: # if output title is equal
101 title = vuln['title'] #title
102 risk = self.risks[vuln['vuln_type']] #vuln type (xss,rce,lfi,etc) - risk
103 location = wp_url+'wp-content/'+name+'/'+p+'/'
104 if vuln['references'].has_key('url') == True: #if references
117 for vuln in j[p]['vulnerabilities']: # iter vulnerabilities
118 if vuln['title'] == title: # if output title is equal
119 title = vuln['title'] # title
120 risk = self.risks[vuln['vuln_type']] # vuln type (xss,rce,lfi,etc) - risk
121 location = wp_url+'wp-content/'+name+'/'+p+'/'
122 if vuln['references'].has_key('url') == True: # if references
105123 refs = vuln['references']['url'] #references[]
106124 else:
107 refs = [] #references null
108 self.createAndAddVulnWebToService(host_id, serv_id, title, severity = risk, website = domain, ref = refs, path = location)
109
110
111 def addWPVulns(self, db, version, host_id, serv_id, domain):
112 with open(self.wpPath+'/data/'+db, "r") as data:
125 refs = [] # references null
126 self.createAndAddVulnWebToService(
127 host_id,
128 serv_id,
129 title,
130 severity=risk,
131 website=domain,
132 ref=refs,
133 path=location)
134
135 def addWPVulns(self, wpscan_db_filename, version, host_id, serv_id, domain):
136 db_file_path = self.search_file_in_wpscan_folder(wpscan_db_filename)
137 with open(db_file_path, "r") as data:
113138 j = json.load(data)
114 for vuln in j[version]['vulnerabilities']: #iter vulnerabilities
115 title = vuln['title'] #title
116 risk = self.risks[vuln['vuln_type']] #vuln type (xss,rce,lfi,etc) - risk
117 if vuln['references'].has_key('url') == True: #if references
118 refs = vuln['references']['url'] #references[]
139 for vuln in j[version]['vulnerabilities']: # iter vulnerabilities
140 title = vuln['title'] # title
141 risk = self.risks[vuln['vuln_type']] # vuln type (xss,rce,lfi,etc) - risk
142 if vuln['references'].has_key('url') == True: # if references
143 refs = vuln['references']['url'] # references[]
119144 else:
120 refs = [] #references null
121 self.createAndAddVulnWebToService(host_id, serv_id, title, severity = risk, website = domain, ref = refs)
122
145 refs = [] # references null
146 self.createAndAddVulnWebToService(
147 host_id,
148 serv_id,
149 title,
150 severity=risk,
151 website=domain,
152 ref=refs)
123153
124154 def parseOutputString(self, output, debug=False):
125155 """Parses the output given as a string by the wpscan tool and creates
126 the appropiate hosts, interface, service and vulnerabilites. Return
156 the appropiate hosts, service and vulnerabilites. Return
127157 nothing.
128158 """
129159 self.parseOutputWpscan(output)
130 wp_url = re.search(r"URL: ((http[s]?)\:\/\/([\w\.]+)[.\S]+)", output)
160 wp_url = re.search(r"URL: ((http[s]?)\:\/\/([\w\.]+)[.\S]+)", output)
131161 service, base_url = self.__get_service_and_url_from_output(output)
132 port = self.getPort(wp_url.group(1), service)
133 host_ip = socket.gethostbyname_ex(base_url)[2][0]
134 host_id = self.createAndAddHost(host_ip)
135 interface_id = self.createAndAddInterface(host_id, host_ip,
136 ipv4_address=host_ip,
137 hostname_resolution=base_url)
138
139 service_id = self.createAndAddServiceToInterface(host_id, interface_id,
140 service, "tcp", ports = [port])
141
142 potential_vulns = re.findall(r"(\[\!\].*)", output)
143 for potential_vuln in potential_vulns:
144 vuln_name, severity = self.__get_name_and_severity(potential_vuln)
145 if vuln_name is not None:
146 vuln = potential_vuln # they grow up so fast
147 path = self.__get_path_from_vuln(vuln)
148 self.createAndAddVulnWebToService(host_id, service_id,
149 name=vuln_name,
150 website=base_url,
151 path=path, severity=severity)
152
153 if len(self.plugins) > 0:
154 self.addThemesOrPluginsVulns('plugins.json', self.plugins, host_id, service_id, base_url, wp_url.group(1), 'plugins')
155 if len(self.wpversion) > 0:
156 self.addWPVulns('wordpresses.json', self.wpversion, host_id, service_id, base_url)
157 if len(self.themes) > 0:
158 self.addThemesOrPluginsVulns('themes.json', self.themes, host_id, service_id, base_url, wp_url.group(1), 'themes')
159
160
162 if service and base_url:
163 port = self.getPort(wp_url.group(1), service)
164 host_ip = socket.gethostbyname_ex(base_url)[2][0]
165 host_id = self.createAndAddHost(
166 host_ip,
167 hostnames=[base_url])
168
169 service_id = self.createAndAddServiceToHost(host_id,
170 service,
171 "tcp",
172 ports=[port])
173
174 potential_vulns = re.findall(r"(\[\!\].*)", output)
175 for potential_vuln in potential_vulns:
176 vuln_name, severity = self.__get_name_and_severity(potential_vuln)
177 if vuln_name is not None:
178 vuln = potential_vuln # they grow up so fast
179 path = self.__get_path_from_vuln(vuln)
180 self.createAndAddVulnWebToService(host_id, service_id,
181 name=vuln_name,
182 website=base_url,
183 path=path, severity=severity)
184
185 if len(self.plugins) > 0:
186 self.addThemesOrPluginsVulns(
187 'plugins.json',
188 self.plugins,
189 host_id,
190 service_id,
191 base_url,
192 wp_url.group(1),
193 'plugins')
194
195 if len(self.wpversion) > 0:
196 self.addWPVulns(
197 'wordpresses.json',
198 self.wpversion,
199 host_id,
200 service_id,
201 base_url)
202
203 if len(self.themes) > 0:
204 self.addThemesOrPluginsVulns(
205 'themes.json',
206 self.themes,
207 host_id,
208 service_id,
209 base_url,
210 wp_url.group(1),
211 'themes')
212
161213 def __get_service_and_url_from_output(self, output):
162214 """ Return the service (http or https) and the base URL (URL without
163215 protocol) from a given string. In case more than one URL is found,
164216 return the service and base_url of the first one, ignore others.
165217 """
166218 search_url = re.search(r"URL: ((http[s]?)\:\/\/([\w\.]+)[.\S]+)", output)
167 service, base_url = search_url.group(2), search_url.group(3)
168 return service, base_url
219 if not search_url:
220 return None, None
221 else:
222 service, base_url = search_url.group(2), search_url.group(3)
223 return service, base_url
169224
170225 def __get_name_and_severity(self, potential_vuln):
171226 """Regex the potential_vuln string against a regex with all
0 import requests
1 import json
2
3
4 class ApiError(Exception):
5 def __init__(self, message):
6 super(ApiError, self).__init__(message)
7
8
9 class Structure:
10 def __init__(self, **entries):
11 self.__dict__.update(entries)
12
13 @property
14 def id(self):
15 if hasattr(self, '_id'):
16 return self._id
17 return None
18
19 @property
20 def class_signature(self):
21 if hasattr(self, 'type'):
22 return self.type
23 return None
24
25 @property
26 def parent_id(self):
27 if hasattr(self, 'parent'):
28 return self.parent
29 return None
30
31 def getMetadata(self):
32 if hasattr(self, 'metadata'):
33 return self.metadata
34 return None
35
36
37 class Api:
38 def __init__(self, workspace, username, password, base='http://127.0.0.1:5985/_api/'):
39 self.base = base
40 self.workspace = workspace
41 self.cookies = self.login(username, password)
42 if self.cookies is None:
43 raise UserWarning('Invalid username or password')
44
45 def _url(self, path):
46 return self.base + 'v2/' + path
47
48 def _get(self, url, object_name):
49 response = requests.get(url, cookies=self.cookies)
50 if response.status_code == 401:
51 raise ApiError('Unauthorized operation trying to get {}'.format(object_name))
52 if response.status_code != 200:
53 raise ApiError('Cannot fetch {}'.format(object_name))
54 return json.loads(response.content)
55
56 def _post(self, url, data, object_name):
57 response = requests.post(url, json=data, cookies=self.cookies)
58 if response.status_code == 401:
59 raise ApiError('Unauthorized operation trying to create {}'.format(object_name))
60 if response.status_code != 201:
61 raise ApiError('Unable to create {}'.format(object_name))
62 return json.loads(response.content)
63
64 def _put(self, url, data, object_name):
65 response = requests.put(url, json=data, cookies=self.cookies)
66 if response.status_code == 401:
67 raise ApiError('Unauthorized operation trying to update {}'.format(object_name))
68 if response.status_code != 200:
69 raise ApiError('Unable to update {}'.format(object_name))
70 return json.loads(response.content)
71
72 def _delete(self, url, object_name):
73 response = requests.delete(url, cookies=self.cookies)
74 if response.status_code == 401:
75 raise ApiError('Unauthorized operation trying to delete {}'.format(object_name))
76 if response.status_code != 204:
77 raise ApiError('Unable to delete {}'.format(object_name))
78 return response.ok
79
80 def login(self, username, password):
81 auth = {"email": username, "password": password}
82 try:
83 resp = requests.post(self.base + 'login', json=auth)
84 if resp.status_code == 401:
85 return None
86 else:
87 return resp.cookies
88 except requests.adapters.ConnectionError:
89 return None
90 except requests.adapters.ReadTimeout:
91 return None
92
93 def get_vulnerabilities(self):
94 return [Structure(**item['value']) for item in self._get(self._url('ws/{}/vulns'.format(self.workspace)),
95 'vulnerabilities')['vulnerabilities']]
96
97 def update_vulnerability(self, vulnerability):
98 return Structure(**self._put(self._url('ws/{}/vulns/{}/'.format(self.workspace, vulnerability.id)),
99 vulnerability.__dict__, 'vulnerability'))
100
101 def delete_vulnerability(self, vulnerability_id):
102 return self._delete(self._url('ws/{}/vulns/{}/'.format(self.workspace, vulnerability_id)), 'vulnerability')
103
104 def get_services(self):
105 return [Structure(**item['value']) for item in self._get(self._url('ws/{}/services'.format(self.workspace)),
106 'services')['services']]
107
108 def get_filtered_services(self, **params):
109 services = self.get_services()
110 filtered_services = []
111 for key, value in params.items():
112 for service in services:
113 if hasattr(service, key) and \
114 (getattr(service, key, None) == value or str(getattr(service, key, None)) == value):
115 filtered_services.append(service)
116 return filtered_services
117
118 def update_service(self, service):
119 if isinstance(service.ports, int):
120 service.ports = [service.ports]
121 else:
122 service.ports = []
123 return Structure(**self._put(self._url('ws/{}/services/{}/'.format(self.workspace, service.id)),
124 service.__dict__, 'service'))
125
126 def delete_service(self, service_id):
127 return self._delete(self._url('ws/{}/services/{}/'.format(self.workspace, service_id)), 'service')
128
129 def get_hosts(self):
130 return [Structure(**item['value']) for item in self._get(self._url('ws/{}/hosts'.format(self.workspace)),
131 'hosts')['rows']]
132
133 def get_filtered_hosts(self, **params):
134 hosts = self.get_hosts()
135 filtered_hosts = []
136 for key, value in params.items():
137 for host in hosts:
138 if hasattr(host, key) and \
139 (getattr(host, key, None) == value or str(getattr(host, key, None)) == value):
140 filtered_hosts.append(host)
141 return filtered_hosts
142
143 def update_host(self, host):
144 return Structure(**self._put(self._url('ws/{}/hosts/{}/'.format(self.workspace, host.id)),
145 host.__dict__, 'hosts'))
146
147 def delete_host(self, host_id):
148 return self._delete(self._url('ws/{}/hosts/{}/'.format(self.workspace, host_id)), 'host')
149
150 def get_vulnerability_templates(self):
151 return [Structure(**item['doc']) for item in self._get(self._url('vulnerability_template'), 'templates')['rows']]
152
153 def get_filtered_templates(self, **params):
154 templates = self.get_vulnerability_templates()
155 filtered_templates = []
156 for key, value in params.items():
157 for template in templates:
158 if hasattr(template, key) and \
159 (getattr(template, key, None) == value or str(getattr(template, key, None)) == value):
160 filtered_templates.append(template)
161 return filtered_templates
1717 from difflib import SequenceMatcher
1818 from email.mime.multipart import MIMEMultipart
1919 from email.mime.text import MIMEText
20 import requests
21 import json
2220 import ast
23 from config.configuration import getInstanceConfiguration
24 from persistence.server import models
25 from persistence.server import server
26 from persistence.server.server import login_user
27 from persistence.server.server_io_exceptions import ResourceDoesNotExist, ConflictInDatabase
2821 from validator import *
29 import urlparse
30
22 from api import Api
3123
3224 logger = logging.getLogger('Faraday searcher')
3325
3426 reload(sys)
3527 sys.setdefaultencoding("utf-8")
36
37 CONF = getInstanceConfiguration()
38
3928
4029 mail_from = ''
4130 mail_password = ''
6857 return SequenceMatcher(None, a, b).ratio()
6958
7059
71 def get_cwe(data, _server='http://127.0.0.1:5985/'):
72 logger.debug("Getting vulnerability templates from %s " % _server)
73 try:
74 url = urlparse.urljoin(_server, "_api/v2/vulnerability_template/")
75 session_cookie = CONF.getDBSessionCookies()
76 response = requests.request("GET", url, cookies=session_cookie)
77 if response.status_code == 200:
78 templates = json.loads(response.content)
79 cwe = None
80 for row in templates['rows']:
81 doc = row['doc']
82 _id = doc['_id']
83 name = doc['name']
84 description = doc['description']
85 resolution = doc['resolution']
86 if str(_id) == data or name == data:
87 cwe = {
88 'id': _id,
89 'name': name,
90 'description': description,
91 'resolution': resolution
92 }
93 break
94 return cwe
95 elif response.status_code == 401:
96 logger.error('You are not authorized to get the vulnerability templates')
97 return None
98 else:
99 logger.error('We can\'t get the vulnerability templates')
100 return None
101
102 except Exception as error:
103 logger.error(error)
104 return None
60 def get_cwe(data):
61 logger.debug("Getting vulnerability templates")
62 templates = api.get_filtered_templates(id=data, name=data)
63 if len(templates) > 0:
64 return templates.pop()
65 return None
10566
10667
10768 def is_same_level(model1, model2):
233194
234195 def update_vulnerability(ws, vuln, key, value, _server):
235196 if key == 'template':
236 cwe = get_cwe(value, _server)
197 cwe = get_cwe(value)
237198 if cwe is None:
238199 logger.error("%s: cwe not found" % value)
239200 return False
240201
241 vuln.name = cwe['name']
242 vuln.description = cwe['description']
243 vuln.desc = cwe['description']
244 vuln.resolution = cwe['resolution']
202 vuln.name = cwe.name
203 vuln.description = cwe.description
204 vuln.desc = cwe.description
205 vuln.resolution = cwe.resolution
245206
246207 logger.info("Applying template '%s' to vulnerability '%s' with id '%s'" % (value, vuln.name, vuln.id))
247208
259220 key = key.strip('-')
260221 to_add = False
261222
262 field = get_field(vuln, key)
263 if field is not None:
223 is_custom_field = False
224 if key in vuln.custom_fields:
225 field = vuln.custom_fields
226 is_custom_field = True
227 else:
228 field = get_field(vuln, key)
229
230 if field is not None and is_custom_field is False:
264231 if isinstance(field, str) or isinstance(field, unicode):
265232 setattr(vuln, key, value)
266233 logger.info(
274241
275242 logger.info(action)
276243
244 if field is not None and is_custom_field is True:
245 vuln.custom_fields[key] = value
246 logger.info(
247 "Changing custom field %s to %s in vulnerability '%s' with id %s" % (key, value, vuln.name, vuln.id))
248
277249 try:
278 if vuln.class_signature == "Vulnerability":
279 models.update_vuln(ws, vuln)
280
281 elif vuln.class_signature == "VulnerabilityWeb":
282 models.update_vuln_web(ws, vuln)
283
284 except ConflictInDatabase:
285 logger.error("There was a conflict trying to save '%s' with ID: %s" % (vuln.name, vuln.id))
286 return False
250 api.update_vulnerability(vuln)
287251 except Exception as error:
288252 logger.error(error)
289253 return False
318282
319283 logger.info(action)
320284 try:
321 models.update_service(ws, service, "")
285 api.update_service(service)
322286 except Exception as error:
323287 logger.error(error)
324288 return False
352316
353317 logger.info(action)
354318 try:
355 models.update_host(ws, host, "")
319 api.update_host(host)
356320 except Exception as error:
357321 logger.error(error)
358322 return False
363327
364328 def get_parent(ws, parent_tag):
365329 logger.debug("Getting parent")
366 try:
367 parent = models.get_host(ws, parent_tag) or models.get_service(ws, parent_tag)
368 except ResourceDoesNotExist:
369 parent = models.get_hosts(ws, name=parent_tag) or models.get_services(ws, name=parent_tag)
370 if len(parent) == 0:
371 return None
372
373 return parent
330 return api.get_filtered_services(id=parent_tag, name=parent_tag) or \
331 api.get_filtered_hosts(id=parent_tag, name=parent_tag)
374332
375333
376334 def filter_objects_by_parent(_objects, parent):
417375 return False
418376 return True
419377
378 if isinstance(temp_value, int):
379 return value == str(temp_value)
380
420381 if value.encode("utf-8") != temp_value.encode("utf-8"):
421382 return False
422383 return True
499460 update_host(ws, obj, key, value)
500461
501462 elif command == 'DELETE':
502 if obj.class_signature == 'VulnerabilityWeb':
503 models.delete_vuln_web(ws, obj.id)
504 logger.info(" Deleting vulnerability web '%s' with id '%s':" % (obj.name, obj.id))
463 if obj.class_signature == 'VulnerabilityWeb' or obj.class_signature == 'Vulnerability':
464 api.delete_vulnerability(obj.id)
465 logger.info("Deleting vulnerability '%s' with id '%s':" % (obj.name, obj.id))
505466 insert_rule(rule['id'], command, obj, _objs_value)
506467
507 elif obj.class_signature == 'Vulnerability':
508 models.delete_vuln(ws, obj.id)
509 logger.info("Deleting vulnerability '%s' with id '%s':" % (obj.name, obj.id))
510
511468 elif obj.class_signature == 'Service':
512 models.delete_service(ws, obj.id)
469 api.delete_service(obj.id)
513470 logger.info("Deleting service '%s' with id '%s':" % (obj.name, obj.id))
514471
515472 elif obj.class_signature == 'Host':
516 models.delete_host(ws, obj.id)
473 api.delete_host(obj.id)
517474 logger.info("Deleting host '%s' with id '%s':" % (obj.name, obj.id))
518475
519476 elif command == 'EXECUTE':
542499 _vars = list(set(r))
543500 for var in _vars:
544501 value = value_item[var]
545 rule_str = rule_str.replace('{{'+var+'}}', value)
502 rule_str = rule_str.replace('{{' + var + '}}', value)
546503
547504 return ast.literal_eval(rule_str)
548505
715672 ch = logging.StreamHandler()
716673 ch.setLevel(numeric_level)
717674 # create formatter and add it to the handlers
718 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s: %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
675 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s: %(message)s',
676 datefmt='%m/%d/%Y %I:%M:%S %p')
719677
720678 fh.setFormatter(formatter)
721679 ch.setFormatter(formatter)
724682 logger.addHandler(ch)
725683
726684 try:
727 session_cookie = login_user(_server, _user, _password)
728 if not session_cookie:
729 raise UserWarning('Invalid credentials!')
730 else:
731 CONF.setDBUser(_user)
732 CONF.setDBSessionCookies(session_cookie)
733
734 server.AUTH_USER = _user
735 server.AUTH_PASS = _password
736 server.SERVER_URL = _server
737 server.FARADAY_UP = False
738
739685 logger.info('Started')
740686 logger.info('Searching objects into workspace %s ' % workspace)
741687
688 global api
689 api = Api(workspace, _user, _password)
690
742691 logger.debug("Getting hosts ...")
743 hosts = models.get_hosts(workspace)
692 hosts = api.get_hosts()
744693
745694 logger.debug("Getting services ...")
746 services = models.get_services(workspace)
695 services = api.get_services()
747696
748697 logger.debug("Getting vulnerabilities ...")
749 vulns = models.get_all_vulns(workspace)
698 vulns = api.get_vulnerabilities()
750699
751700 if validate_rules():
752701 process_vulnerabilities(workspace, vulns, _server)
758707
759708 logger.info('Finished')
760709
761 except ResourceDoesNotExist:
762 logger.error("Resource not found")
763 os.remove(lockf)
764 exit(0)
765
766710 except Exception as errorMsg:
767711 logger.error(errorMsg)
768712 os.remove(lockf)
667667 else:
668668 flask.abort(404, "Vulnerability not found")
669669
670 @route('/<int:vuln_id>/attachments/', methods=['GET'])
671 def get_attachments_by_vuln(self, workspace_name, vuln_id):
672 workspace = self._get_workspace(workspace_name)
673 vuln_workspace_check = db.session.query(VulnerabilityGeneric, Workspace.id).join(
674 Workspace).filter(VulnerabilityGeneric.id == vuln_id,
675 Workspace.name == workspace.name).first()
676 if vuln_workspace_check:
677 files = db.session.query(File).filter_by(object_type='vulnerability',
678 object_id=vuln_id).all()
679 res = {}
680 for file_obj in files:
681 ret, errors = EvidenceSchema().dump(file_obj)
682 if errors:
683 raise ValidationError(errors, data=ret)
684 res[file_obj.filename] = ret
685
686 return flask.jsonify(res)
687 else:
688 flask.abort(404, "Vulnerability not found")
689
690
670691 @route('/<int:vuln_id>/attachment/<attachment_filename>/', methods=['DELETE'])
671692 def delete_attachment(self, workspace_name, vuln_id, attachment_filename):
672693 vuln_workspace_check = db.session.query(VulnerabilityGeneric, Workspace.id).join(
4646 def check_postgres():
4747 with app.app_context():
4848 try:
49 result = str(db.engine.execute("SELECT version()"))
50 return result
49 result = (str(db.session.query("version()").one()),db.session.query("current_setting('server_version_num')").one())
50 return result
5151 except sqlalchemy.exc.OperationalError:
5252 return False
5353 except sqlalchemy.exc.ArgumentError:
188188 """Prints the status of PostgreSQL using check_postgres()"""
189189 exit_code = 0
190190 result = check_postgres()
191 if result:
192 print('[{green}+{white}] PostgreSQL is running'.\
191 print(result[0])
192 if result[1]<90400:
193 print('[{red}-{white}] PostgreSQL is running, but needs to be 9.4 or newer, please update PostgreSQL'.\
194 format(red=Fore.RED, white=Fore.WHITE))
195 elif result:
196 print('[{green}+{white}] PostgreSQL is running and up to date'.\
193197 format(green=Fore.GREEN, white=Fore.WHITE))
194198 return exit_code
195199 elif result == False:
77 certificate=
88 keyfile=
99 ;keyfile_pwd=''
10
11 [couchdb]
12 host=localhost
13 port=5984
14 ssl_port=6984
15 user=
16 password=
17 protocol=http
18
17921792 title = BlankColumn(Text)
17931793 confirmed = Column(Boolean, nullable=False, default=False)
17941794 vuln_count = Column(Integer, default=0) # saves the amount of vulns when the report was generated.
1795 markdown = Column(Boolean, default=False, nullable=False)
17951796
17961797 workspace_id = Column(Integer, ForeignKey('workspace.id'), index=True, nullable=False)
17971798 workspace = relationship(
301301
302302 .tab-pane-container {
303303 width: 100%;
304 overflow-y: auto;
305 max-height: calc(100% - 180px);
304306 }
305307
306308 .btn-primary-white {
423425 -moz-user-select: none;
424426 -ms-user-select: none;
425427 user-select: none;
428 top: -5px;
426429 }
427430
428431 /* Hide the browser's default checkbox */
441444
442445 /* When the checkbox is checked, add a blue background */
443446 .chbox-container input:checked ~ .checkmark {
444 background-color: #008000;
447 background-color: #488be6;
445448 }
446449
447450 /* Create the checkmark/indicator (hidden when not checked) */
485488 li.nav-item.has-error:not(.active) a {
486489 color: #a94442;
487490 }
491
492 .nav-item{
493 margin-right: 10px;
494 }
495
488496 .active-toggle{
489497 width: 3%;
490498 text-align: center!important;
557565
558566 .toogle-img-container {
559567 width: 46px;
568 }
569
570 .right-main{
571 overflow-x: hidden;
572 }
573
574 #vuln-preview {
575 position: fixed;
576 z-index: 100000;
577 top: 139px;
578 height: calc(100% - 139px);
579 background-color: #fff;
580 border-left: 1px solid #ddd;
581 border-top: solid 4px #e5e5e5;
582 width: 0;
583 transition: 0.5s;
584 right: -75%;
585 padding: 16px;
586 }
587
588 #vuln-preview.show-preview{
589 transition: width 0.3s!important;
590 width: 70%!important;
591 right: 0!important;
592 }
593
594 .faraday-page-header{
595 width: 100%;
596 }
597
598 .faraday-page-header.show-preview{
599 transition: width 0.3s!important;
600 width: 74.5%!important;
601 }
602
603 #btn_bar.show-preview{
604 transition: width 0.3s!important;
605 width: 73.2%!important;
606 }
607
608 .preview-header {
609 width: 100%;
610 padding: 5px 10px 20px;
611 }
612
613 .preview-section {
614 border-top: 1px solid #ddd;
615 padding: 24px 0;
616 margin-bottom: 22px;
617 }
618
619 .preview-section .form-group{
620 margin-bottom: 0;
621 }
622
623 .preview-icon {
624 color: #aaa;
625 cursor: pointer;
626 text-align: center;
627 padding: 6px 8px;
628 font-size: 0.8em;
629 }
630
631 .preview-icon:hover {
632 background-color: #ddd;
633 color: #777;
634 border-radius: 50px;
635 box-shadow: 2px 2px 10px 0px #aaa;
636 }
637
638 .preview-tag {
639 background-color: #ddd;
640 padding: 2px 8px;
641 border-radius: 3px;
642 font-weight: bold;
643 color: #555;
644 box-shadow: 2px 2px 2px 0 #aaa;
645 margin-right: 10px;
646 }
647
648 .preview-section.row {
649 margin-right: 0;
650 margin-left: 0;
651 margin-bottom: 0;
652 padding-bottom: 12px;
653 }
654
655 .preview-section .tab-pane-header {
656 font-size: 1.1em;
657 overflow-wrap: break-word;
658 }
659
660 .prev-apply-template.active{
661 /*transition: 0.1s;*/
662 width: 75%!important;
663 }
664
665 .prev-apply-template {
666 padding-right: 0;
667 }
668
669 .pretty-text.tab-pane-header {
670 font-size: 1.01em;
671 /* font-weight: normal; */
672 color: #aaa;
673 }
674
675 .text-code {
676 background-color: #f9f9f9;
677 padding: 15px 10px;
678 font-weight: normal;
679 color: #777!important;
680 min-height: 150px;
681 overflow-wrap: break-word;
682 }
683
684 .show-scroll {
685 height: 230px;
686 overflow-y: auto;
687 }
688
689 .show-scroll input {
690 color: #444!important;
691 }
692
693 .margin-bottom-24{
694 margin-bottom: 24px;
695 }
696
697 .input-evidence {
698 height: 40px;
699 width: 100%;
700 position: absolute;
701 top: 0;
702 left: -15px;
703 opacity: 0;
704 cursor: pointer;
705 }
706
707 .upload-options button {
708 margin-bottom: 5px;
709 }
710
711 #attachment-img{
712 width: 100%;
713 max-height: 500px;
714 }
715
716 ul#nav-tabs-container {
717 margin-left: 50px;
718 }
719
720 .padding-left-0{
721 padding-left: 0;
722 }
723
724 .margin-left-0{
725 margin-left: 0;
726 }
727
728 .desc-container {
729 height: 65%;
730 overflow-y: auto;
731 }
732
733 .height-100{
734 height: 100%;
735 }
736
737 .line-breaks{
738 white-space: pre-wrap;
739 line-height: 1.5;
560740 }
6868 <script type="text/javascript" src="script/angular-selection-model.js"></script>
6969 <script type="text/javascript" src="script/angular-file-upload-shim.js"></script><!-- compatibility with older browsers -->
7070 <script type="text/javascript" src="script/angular-file-upload.js"></script>
71 <script type="text/javascript" src="script/angular-file-upload-lib.min.js"></script>
7172 <script type="text/javascript" src="script/ui-bootstrap-tpls-0.14.1.min.js"></script>
7273 <script type="text/javascript" src="script/cryptojs-sha1.js"></script>
7374 <script type="text/javascript" src="script/sanitize.js"></script>
146147 <script type="text/javascript" src="scripts/statusReport/directives/appendSearchParam.js"></script>
147148 <script type="text/javascript" src="scripts/statusReport/directives/autofocus.js"></script>
148149 <script type="text/javascript" src="scripts/statusReport/directives/customField.js"></script>
150 <script type="text/javascript" src="scripts/statusReport/directives/customFieldPrev.js"></script>
149151 <script type="text/javascript" src="scripts/statusReport/directives/checkCustomType.js"></script>
150152 <script type="text/javascript" src="scripts/statusReport/providers/target.js"></script>
151153 <script type="text/javascript" src="scripts/statusReport/providers/reference.js"></script>
152154 <script type="text/javascript" src="scripts/statusReport/providers/parser.js"></script>
155 <script type="text/javascript" src="scripts/statusReport/providers/ui-common.js"></script>
153156 <script type="text/javascript" src="scripts/vulns/providers/vuln.js"></script>
154157 <script type="text/javascript" src="scripts/vulns/providers/vulns.js"></script>
155158 <script type="text/javascript" src="scripts/vulns/providers/web.js"></script>
0 /*
1 angular-file-upload-lib v2.5.0
2 https://github.com/nervgh/angular-file-upload-lib
3 */
4
5 !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports["angular-file-upload-lib"]=t():e["angular-file-upload-lib"]=t()}(this,function(){return function(e){function t(o){if(n[o])return n[o].exports;var r=n[o]={exports:{},id:o,loaded:!1};return e[o].call(r.exports,r,r.exports,t),r.loaded=!0,r.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}var r=n(1),i=o(r),s=n(2),a=o(s),u=n(3),l=o(u),p=n(4),c=o(p),f=n(5),d=o(f),h=n(6),y=o(h),v=n(7),m=o(v),_=n(8),g=o(_),b=n(9),F=o(b),O=n(10),C=o(O),w=n(11),A=o(w),I=n(12),T=o(I),U=n(13),x=o(U);angular.module(i["default"].name,[]).value("fileUploaderOptions",a["default"]).factory("FileUploader",l["default"]).factory("FileLikeObject",c["default"]).factory("FileItem",d["default"]).factory("FileDirective",y["default"]).factory("FileSelect",m["default"]).factory("FileDrop",F["default"]).factory("FileOver",C["default"]).factory("Pipeline",g["default"]).directive("nvFileSelect",A["default"]).directive("nvFileDrop",T["default"]).directive("nvFileOver",x["default"]).run(["FileUploader","FileLikeObject","FileItem","FileDirective","FileSelect","FileDrop","FileOver","Pipeline",function(e,t,n,o,r,i,s,a){e.FileLikeObject=t,e.FileItem=n,e.FileDirective=o,e.FileSelect=r,e.FileDrop=i,e.FileOver=s,e.Pipeline=a}])},function(e,t){e.exports={name:"angularFileUploadLib"}},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t["default"]={url:"/",alias:"file",headers:{},queue:[],progress:0,autoUpload:!1,removeAfterUpload:!1,method:"POST",filters:[],formData:[],queueLimit:Number.MAX_VALUE,withCredentials:!1,disableMultipart:!1}},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t,n,o,i,a,u,g){var b=o.File,F=o.FormData,O=function(){function o(t){r(this,o);var n=p(e);c(this,n,t,{isUploading:!1,_nextIndex:0,_directives:{select:[],drop:[],over:[]}}),this.filters.unshift({name:"queueLimit",fn:this._queueLimitFilter}),this.filters.unshift({name:"folder",fn:this._folderFilter})}return o.prototype.addToQueue=function(e,t,n){var o=this,r=this.isArrayLikeObject(e)?Array.prototype.slice.call(e):[e],i=this._getFilters(n),l=this.queue.length,p=[],c=function d(){var e=r.shift();if(m(e))return f();var n=o.isFile(e)?e:new a(e),l=o._convertFiltersToPipes(i),c=new g(l),h=function(e){var t=e.pipe.originalFilter,n=s(e.args,2),r=n[0],i=n[1];o._onWhenAddingFileFailed(r,t,i),d()},y=function(e,t){var n=new u(o,e,t);p.push(n),o.queue.push(n),o._onAfterAddingFile(n),d()};c.onThrown=h,c.onSuccessful=y,c.exec(n,t)},f=function(){o.queue.length!==l&&(o._onAfterAddingAll(p),o.progress=o._getTotalProgress()),o._render(),o.autoUpload&&o.uploadAll()};c()},o.prototype.removeFromQueue=function(e){var t=this.getIndexOfItem(e),n=this.queue[t];n.isUploading&&n.cancel(),this.queue.splice(t,1),n._destroy(),this.progress=this._getTotalProgress()},o.prototype.clearQueue=function(){for(;this.queue.length;)this.queue[0].remove();this.progress=0},o.prototype.uploadItem=function(e){var t=this.getIndexOfItem(e),n=this.queue[t],o=this.isHTML5?"_xhrTransport":"_iframeTransport";n._prepareToUploading(),this.isUploading||(this._onBeforeUploadItem(n),n.isCancel||(n.isUploading=!0,this.isUploading=!0,this[o](n),this._render()))},o.prototype.cancelItem=function(e){var t=this,n=this.getIndexOfItem(e),o=this.queue[n],r=this.isHTML5?"_xhr":"_form";o&&(o.isCancel=!0,o.isUploading?o[r].abort():!function(){var e=[void 0,0,{}],n=function(){t._onCancelItem.apply(t,[o].concat(e)),t._onCompleteItem.apply(t,[o].concat(e))};i(n)}())},o.prototype.uploadAll=function(){var e=this.getNotUploadedItems().filter(function(e){return!e.isUploading});e.length&&(f(e,function(e){return e._prepareToUploading()}),e[0].upload())},o.prototype.cancelAll=function(){var e=this.getNotUploadedItems();f(e,function(e){return e.cancel()})},o.prototype.isFile=function(e){return this.constructor.isFile(e)},o.prototype.isFileLikeObject=function(e){return this.constructor.isFileLikeObject(e)},o.prototype.isArrayLikeObject=function(e){return this.constructor.isArrayLikeObject(e)},o.prototype.getIndexOfItem=function(e){return h(e)?e:this.queue.indexOf(e)},o.prototype.getNotUploadedItems=function(){return this.queue.filter(function(e){return!e.isUploaded})},o.prototype.getReadyItems=function(){return this.queue.filter(function(e){return e.isReady&&!e.isUploading}).sort(function(e,t){return e.index-t.index})},o.prototype.destroy=function(){var e=this;f(this._directives,function(t){f(e._directives[t],function(e){e.destroy()})})},o.prototype.onAfterAddingAll=function(e){},o.prototype.onAfterAddingFile=function(e){},o.prototype.onWhenAddingFileFailed=function(e,t,n){},o.prototype.onBeforeUploadItem=function(e){},o.prototype.onProgressItem=function(e,t){},o.prototype.onProgressAll=function(e){},o.prototype.onSuccessItem=function(e,t,n,o){},o.prototype.onErrorItem=function(e,t,n,o){},o.prototype.onCancelItem=function(e,t,n,o){},o.prototype.onCompleteItem=function(e,t,n,o){},o.prototype.onCompleteAll=function(){},o.prototype._getTotalProgress=function(e){if(this.removeAfterUpload)return e||0;var t=this.getNotUploadedItems().length,n=t?this.queue.length-t:this.queue.length,o=100/this.queue.length,r=(e||0)*o/100;return Math.round(n*o+r)},o.prototype._getFilters=function(e){if(!e)return this.filters;if(v(e))return e;var t=e.match(/[^\s,]+/g);return this.filters.filter(function(e){return-1!==t.indexOf(e.name)})},o.prototype._convertFiltersToPipes=function(e){var t=this;return e.map(function(e){var n=l(t,e.fn);return n.isAsync=3===e.fn.length,n.originalFilter=e,n})},o.prototype._render=function(){t.$$phase||t.$apply()},o.prototype._folderFilter=function(e){return!(!e.size&&!e.type)},o.prototype._queueLimitFilter=function(){return this.queue.length<this.queueLimit},o.prototype._isSuccessCode=function(e){return e>=200&&300>e||304===e},o.prototype._transformResponse=function(e,t){var o=this._headersGetter(t);return f(n.defaults.transformResponse,function(t){e=t(e,o)}),e},o.prototype._parseHeaders=function(e){var t,n,o,r={};return e?(f(e.split("\n"),function(e){o=e.indexOf(":"),t=e.slice(0,o).trim().toLowerCase(),n=e.slice(o+1).trim(),t&&(r[t]=r[t]?r[t]+", "+n:n)}),r):r},o.prototype._headersGetter=function(e){return function(t){return t?e[t.toLowerCase()]||null:e}},o.prototype._xhrTransport=function(e){var t,n=this,o=e._xhr=new XMLHttpRequest;if(e.disableMultipart?t=e._file:(t=new F,f(e.formData,function(e){f(e,function(e,n){t.append(n,e)})}),t.append(e.alias,e._file,e.file.name)),"number"!=typeof e._file.size)throw new TypeError("The file specified is no longer valid");o.upload.onprogress=function(t){var o=Math.round(t.lengthComputable?100*t.loaded/t.total:0);n._onProgressItem(e,o)},o.onload=function(){var t=n._parseHeaders(o.getAllResponseHeaders()),r=n._transformResponse(o.response,t),i=n._isSuccessCode(o.status)?"Success":"Error",s="_on"+i+"Item";n[s](e,r,o.status,t),n._onCompleteItem(e,r,o.status,t)},o.onerror=function(){var t=n._parseHeaders(o.getAllResponseHeaders()),r=n._transformResponse(o.response,t);n._onErrorItem(e,r,o.status,t),n._onCompleteItem(e,r,o.status,t)},o.onabort=function(){var t=n._parseHeaders(o.getAllResponseHeaders()),r=n._transformResponse(o.response,t);n._onCancelItem(e,r,o.status,t),n._onCompleteItem(e,r,o.status,t)},o.open(e.method,e.url,!0),o.withCredentials=e.withCredentials,f(e.headers,function(e,t){o.setRequestHeader(t,e)}),o.send(t)},o.prototype._iframeTransport=function(e){var t=this,n=_('<form style="display: none;" />'),o=_('<iframe name="iframeTransport'+Date.now()+'">'),r=e._input;e._form&&e._form.replaceWith(r),e._form=n,r.prop("name",e.alias),f(e.formData,function(e){f(e,function(e,t){var o=_('<input type="hidden" name="'+t+'" />');o.val(e),n.append(o)})}),n.prop({action:e.url,method:"POST",target:o.prop("name"),enctype:"multipart/form-data",encoding:"multipart/form-data"}),o.bind("load",function(){var n="",r=200;try{n=o[0].contentDocument.body.innerHTML}catch(i){r=500}var s={response:n,status:r,dummy:!0},a={},u=t._transformResponse(s.response,a);t._onSuccessItem(e,u,s.status,a),t._onCompleteItem(e,u,s.status,a)}),n.abort=function(){var i,s={status:0,dummy:!0},a={};o.unbind("load").prop("src","javascript:false;"),n.replaceWith(r),t._onCancelItem(e,i,s.status,a),t._onCompleteItem(e,i,s.status,a)},r.after(n),n.append(r).append(o),n[0].submit()},o.prototype._onWhenAddingFileFailed=function(e,t,n){this.onWhenAddingFileFailed(e,t,n)},o.prototype._onAfterAddingFile=function(e){this.onAfterAddingFile(e)},o.prototype._onAfterAddingAll=function(e){this.onAfterAddingAll(e)},o.prototype._onBeforeUploadItem=function(e){e._onBeforeUpload(),this.onBeforeUploadItem(e)},o.prototype._onProgressItem=function(e,t){var n=this._getTotalProgress(t);this.progress=n,e._onProgress(t),this.onProgressItem(e,t),this.onProgressAll(n),this._render()},o.prototype._onSuccessItem=function(e,t,n,o){e._onSuccess(t,n,o),this.onSuccessItem(e,t,n,o)},o.prototype._onErrorItem=function(e,t,n,o){e._onError(t,n,o),this.onErrorItem(e,t,n,o)},o.prototype._onCancelItem=function(e,t,n,o){e._onCancel(t,n,o),this.onCancelItem(e,t,n,o)},o.prototype._onCompleteItem=function(e,t,n,o){e._onComplete(t,n,o),this.onCompleteItem(e,t,n,o);var r=this.getReadyItems()[0];return this.isUploading=!1,y(r)?void r.upload():(this.onCompleteAll(),this.progress=this._getTotalProgress(),void this._render())},o.isFile=function(e){return b&&e instanceof b},o.isFileLikeObject=function(e){return e instanceof a},o.isArrayLikeObject=function(e){return d(e)&&"length"in e},o.inherit=function(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.super_=t},o}();return O.prototype.isHTML5=!(!b||!F),O.isHTML5=O.prototype.isHTML5,O}Object.defineProperty(t,"__esModule",{value:!0});var s=function(){function e(e,t){var n=[],o=!0,r=!1,i=void 0;try{for(var s,a=e[Symbol.iterator]();!(o=(s=a.next()).done)&&(n.push(s.value),!t||n.length!==t);o=!0);}catch(u){r=!0,i=u}finally{try{!o&&a["return"]&&a["return"]()}finally{if(r)throw i}}return n}return function(t,n){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();t["default"]=i;var a=n(1),u=(o(a),angular),l=u.bind,p=u.copy,c=u.extend,f=u.forEach,d=u.isObject,h=u.isNumber,y=u.isDefined,v=u.isArray,m=u.isUndefined,_=u.element;i.$inject=["fileUploaderOptions","$rootScope","$http","$window","$timeout","FileLikeObject","FileItem","Pipeline"]},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(){return function(){function e(t){r(this,e);var n=l(t),o=n?t.value:t,i=p(o)?"FakePath":"Object",s="_createFrom"+i;this[s](o)}return e.prototype._createFromFakePath=function(e){this.lastModifiedDate=null,this.size=null,this.type="like/"+e.slice(e.lastIndexOf(".")+1).toLowerCase(),this.name=e.slice(e.lastIndexOf("/")+e.lastIndexOf("\\")+2)},e.prototype._createFromObject=function(e){this.lastModifiedDate=u(e.lastModifiedDate),this.size=e.size,this.type=e.type,this.name=e.name},e}()}Object.defineProperty(t,"__esModule",{value:!0}),t["default"]=i;var s=n(1),a=(o(s),angular),u=a.copy,l=a.isElement,p=a.isString},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){return function(){function n(e,o,i){r(this,n);var s=c(o),a=s?p(o):null,f=s?null:o;l(this,{url:e.url,alias:e.alias,headers:u(e.headers),formData:u(e.formData),removeAfterUpload:e.removeAfterUpload,withCredentials:e.withCredentials,disableMultipart:e.disableMultipart,method:e.method},i,{uploader:e,file:new t(o),isReady:!1,isUploading:!1,isUploaded:!1,isSuccess:!1,isCancel:!1,isError:!1,progress:0,index:null,_file:f,_input:a}),a&&this._replaceNode(a)}return n.prototype.upload=function(){try{this.uploader.uploadItem(this)}catch(e){var t=e.name+":"+e.message;this.uploader._onCompleteItem(this,t,e.code,[]),this.uploader._onErrorItem(this,t,e.code,[])}},n.prototype.cancel=function(){this.uploader.cancelItem(this)},n.prototype.remove=function(){this.uploader.removeFromQueue(this)},n.prototype.onBeforeUpload=function(){},n.prototype.onProgress=function(e){},n.prototype.onSuccess=function(e,t,n){},n.prototype.onError=function(e,t,n){},n.prototype.onCancel=function(e,t,n){},n.prototype.onComplete=function(e,t,n){},n.prototype._onBeforeUpload=function(){this.isReady=!0,this.isUploading=!1,this.isUploaded=!1,this.isSuccess=!1,this.isCancel=!1,this.isError=!1,this.progress=0,this.onBeforeUpload()},n.prototype._onProgress=function(e){this.progress=e,this.onProgress(e)},n.prototype._onSuccess=function(e,t,n){this.isReady=!1,this.isUploading=!1,this.isUploaded=!0,this.isSuccess=!0,this.isCancel=!1,this.isError=!1,this.progress=100,this.index=null,this.onSuccess(e,t,n)},n.prototype._onError=function(e,t,n){this.isReady=!1,this.isUploading=!1,this.isUploaded=!0,this.isSuccess=!1,this.isCancel=!1,this.isError=!0,this.progress=0,this.index=null,this.onError(e,t,n)},n.prototype._onCancel=function(e,t,n){this.isReady=!1,this.isUploading=!1,this.isUploaded=!1,this.isSuccess=!1,this.isCancel=!0,this.isError=!1,this.progress=0,this.index=null,this.onCancel(e,t,n)},n.prototype._onComplete=function(e,t,n){this.onComplete(e,t,n),this.removeAfterUpload&&this.remove()},n.prototype._destroy=function(){this._input&&this._input.remove(),this._form&&this._form.remove(),delete this._form,delete this._input},n.prototype._prepareToUploading=function(){this.index=this.index||++this.uploader._nextIndex,this.isReady=!0},n.prototype._replaceNode=function(t){var n=e(t.clone())(t.scope());n.prop("value",null),t.css("display","none"),t.after(n)},n}()}Object.defineProperty(t,"__esModule",{value:!0}),t["default"]=i;var s=n(1),a=(o(s),angular),u=a.copy,l=a.extend,p=a.element,c=a.isElement;i.$inject=["$compile","FileLikeObject"]},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(){var e=function(){function e(t){r(this,e),u(this,t),this.uploader._directives[this.prop].push(this),this._saveLinks(),this.bind()}return e.prototype.bind=function(){for(var e in this.events){var t=this.events[e];this.element.bind(e,this[t])}},e.prototype.unbind=function(){for(var e in this.events)this.element.unbind(e,this.events[e])},e.prototype.destroy=function(){var e=this.uploader._directives[this.prop].indexOf(this);this.uploader._directives[this.prop].splice(e,1),this.unbind()},e.prototype._saveLinks=function(){for(var e in this.events){var t=this.events[e];this[t]=this[t].bind(this)}},e}();return e.prototype.events={},e}Object.defineProperty(t,"__esModule",{value:!0}),t["default"]=i;var s=n(1),a=(o(s),angular),u=a.extend},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function s(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function a(e,t){return function(t){function n(e){r(this,n);var o=p(e,{events:{$destroy:"destroy",change:"onChange"},prop:"select"}),s=i(this,t.call(this,o));return s.uploader.isHTML5||s.element.removeAttr("multiple"),s.element.prop("value",null),s}return s(n,t),n.prototype.getOptions=function(){},n.prototype.getFilters=function(){},n.prototype.isEmptyAfterSelection=function(){return!!this.element.attr("multiple")},n.prototype.onChange=function(){var t=this.uploader.isHTML5?this.element[0].files:this.element[0],n=this.getOptions(),o=this.getFilters();this.uploader.isHTML5||this.destroy(),this.uploader.addToQueue(t,n,o),this.isEmptyAfterSelection()&&(this.element.prop("value",null),this.element.replaceWith(e(this.element.clone())(this.scope)))},n}(t)}Object.defineProperty(t,"__esModule",{value:!0}),t["default"]=a;var u=n(1),l=(o(u),angular),p=l.extend;a.$inject=["$compile","FileDirective"]},function(e,t){"use strict";function n(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t<e.length;t++)n[t]=e[t];return n}return Array.from(e)}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e){return function(){function t(){var e=arguments.length<=0||void 0===arguments[0]?[]:arguments[0];o(this,t),this.pipes=e}return t.prototype.next=function(t){var o=this.pipes.shift();if(a(o))return void this.onSuccessful.apply(this,n(t));var r=new Error("The filter has not passed");if(r.pipe=o,r.args=t,o.isAsync){var i=e.defer(),u=s(this,this.next,t),l=s(this,this.onThrown,r);i.promise.then(u,l),o.apply(void 0,n(t).concat([i]))}else{var p=Boolean(o.apply(void 0,n(t)));p?this.next(t):this.onThrown(r)}},t.prototype.exec=function(){for(var e=arguments.length,t=Array(e),n=0;e>n;n++)t[n]=arguments[n];this.next(t)},t.prototype.onThrown=function(e){},t.prototype.onSuccessful=function(){},t}()}Object.defineProperty(t,"__esModule",{value:!0}),t["default"]=r;var i=angular,s=i.bind,a=i.isUndefined;r.$inject=["$q"]},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function s(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function a(e){return function(e){function t(n){r(this,t);var o=p(n,{events:{$destroy:"destroy",drop:"onDrop",dragover:"onDragOver",dragleave:"onDragLeave"},prop:"drop"});return i(this,e.call(this,o))}return s(t,e),t.prototype.getOptions=function(){},t.prototype.getFilters=function(){},t.prototype.onDrop=function(e){var t=this._getTransfer(e);if(t){var n=this.getOptions(),o=this.getFilters();this._preventAndStop(e),c(this.uploader._directives.over,this._removeOverClass,this),this.uploader.addToQueue(t.files,n,o)}},t.prototype.onDragOver=function(e){var t=this._getTransfer(e);this._haveFiles(t.types)&&(t.dropEffect="copy",this._preventAndStop(e),c(this.uploader._directives.over,this._addOverClass,this))},t.prototype.onDragLeave=function(e){e.currentTarget!==this.element[0]&&(this._preventAndStop(e),c(this.uploader._directives.over,this._removeOverClass,this))},t.prototype._getTransfer=function(e){return e.dataTransfer?e.dataTransfer:e.originalEvent.dataTransfer},t.prototype._preventAndStop=function(e){e.preventDefault(),e.stopPropagation()},t.prototype._haveFiles=function(e){return e?e.indexOf?-1!==e.indexOf("Files"):e.contains?e.contains("Files"):!1:!1},t.prototype._addOverClass=function(e){e.addOverClass()},t.prototype._removeOverClass=function(e){e.removeOverClass()},t}(e)}Object.defineProperty(t,"__esModule",{value:!0}),t["default"]=a;var u=n(1),l=(o(u),angular),p=l.extend,c=l.forEach;a.$inject=["FileDirective"]},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function s(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function a(e){return function(e){function t(n){r(this,t);var o=p(n,{events:{$destroy:"destroy"},prop:"over",overClass:"nv-file-over"});return i(this,e.call(this,o))}return s(t,e),t.prototype.addOverClass=function(){this.element.addClass(this.getOverClass())},t.prototype.removeOverClass=function(){this.element.removeClass(this.getOverClass())},t.prototype.getOverClass=function(){return this.overClass},t}(e)}Object.defineProperty(t,"__esModule",{value:!0}),t["default"]=a;var u=n(1),l=(o(u),angular),p=l.extend;a.$inject=["FileDirective"]},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function r(e,t,n){return{link:function(o,r,i){var s=o.$eval(i.uploader);if(!(s instanceof t))throw new TypeError('"Uploader" must be an instance of FileUploader');var a=new n({uploader:s,element:r,scope:o});a.getOptions=e(i.options).bind(a,o),a.getFilters=function(){return i.filters}}}}Object.defineProperty(t,"__esModule",{value:!0}),t["default"]=r;var i=n(1);o(i);r.$inject=["$parse","FileUploader","FileSelect"]},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function r(e,t,n){return{link:function(o,r,i){var s=o.$eval(i.uploader);if(!(s instanceof t))throw new TypeError('"Uploader" must be an instance of FileUploader');if(s.isHTML5){var a=new n({uploader:s,element:r});a.getOptions=e(i.options).bind(a,o),a.getFilters=function(){return i.filters}}}}}Object.defineProperty(t,"__esModule",{value:!0}),t["default"]=r;var i=n(1);o(i);r.$inject=["$parse","FileUploader","FileDrop"]},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function r(e,t){return{link:function(n,o,r){var i=n.$eval(r.uploader);if(!(i instanceof e))throw new TypeError('"Uploader" must be an instance of FileUploader');var s=new t({uploader:i,element:o});s.getOverClass=function(){return r.overClass||s.overClass}}}}Object.defineProperty(t,"__esModule",{value:!0}),t["default"]=r;var i=n(1);o(i);r.$inject=["FileUploader","FileOver"]}])});
6 //# sourceMappingURL=angular-file-upload-lib.min.js.map
1111 'filter', 'angular-clipboard', 'ngCookies', 'cfp.hotkeys', 'chart.js',
1212 'ui.grid', 'ui.grid.selection', 'ui.grid.grouping', 'ngSanitize',
1313 'ui.grid.pagination', 'ui.grid.pinning', 'angularMoment', 'ui-notification',
14 'ui.grid.resizeColumns', 'angularSimplePagination'])
14 'ui.grid.resizeColumns', 'angularSimplePagination', 'angularFileUploadLib'])
1515 .constant("BASEURL", (function() {
1616 var url = window.location.origin + "/";
1717 return url;
77 "$location", "$uibModal", "$cookies", "$q", "$window", "BASEURL",
88 "SEVERITIES", "EASEOFRESOLUTION", "STATUSES", "hostsManager", "commonsFact", 'parserFact',
99 "vulnsManager", "workspacesFact", "csvService", "uiGridConstants", "vulnModelsManager",
10 "referenceFact", "ServerAPI", '$http',
10 "referenceFact", "ServerAPI", '$http', 'uiCommonFact', 'FileUploader',
1111 function($scope, $filter, $routeParams,
1212 $location, $uibModal, $cookies, $q, $window, BASEURL,
1313 SEVERITIES, EASEOFRESOLUTION, STATUSES, hostsManager, commonsFact,parserFact,
14 vulnsManager, workspacesFact, csvService, uiGridConstants, vulnModelsManager, referenceFact, ServerAPI, $http) {
14 vulnsManager, workspacesFact, csvService, uiGridConstants, vulnModelsManager, referenceFact,
15 ServerAPI, $http, uiCommonFact, FileUploader) {
1516 $scope.baseurl;
1617 $scope.columns;
1718 $scope.columnsWidths;
3233
3334 $scope.gridHeight;
3435 $scope.customFields;
36
37 $scope.isShowingPreview;
38
39 $scope.cweList;
40 $scope.temTemplate;
41 $scope.new_ref;
42 $scope.new_policyviolation;
43
44 $scope.selectedAtachment;
45
46
3547 var allVulns;
3648
3749 var searchFilter = {};
4254 sortColumn: null,
4355 sortDirection: null
4456 };
57
58 var uploader = $scope.uploader = new FileUploader({});
59
60 // FILTERS
61
62 // a sync filter
63 uploader.filters.push({
64 name: 'syncFilter',
65 fn: function(item /*{File|FileLikeObject}*/, options) {
66 return this.queue.length < 10;
67 }
68 });
69
70 // an async filter
71 uploader.filters.push({
72 name: 'asyncFilter',
73 fn: function(item /*{File|FileLikeObject}*/, options, deferred) {
74 setTimeout(deferred.resolve, 1e3);
75 }
76 });
77
4578
4679 var init = function() {
4780 $scope.baseurl = BASEURL;
287320 });
288321
289322 $cookies.remove("selectedVulns");
323 $scope.isShowingPreview = false;
324
325 $scope.cweList = [];
326
327 vulnModelsManager.get().then(function (data) {
328 $scope.cweList = data;
329 });
330
331 $scope.temTemplate = undefined;
332 $scope.new_ref = "";
333 $scope.new_policyviolation = "";
334
335 $scope.selectedAtachment = {
336 url: '',
337 name: '',
338 imgPrevFail: false
339 };
290340 };
291341
292342
827877
828878 // action triggered from EDIT button
829879 $scope.edit = function() {
880 $scope.hideVulnPreview();
830881 _edit($scope.getCurrentSelection());
831882 };
832883
11081159 };
11091160
11101161 $scope.new = function() {
1162 $scope.hideVulnPreview();
11111163 var modal = $uibModal.open({
11121164 templateUrl: 'scripts/statusReport/partials/modalNew.html',
11131165 backdrop : 'static',
12661318 return elements.join("\n" + (useDoubleLinebreak ? "\n" : ""));
12671319 };
12681320
1321 $scope.showVulnPreview = function () {
1322 $scope.isShowingPreview = true;
1323 angular.element('#vuln-preview').addClass('show-preview');
1324 // angular.element('.faraday-page-header').addClass('show-preview');
1325 // angular.element('#btn_bar').addClass('show-preview');
1326 };
1327
1328 $scope.hideVulnPreview = function () {
1329 $scope.lastClickedVuln = undefined;
1330 $scope.isShowingPreview = false;
1331 angular.element('#vuln-preview').removeClass('show-preview');
1332 // angular.element('.faraday-page-header').removeClass('show-preview');
1333 // angular.element('#btn_bar').removeClass('show-preview');
1334 };
1335
1336
1337 var updateSelectedVulnAtachments = function () {
1338 var url = '/_api/v2/ws/' + $routeParams.wsId + '/vulns/' + $scope.lastClickedVuln._id + '/attachments/';
1339 $http.get(url).then(
1340 function (response) {
1341 $scope.lastClickedVuln._attachments = response.data
1342 }
1343 );
1344 };
1345
1346 $scope.toggleVulnPreview = function (e, vuln) {
1347 e.stopPropagation();
1348 if ($scope.lastClickedVuln !== undefined && $scope.lastClickedVuln._id === vuln._id){
1349 $scope.hideVulnPreview();
1350 $scope.lastClickedVuln = undefined;
1351 }else{
1352 $scope.showVulnPreview();
1353 $scope.realVuln = vuln;
1354 $scope.lastClickedVuln = angular.copy(vuln);
1355 updateSelectedVulnAtachments();
1356 uiCommonFact.updateBtnSeverityColor($scope.lastClickedVuln.severity, '#btn-chg-severity-prev', '#caret-chg-severity-prev');
1357 uiCommonFact.updateBtnStatusColor($scope.lastClickedVuln.status, '#btn-chg-status-prev', '#caret-chg-status-prev');
1358 }
1359 $scope.cwe_selected = undefined;
1360 $scope.selectedAtachment = {
1361 url: '',
1362 name: '',
1363 imgPrevFail: false
1364 };
1365
1366 $scope.uploader.clearQueue();
1367 };
1368
1369
1370 $scope.changeVulnPrevByEventKey = function (event) {
1371 if ($scope.lastClickedVuln !== undefined) {
1372 var curRowindex = -1;
1373 var targetIndex = -1;
1374 for (var i = 0; i < $scope.gridApi.grid.rows.length; i++) {
1375 if ($scope.gridApi.grid.rows[i].entity._id === $scope.lastClickedVuln._id) {
1376 curRowindex = i;
1377 break;
1378 }
1379 }
1380
1381 if (event.keyCode === uiGridConstants.keymap.DOWN)
1382 targetIndex = curRowindex + 1;
1383 else if (event.keyCode === uiGridConstants.keymap.UP)
1384 targetIndex = curRowindex - 1;
1385
1386 if (targetIndex !== -1 && targetIndex < $scope.gridApi.grid.rows.length) {
1387 $scope.lastClickedVuln = $scope.gridApi.grid.rows[targetIndex].entity;
1388 }
1389 }
1390
1391 };
1392
1393 $scope.activeEditPreview = function (field) {
1394 $scope.fieldToEdit = field;
1395 };
1396
1397 $scope.processToEditPreview = function (isMandatory) {
1398 if (($scope.lastClickedVuln.hasOwnProperty($scope.fieldToEdit) &&
1399 $scope.lastClickedVuln[$scope.fieldToEdit] !== undefined &&
1400 $scope.lastClickedVuln[$scope.fieldToEdit] !== '') || isMandatory === false){
1401
1402 $scope.isUpdatingVuln = true;
1403 if ($scope.realVuln[$scope.fieldToEdit] !== $scope.lastClickedVuln[$scope.fieldToEdit] ||
1404 ($scope.realVuln['custom_fields'].hasOwnProperty($scope.fieldToEdit))){
1405 vulnsManager.updateVuln($scope.realVuln, $scope.lastClickedVuln).then(function () {
1406 $scope.isUpdatingVuln = false;
1407 $scope.fieldToEdit = undefined;
1408 }, function (data) {
1409 $scope.hideVulnPreview();
1410 commonsFact.showMessage("Error updating vuln " + $scope.realVuln.name + " (" + $scope.realVuln._id + "): " + (data.message || JSON.stringify(data.messages)));
1411 $scope.fieldToEdit = undefined;
1412 $scope.isUpdatingVuln = false;
1413 });
1414 }else{
1415 $scope.fieldToEdit = undefined;
1416 $scope.isUpdatingVuln = false;
1417 }
1418
1419 }
1420 };
1421
1422 $scope.changeSeverity = function (severity) {
1423 $scope.fieldToEdit = 'severity';
1424 $scope.lastClickedVuln.severity = severity;
1425 uiCommonFact.updateBtnSeverityColor(severity, '#btn-chg-severity-prev', '#caret-chg-severity-prev');
1426 $scope.processToEditPreview();
1427 };
1428
1429 $scope.changeEaseOfResolution = function (easeofresolution) {
1430 $scope.fieldToEdit = 'easeofresolution';
1431 $scope.lastClickedVuln.easeofresolution = easeofresolution;
1432 $scope.processToEditPreview();
1433 };
1434
1435 $scope.changeStatus = function (status) {
1436 $scope.fieldToEdit = 'status';
1437 $scope.lastClickedVuln.status = status;
1438 uiCommonFact.updateBtnStatusColor(status, '#btn-chg-status-prev', '#caret-chg-status-prev');
1439 $scope.processToEditPreview();
1440 };
1441
1442 $scope.changeConfirmed = function (confirmed) {
1443 $scope.fieldToEdit = 'confirmed';
1444 $scope.lastClickedVuln.confirmed = confirmed;
1445 $scope.processToEditPreview();
1446 };
1447
1448 $scope.toggleImpact = function (key) {
1449 $scope.fieldToEdit = 'impact';
1450 $scope.lastClickedVuln.impact[key] = !$scope.lastClickedVuln.impact[key];
1451 $scope.processToEditPreview();
1452 };
1453
1454
1455 $scope.populate = function () {
1456 $scope.temTemplate = angular.copy($scope.lastClickedVuln);
1457 uiCommonFact.populate($scope.cwe_selected, $scope.lastClickedVuln);
1458 };
1459
1460 $scope.applyTemplate = function () {
1461 $scope.fieldToEdit = 'template';
1462 $scope.isUpdatingVuln = true;
1463 vulnsManager.updateVuln($scope.realVuln, $scope.lastClickedVuln).then(function () {
1464 $scope.isUpdatingVuln = false;
1465 $scope.fieldToEdit = undefined;
1466 $scope.temTemplate = undefined;
1467 $scope.cwe_selected = undefined
1468 }, function (data) {
1469 commonsFact.showMessage("Error updating vuln " + $scope.realVuln.name + " (" + $scope.realVuln._id + "): " + (data.message || JSON.stringify(data.messages)));
1470 $scope.fieldToEdit = undefined;
1471 $scope.isUpdatingVuln = false;
1472 $scope.temTemplate = undefined;
1473 $scope.cwe_selected = undefined;
1474 $scope.hideVulnPreview();
1475 });
1476 };
1477
1478 $scope.discardTemplate = function () {
1479 uiCommonFact.populate($scope.temTemplate, $scope.lastClickedVuln);
1480 $scope.temTemplate = undefined;
1481 $scope.cwe_selected = undefined;
1482 };
1483
1484
1485 $scope.newReference = function () {
1486 $scope.fieldToEdit = 'refs';
1487 uiCommonFact.newReference($scope.new_ref, $scope.lastClickedVuln);
1488 $scope.processToEditPreview();
1489 $scope.new_ref = "";
1490 };
1491
1492
1493 $scope.removeReference = function (index) {
1494 $scope.fieldToEdit = 'refs';
1495 $scope.lastClickedVuln.refs.splice(index, 1);
1496 $scope.isUpdatingVuln = true;
1497
1498 vulnsManager.updateVuln($scope.realVuln, $scope.lastClickedVuln).then(function () {
1499 $scope.isUpdatingVuln = false;
1500 $scope.fieldToEdit = undefined;
1501 }, function (data) {
1502 $scope.hideVulnPreview();
1503 commonsFact.showMessage("Error updating vuln " + $scope.realVuln.name + " (" + $scope.realVuln._id + "): " + (data.message || JSON.stringify(data.messages)));
1504 $scope.fieldToEdit = undefined;
1505 $scope.isUpdatingVuln = false;
1506
1507 });
1508 };
1509
1510 $scope.openReference = function (text) {
1511 window.open(referenceFact.processReference(text), '_blank');
1512 };
1513
1514
1515 $scope.newPolicyviolation = function () {
1516 $scope.fieldToEdit = 'policyviolations';
1517 uiCommonFact.newPolicyViolation($scope.new_policyviolation, $scope.lastClickedVuln);
1518 $scope.processToEditPreview();
1519 $scope.new_policyviolation = "";
1520 };
1521
1522
1523 $scope.removePolicyviolation = function (index) {
1524 $scope.fieldToEdit = 'policyviolations';
1525 $scope.lastClickedVuln.policyviolations.splice(index, 1);
1526 $scope.isUpdatingVuln = true;
1527
1528 vulnsManager.updateVuln($scope.realVuln, $scope.lastClickedVuln).then(function () {
1529 $scope.isUpdatingVuln = false;
1530 $scope.fieldToEdit = undefined;
1531 }, function (data) {
1532 $scope.hideVulnPreview();
1533 commonsFact.showMessage("Error updating vuln " + $scope.realVuln.name + " (" + $scope.realVuln._id + "): " + (data.message || JSON.stringify(data.messages)));
1534 $scope.fieldToEdit = undefined;
1535 $scope.isUpdatingVuln = false;
1536
1537 });
1538 };
1539
1540
1541 uploader.onAfterAddingFile = function(fileItem) {
1542 if ($scope.lastClickedVuln._attachments.hasOwnProperty(fileItem.file.name)){
1543 fileItem.isError = true;
1544 fileItem.isReady = true;
1545 return;
1546 }
1547
1548 $http.get('/_api/session').then(
1549 function(d) {
1550 $scope.csrf_token = d.data.csrf_token;
1551 fileItem.formData.push({'csrf_token': $scope.csrf_token});
1552 fileItem.url = '_api/v2/ws/' + $routeParams.wsId + '/vulns/' + $scope.lastClickedVuln._id + '/attachment/';
1553 $scope.uploader.uploadAll();
1554 }
1555 );
1556
1557 };
1558
1559
1560
1561 uploader.onSuccessItem = function(fileItem, response, status, headers) {
1562 updateSelectedVulnAtachments();
1563 };
1564
1565 $scope.removeEvidence = function (name) {
1566 var url = '/_api/v2/ws/'+ $routeParams.wsId +'/vulns/'+ $scope.lastClickedVuln._id +'/attachment/' + name + '/'
1567 $http.delete(url).then(
1568 function(response) {
1569 if (response && response.status === 200){
1570 uiCommonFact.removeEvidence(name, $scope.lastClickedVuln);
1571 }
1572 }
1573 );
1574 };
1575
1576 $scope.selectItemToPrev = function (name) {
1577 $scope.selectedAtachment.name = name;
1578 $scope.selectedAtachment.url = BASEURL + '_api/v2/ws/' + $routeParams.wsId + /vulns/ + $scope.lastClickedVuln._id + /attachment/ + name
1579 $scope.selectedAtachment.imgPrevFail = false;
1580 var format = $scope.selectedAtachment.name.split('.').pop();
1581 var imagesFormat = ['png','jpg', 'jpeg', 'gif'];
1582 if (imagesFormat.indexOf(format) === -1){
1583 $scope.selectedAtachment.imgPrevFail = true;
1584 }
1585 };
1586
1587
1588 $scope.copyToClipboard = function (name) {
1589 var url = BASEURL + '_api/v2/ws/' + $routeParams.wsId + /vulns/ + $scope.lastClickedVuln._id + /attachment/ + name;
1590 var copyElement = document.createElement("textarea");
1591 copyElement.style.position = 'fixed';
1592 copyElement.style.opacity = '0';
1593 copyElement.textContent = decodeURI(url);
1594 var body = document.getElementsByTagName('body')[0];
1595 body.appendChild(copyElement);
1596 copyElement.select();
1597 document.execCommand('copy');
1598 body.removeChild(copyElement);
1599 }
1600
1601
1602
1603 $scope.openEvidence = function (name) {
1604 uiCommonFact.openEvidence(name, $scope.lastClickedVuln, $routeParams.wsId);
1605 };
1606
1607 $scope.processLinesToHtml = function (rawText) {
1608 if (rawText !== undefined)
1609 return rawText.replace(/(?:\r\n|\r|\n)/g, '<br>');
1610 return '';
1611 };
1612
12691613 init();
12701614 }]);
0 // Faraday Penetration Test IDE
1 // Copyright (C) 2018 Infobyte LLC (http://www.infobytesec.com/)
2 // See the file 'doc/LICENSE' for the license information
3
4 angular.module('faradayApp')
5 .directive('customFieldPrev', ['vulnsManager', function (vulnsManager) {
6 return {
7 restrict: 'E',
8 scope: false,
9 replace: true,
10 template: '<div><div class="tab-pane-header"><i class="fa fa-spinner fa-spin" ng-show="isUpdatingVuln === true && fieldToEdit === cf.field_display_name"></i> {{cf.field_display_name}}</div> \n\
11 <div class="form-group" ng-if="cf.field_type !== \'list\'"> \n\
12 <label class="sr-only" for="{{cf.field_name}}">{{cf.field_display_name}}</label> \n\
13 <input type="text" class="form-control input-sm" id="{{cf.field_name}}" name="{{cf.field_name}}" \n\
14 placeholder="{{cf.field_display_name}}" \n\
15 ng-focus="activeEditPreview(cf.field_display_name)" \
16 ng-blur="processToEditPreview(false)"\
17 ng-model="lastClickedVuln.custom_fields[cf.field_display_name]" check-custom-type="{{cf.field_type}}" \n\
18 uib-tooltip="{{(cf.field_type === \'int\') ? \'Type only numbers\' : \'Input type text\'}}"/> \n\
19 </div> \n\
20 <div class="form-group " ng-if="cf.field_type === \'list\'">\n\
21 <div class="input-group"> \n\
22 <label class="sr-only" for="{{cf.field_name}}">{{cf.field_display_name}}</label> \n\
23 <input type="text" class="form-control input-sm" id="{{cf.field_name}}" name="{{cf.field_name}}" \n\
24 placeholder="{{cf.field_display_name}}" \n\
25 ng-focus="activeEditPreview(cf.field_display_name)" \
26 ng-model="valueField" \n\
27 uib-tooltip="Input type list"/> \n\
28 <span class="input-group-addon cursor"><i class="fa fa-plus-circle" ng-click="newValueField(valueField)"></i></span> \n\
29 </div> \n\
30 </div> \n\
31 <div class="col-md-12 reference last-item-field" ng-repeat="item in lastClickedVuln.custom_fields[cf.field_display_name] track by $index" ng-class="{\'last-item-field\':$last}" ng-if="cf.field_type === \'list\'"> \n\
32 <div class="input-group margin-bottom-sm"> \n\
33 <label class="sr-only" for="vuln-refs-create">{{cf.field_display_name}}</label> \n\
34 <input type="text" class="form-control" id="vuln-refs-create" placeholder="{{cf.field_display_name}}" \n\
35 ng-model="item.value" \n\
36 role="button" readonly/> \n\
37 <span class="input-group-addon cursor" ng-click="removeValueField($index)"> \n\
38 <i class="fa fa-minus-circle"></i></span> \n\
39 </div> \n\
40 </div> \n\
41 </div></div>',
42 link: function (scope, element, attrs) {
43 scope.newValueField = function (valueField) {
44 if (valueField !== "" && valueField !== undefined) {
45 if(scope.lastClickedVuln.custom_fields[scope.cf.field_display_name] === null )
46 scope.lastClickedVuln.custom_fields[scope.cf.field_display_name] = [];
47
48 // we need to check if the ref already exists
49 if (scope.lastClickedVuln.custom_fields[scope.cf.field_display_name].filter(function(field) {return field.value === valueField}).length === 0) {
50 scope.lastClickedVuln.custom_fields[scope.cf.field_display_name].push({value: valueField});
51 scope.valueField = "";
52 }
53 angular.element('#'+scope.cf.field_name).val("");
54
55 scope.fieldToEdit = scope.cf.field_display_name;
56 scope.processToEditPreview(false);
57
58 }
59 };
60
61 scope.removeValueField = function (index) {
62 scope.fieldToEdit = scope.cf.field_display_name;
63 scope.lastClickedVuln.custom_fields[scope.cf.field_display_name].splice(index, 1);
64 scope.isUpdatingVuln = true;
65
66 vulnsManager.updateVuln(scope.realVuln, scope.lastClickedVuln).then(function () {
67 scope.isUpdatingVuln = false;
68 scope.fieldToEdit = undefined;
69 }, function (data) {
70 scope.hideVulnPreview();
71 commonsFact.showMessage("Error updating vuln " + scope.realVuln.name + " (" + scope.realVuln._id + "): " + (data.message || JSON.stringify(data.messages)));
72 scope.fieldToEdit = undefined;
73 scope.isUpdatingVuln = false;
74
75 });
76 };
77 }
78 }
79 }]);
66 <div class="right-main">
77 <div ng-controller="headerCtrl" ng-include="'scripts/commons/partials/header.html'"></div>
88 <div id="reports-main" class="fila clearfix">
9 <div class="button-control col-md-12 col-sm-12 col-xs-12">
9 <div class="button-control col-md-12 col-sm-12 col-xs-12" id="btn_bar">
1010 <div class="control-wrapper control-new">
1111 <button type="button" class="btn btn-success btn-new" title="{{workspaceData.readonly == true ? 'Read-only. Workspace disabled': 'New Vulns'}}" ng-click="new()" ng-disabled="workspaceData.readonly == true">
1212 New
163163 <!-- .reports -->
164164 </div>
165165 <!-- #reports-main -->
166
167 <div id="vuln-preview">
168 <div class="preview-header">
169 <button type="button" class="close" ng-click="hideVulnPreview()" data-dismiss="alert"><span area-hidden="true">&times;</span><span class="sr-only">Close</span></button>
170 </div>
171 <div class="mt-3 height-100 ">
172 <div class="margin-left-0 edit-vulns-dropdowns row" ng-init="updateBtnSeverityColor(lastClickedVuln.severity);updateBtnStatusColor(lastClickedVuln.status)">
173
174 <div class="margin-left-0 btn-group col-md-2 col-sm-4 col-xs-4">
175 <button type="button" class="dropdown-toggle btn-change-property primary-btn"
176 data-toggle="dropdown"
177 id="btn-chg-severity-prev"
178 title="{{lastClickedVuln.severity}}">
179 <i class="fa fa-spinner fa-spin" ng-show="isUpdatingVuln === true && fieldToEdit === 'severity'"></i>{{lastClickedVuln.severity | uppercase}}
180 </button>
181 <button type="button" class="dropdown-toggle secondary-btn btn-change-property"
182 data-toggle="dropdown"
183 id="caret-chg-severity-prev"
184 title="Change severity-prev">
185 <span> <i class="fa fa-angle-down fa-lg" aria-hidden="true"></i> </span>
186 </button>
187 <ul class="dropdown-menu dropdown-menu-right" role="menu">
188 <li>
189 <a class="ws text-unclassified"
190 ng-click="changeSeverity('unclassified')">UNCLASSIFIED</a>
191 <a class="ws text-info"
192 ng-click="changeSeverity('info')">INFO</a>
193 <a class="ws text-low"
194 ng-click="changeSeverity('low')">LOW</a>
195 <a class="ws text-med"
196 ng-click="changeSeverity('med')">MEDIUM</a>
197 <a class="ws text-high"
198 ng-click="changeSeverity('high')">HIGH</a>
199 <a class="ws text-critical"
200 ng-click="changeSeverity('critical')">CRITICAL</a>
201 </li>
202 </ul>
203 </div>
204
205
206 <div class="btn-group col-md-2 col-sm-4 col-xs-4">
207 <button type="button" class="dropdown-toggle btn-change-property primary-btn btn-primary-white"
208 data-toggle="dropdown"
209 id="btn-chg-ease_resolution"
210 title="{{lastClickedVuln.easeofresolution}}">
211 <i class="fa fa-spinner fa-spin" ng-show="isUpdatingVuln === true && fieldToEdit === 'easeofresolution'"></i>{{lastClickedVuln.easeofresolution || "Fix Effort"}}
212 </button>
213 <button type="button" class="dropdown-toggle secondary-btn btn-change-property btn-secondary-white"
214 data-toggle="dropdown"
215 id="caret-ease_resolution"
216 title="Change Ease of Resolution">
217 <span> <i class="fa fa-angle-down fa-lg" aria-hidden="true"></i> </span>
218 </button>
219 <ul class="dropdown-menu dropdown-menu-right" role="menu">
220 <li>
221 <a class="ws"
222 ng-click="changeEaseOfResolution(null)">Undetermined</a>
223 <a class="ws"
224 ng-click="changeEaseOfResolution('trivial')">Trivial</a>
225 <a class="ws"
226 ng-click="changeEaseOfResolution('simple')">Simple</a>
227 <a class="ws"
228 ng-click="changeEaseOfResolution('moderate')">Moderate</a>
229 <a class="ws"
230 ng-click="changeEaseOfResolution('difficult')">Difficult</a>
231 <a class="ws"
232 ng-click="changeEaseOfResolution('infeasible')">Infeasible</a>
233 </li>
234 </ul>
235 </div>
236
237
238 <div class="btn-group col-md-2 col-sm-4 col-xs-4">
239 <button type="button" class="dropdown-toggle btn-change-property primary-btn text-capitalize"
240 data-toggle="dropdown"
241 id="btn-chg-status-prev"
242 title="{{lastClickedVuln.status}}">
243 <i class="fa fa-spinner fa-spin" ng-show="isUpdatingVuln === true && fieldToEdit === 'status'"></i>{{lastClickedVuln.status || "Status"}}
244 </button>
245 <button type="button" class="dropdown-toggle secondary-btn btn-change-property"
246 data-toggle="dropdown"
247 id="caret-chg-status-prev"
248 title="Change Status">
249 <span> <i class="fa fa-angle-down fa-lg" aria-hidden="true"></i> </span>
250 </button>
251 <ul class="dropdown-menu dropdown-menu-right" role="menu">
252 <li>
253 <a class="ws"
254 ng-click="changeStatus('opened')">Opened</a>
255 <a class="ws"
256 ng-click="changeStatus('closed')">Closed</a>
257 <a class="ws"
258 ng-click="changeStatus('re-opened')">Re-opened</a>
259 <a class="ws"
260 ng-click="changeStatus('risk-accepted')">Risk-accepted</a>
261 </li>
262 </ul>
263 </div>
264
265 <div class="col-md-2 col-sm-4 col-xs-4">
266 <label class="chbox-container">
267 <div class="tab-pane-header"><h4>Confirmed</h4></div>
268 <input type="checkbox" ng-checked="lastClickedVuln.confirmed === true" ng-model="lastClickedVuln.confirmed" ng-change="changeConfirmed(lastClickedVuln.confirmed)">
269 <span class="checkmark"></span>
270 </label>
271 </div>
272
273 </div>
274
275 <div class="margin-left-0 row">
276 <div ng-if="fieldToEdit !== 'name'">
277 <div class="margin-left-0 col-md-12">
278 <div class="tab-pane-header" ng-dblclick="activeEditPreview('name')" title="Double click to edit">
279 {{lastClickedVuln.name}} <span>({{lastClickedVuln.target}})</span>
280 </div>
281 </div>
282 </div>
283 <div class="form-group col-md-12" ng-if="fieldToEdit === 'name'" style="margin-bottom: 24px">
284 <label for="inp-edit-name"><i class="fa fa-spinner fa-spin" ng-show="isUpdatingVuln === true"></i> Vulnerability name</label>
285 <input type="text" class="form-control" id="inp-edit-name"
286 ng-model="lastClickedVuln.name" name="name" placeholder="Vulnerability name"
287 ng-blur="processToEditPreview()"
288 autofocus required>
289 </div>
290 </div>
291
292 <!-- Nav tabs -->
293 <ul class="nav nav-tabs" id="nav-tabs-container">
294 <li class="nav-item active" ng-class="{'has-error': formEdit.desc.$invalid}">
295 <a class="nav-link active" data-toggle="tab" data-target="#general_prev"
296 href="javascript:;">General</a>
297 </li>
298 <li class="nav-item">
299 <a class="nav-link" data-toggle="tab" data-target="#technical_details_prev" href="javascript:;">Technical
300 Details</a>
301 </li>
302 <li class="nav-item">
303 <a class="nav-link" data-toggle="tab" data-target="#tab-evidence_prev" href="javascript:;">Evidence</a>
304 </li>
305 <li class="nav-item">
306 <a class="nav-link" data-toggle="tab" data-target="#hosts_prev" href="javascript:;">Host</a>
307 </li>
308 <li class="nav-item">
309 <a class="nav-link" data-toggle="tab" data-target="#tab-custom-fields_prev" href="javascript:;">Custom Fields</a>
310 </li>
311 </ul>
312
313 <!-- Tab panes -->
314 <div class="tab-content height-100 ">
315 <div id="general_prev" class="container tab-pane-container tab-pane active"><br>
316
317 <div class="row margin-left-0">
318 <div class="height-100 padding-left-0 col-md-7">
319 <div class="height-100 padding-left-0 col-md-12">
320 <div ng-if="fieldToEdit !== 'desc'" class="height-100">
321 <div class="height-100 padding-left-0 col-md-12 margin-bottom-24">
322 <div ng-if="lastClickedVuln.desc === '' || lastClickedVuln.desc === undefined" style="margin-bottom: 15px;color: #aaa;">
323 <p>
324 No Description was found.
325 </p>
326 </div>
327
328 <div class="tab-pane-header" ng-dblclick="activeEditPreview('desc')" title="Double click to edit">
329 <i class="fa fa-spinner fa-spin" ng-show="isUpdatingVuln === true && fieldToEdit === 'desc'"></i>
330 Description
331 </div>
332
333 <div>
334 <div class="tab-pane-header pretty-text" id="desc-prev" ng-dblclick="activeEditPreview('desc')" title="Double click to edit">
335 <span class="line-breaks">{{lastClickedVuln.desc}}</span>
336 </div>
337 </div>
338
339 </div>
340 </div>
341 <div class="form-group" ng-if="fieldToEdit === 'desc'">
342 <label for="inp-edit-desc"><i class="fa fa-spinner fa-spin" ng-show="isUpdatingVuln === true"></i> Description</label>
343 <textarea type="text" class="form-control" id="inp-edit-desc" rows="18"
344 ng-model="lastClickedVuln.desc" name="desc" placeholder="Description"
345 ng-blur="processToEditPreview()"
346 autofocus>
347 </textarea>
348 </div>
349 </div>
350 </div>
351
352 <div class="col-md-5">
353 <div class="row">
354 <div ng-if="fieldToEdit !== 'resolution'">
355 <div class="col-md-12 margin-bottom-24">
356 <div class="tab-pane-header" ng-dblclick="activeEditPreview('resolution')" title="Double click to edit">
357 <i class="fa fa-spinner fa-spin" ng-show="isUpdatingVuln === true && fieldToEdit === 'resolution'"></i>
358 Resolution
359 </div>
360 <div ng-if="lastClickedVuln.resolution === '' || lastClickedVuln.resolution === undefined" style="margin-bottom: 15px;color: #aaa;">
361 <p>
362 No Resolution was found.
363 </p>
364 </div>
365 <div class="tab-pane-header pretty-text" id="resolution-prev" ng-dblclick="activeEditPreview('resolution')" title="Double click to edit">
366 <span class="line-breaks">{{lastClickedVuln.resolution}}</span>
367 </div>
368
369 </div>
370 </div>
371 <div class="form-group" ng-if="fieldToEdit === 'resolution'">
372 <label for="inp-edit-desc"><i class="fa fa-spinner fa-spin" ng-show="isUpdatingVuln === true"></i> Resolution</label>
373 <textarea type="text" class="form-control" id="inp-edit-res" rows="18"
374 ng-model="lastClickedVuln.resolution" name="desc" placeholder="Resolution"
375 ng-blur="processToEditPreview(false)"
376 autofocus>
377 </textarea>
378 </div>
379 </div>
380 </div>
381 </div>
382
383 <div class="row margin-top-30px small-size">
384 <div class="tab-pane-header col-md-2">
385 Owner
386 <div class="text-gray">{{lastClickedVuln.metadata['owner']}}</div>
387 </div>
388 <div class="tab-pane-header col-md-3">
389 Created
390 <div class="text-gray"><span am-time-ago="lastClickedVuln.metadata['create_time']"></span></div>
391 </div>
392 <div class="tab-pane-header col-md-4 ">
393 Updated
394 <div class="text-gray"><span am-time-ago="lastClickedVuln.metadata['update_time']"></span></div>
395 </div>
396 </div>
397
398 </div>
399
400 <div id="technical_details_prev" class="container tab-pane-container tab-pane fade"><br>
401 <div class="padding-left-0 col-md-12">
402 <div class="padding-left-0 col-md-12">
403 <div class="tab-pane-header" ng-dblclick="activeEditPreview('data')" title="Double click to edit">
404 <i class="fa fa-spinner fa-spin" ng-show="isUpdatingVuln === true && fieldToEdit === 'data'"></i> Data
405 </div>
406 <div ng-if="fieldToEdit !== 'data'">
407 <div class="padding-left-0 col-md-12 margin-bottom-24">
408 <div ng-if="lastClickedVuln.data === '' || lastClickedVuln.data === undefined" style="margin-bottom: 15px;color: #aaa;">
409 <p>
410 No Data was found.
411 </p>
412 </div>
413 <div class="tab-pane-header pretty-text" id="data-prev" ng-dblclick="activeEditPreview('data')" title="Double click to edit">
414 <span class="line-breaks">{{lastClickedVuln.data}} </span>
415 </div>
416
417 </div>
418 </div>
419 <div class="form-group" ng-if="fieldToEdit === 'data'">
420 <textarea type="text" class="form-control" id="inp-edit-data" rows="18"
421 ng-model="lastClickedVuln.data" name="desc" placeholder="Data"
422 ng-blur="processToEditPreview(false)"
423 autofocus>
424 </textarea>
425 </div>
426 </div>
427
428 <div class="padding-left-0 row" style="margin-left: 0; margin-right: 0">
429 <div class="padding-left-0 col-md-6 col-sm-12 col-xs-12" ng-show="lastClickedVuln.type === 'VulnerabilityWeb'">
430 <div class="tab-pane-header" ng-dblclick="activeEditPreview('request')" title="Double click to edit"><i class="fa fa-spinner fa-spin" ng-show="isUpdatingVuln === true && fieldToEdit === 'request'"></i> Request
431 </div>
432 <div ng-if="fieldToEdit !== 'request'" >
433 <div class="col-md-12 margin-bottom-24">
434 <div class="tab-pane-header pretty-text text-code" id="request-prev">
435 <div ng-if="lastClickedVuln.request === '' || lastClickedVuln.request === undefined"
436 style="margin-bottom: 15px;color: #aaa;">
437 <p>
438 No Request was found.
439 </p>
440 </div>
441 <span class="line-breaks" ng-dblclick="activeEditPreview('request')" title="Double click to edit"> {{lastClickedVuln.request}} </span>
442 </div>
443 </div>
444 </div>
445 <div class="form-group" ng-if="fieldToEdit === 'request'">
446 <textarea type="text" class="form-control" id="inp-edit-request" rows="18"
447 ng-model="lastClickedVuln.request" name="desc" placeholder="Request"
448 ng-blur="processToEditPreview(false)"
449 autofocus>
450 </textarea>
451 </div>
452
453 </div>
454 <div class="col-md-6 col-sm-12 col-xs-12" ng-show="lastClickedVuln.type === 'VulnerabilityWeb'">
455 <div class="tab-pane-header" ng-dblclick="activeEditPreview('response')" title="Double click to edit"><i class="fa fa-spinner fa-spin" ng-show="isUpdatingVuln === true && fieldToEdit === 'response'"></i> Response
456 </div>
457 <div ng-if="fieldToEdit !== 'response'">
458 <div class="col-md-12 margin-bottom-24">
459 <div class="tab-pane-header pretty-text text-code" id="response-prev" >
460 <div ng-if="lastClickedVuln.response === '' || lastClickedVuln.response === undefined" style="margin-bottom: 15px;color: #aaa;">
461 <p>
462 No Response was found.
463 </p>
464 </div>
465 <span class="line-breaks" ng-dblclick="activeEditPreview('response')" title="Double click to edit"> {{lastClickedVuln.response}} </span>
466
467 </div>
468
469 </div>
470 </div>
471 <div class="form-group" ng-if="fieldToEdit === 'response'">
472 <textarea type="text" class="form-control" id="inp-edit-response" rows="18"
473 ng-model="lastClickedVuln.response" name="desc" placeholder="Response"
474 ng-blur="processToEditPreview(false)"
475 autofocus>
476 </textarea>
477 </div>
478 </div>
479 </div>
480 </div>
481 </div>
482
483 <div id="tab-evidence_prev" class="container tab-pane-container tab-pane fade"><br>
484 <div class="padding-left-0 col-md-12 margin-bottom-15px">
485
486 <div class="col-md-4">
487
488 <div class="tab-pane-header padding-left-0 col-md-8">Attachments</div>
489 <div class="padding-left-0 form-group col-md-4">
490 <div class="upload-plus">
491 <div class="icon-evidence">
492 <button type="button" class="btn btn-success col-md-12">
493 <i class="fa fa-plus"></i> New
494 </button>
495
496 </div>
497 <input type="file" class="input-evidence" nv-file-select="" uploader="uploader" multiple/>
498 </div>
499 </div>
500
501
502
503 <table class="table">
504 <thead>
505 <tr>
506 <th width="50%">Name</th>
507 <th>Actions</th>
508 </tr>
509 </thead>
510 <tbody>
511 <tr ng-repeat="(name, file) in lastClickedVuln._attachments">
512 <td>
513 <strong><a href="javascript:;" ng-click="selectItemToPrev(name)">{{ name }}</a></strong>
514 <div ng-show="uploader.isHTML5" ng-thumb="{ file: file, height: 100 }"></div>
515 </td>
516 <td nowrap>
517 <button type="button" class="btn btn-danger btn-xs" ng-click="removeEvidence(name)">
518 <span class="glyphicon glyphicon-trash"></span> Remove
519 </button>
520 <button type="button" class="btn btn-info btn-xs" ng-click="copyToClipboard(name)">
521 <span class="fa fa-copy"></span> Copy link
522 </button>
523 </td>
524 </tr>
525 </tbody>
526 </table>
527 </div>
528
529
530 <div class="col-md-8 attachment-prev">
531 <div ng-if="selectedAtachment.url === ''" class="no-info-overlay" style="margin-bottom: 15px;top: -8px;">
532 <p class="no-info-text">
533 No attachment selected
534 </p>
535 </div>
536
537 <div class="tab-pane-header">{{selectedAtachment.name}}</div>
538 <img ng-if="selectedAtachment.url !== '' && selectedAtachment.imgPrevFail === false" src="{{selectedAtachment.url}}" id="attachment-img">
539 <div class="no-info-overlay" ng-if="selectedAtachment.imgPrevFail === true" style="margin-bottom: 15px;top: -8px;">
540 <p class="no-info-text">
541 No available preview to this attachment
542 </p>
543 </div>
544 </div>
545
546
547
548 </div>
549
550 </div>
551
552 <div id="hosts_prev" class="container tab-pane-container tab-pane fade"><br>
553 <div class="padding-left-0 col-md-12">
554 <div class="padding-left-0 col-md-3">
555 <div class="tab-pane-header">Host</div>
556 <div class="tab-pane-header"><i class="fa fa-desktop"></i>&nbsp;&nbsp;{{lastClickedVuln.target}}:{{lastClickedVuln.service.ports}}</div>
557 </div>
558
559 <div class="padding-left-0 col-md-3">
560 <div class="tab-pane-header">Hostnames</div>
561 <div class="tab-pane-header" ng-repeat="hostname in lastClickedVuln.hostnames"><i class="fa fa-desktop"></i>&nbsp;&nbsp;{{hostname}}</div>
562 </div>
563 </div>
564 </div>
565
566 <div id="tab-custom-fields_prev" class="container tab-pane-container tab-pane fade"><br>
567 <div ng-if="customFields.length === 0" class="no-info-overlay" style="margin-bottom: 15px;">
568 <p class="no-info-text">
569 No custom fields were found. To create one refer to our
570 <a href="https://github.com/infobyte/faraday/wiki/Custom-Fields" target="_blank">wiki page</a>.
571 </p>
572 </div>
573 <div class="padding-left-0 col-md-5 margin-bottom-15px">
574 <div class="padding-left-0 col-md-12" ng-repeat="cf in customFields | orderBy : 'field_order'">
575 <custom-field-prev field="{{cf}}"></custom-field-prev>
576 </div>
577 </div>
578 </div>
579 </div>
580
581
582
583 </div>
584 </div>
166585 </div>
167586 <!-- .right-main -->
168587 </section>
00 <div ng-if="row.entity._id != undefined">
1 <div ng-if="!col.grouping || col.grouping.groupPriority === undefined || col.grouping.groupPriority === null || ( row.groupHeader && col.grouping.groupPriority === row.treeLevel )" class="ui-grid-cell-contents white-space"><a ng-href="{{grid.appScope.hash}}/search/name={{grid.appScope.encodeUrl(row.entity.name)}}" append-search-param="name={{grid.appScope.encodeUrl(row.entity.name)}}">{{COL_FIELD CUSTOM_FILTERS}}</a>
1 <div ng-keyup="grid.appScope.changeVulnPrevByEventKey($event)" ng-if="!col.grouping || col.grouping.groupPriority === undefined || col.grouping.groupPriority === null || ( row.groupHeader && col.grouping.groupPriority === row.treeLevel )" class="ui-grid-cell-contents white-space"><a href="javascript:;" ng-click="grid.appScope.toggleVulnPreview($event, row.entity)">{{COL_FIELD CUSTOM_FILTERS}}</a> &nbsp; &nbsp; <span style="color: #337ab7" ng-if="row.entity._id === grid.appScope.lastClickedVuln._id"><i class="fa fa-check"></i></span>
22 </div>
33 </div>
4 <div ng-if="row.groupHeader && col.grouping.groupPriority !== undefined" class="ui-grid-cell-contents white-space">{{COL_FIELD CUSTOM_FILTERS}}</div>
4 <div ng-keyup="grid.appScope.changeVulnPrevByEventKey($event)" ng-if="row.groupHeader && col.grouping.groupPriority !== undefined" class="ui-grid-cell-contents white-space">{{COL_FIELD CUSTOM_FILTERS}}</div>
0 // Faraday Penetration Test IDE
1 // Copyright (C) 2018 Infobyte LLC (http://www.infobytesec.com/)
2 // See the file 'doc/LICENSE' for the license information
3
4 angular.module('faradayApp')
5 .factory('uiCommonFact', ['BASEURL', function (BASEURL) {
6
7 var uiCommonFact = {};
8
9 uiCommonFact.updateBtnSeverityColor = function (severity, btnSelector, caretSelector) {
10 var color = undefined;
11 switch (severity) {
12 case "unclassified":
13 color = '#999999';
14 break;
15 case "info":
16 color = '#2e97bd';
17 break;
18 case "low":
19 color = '#a1ce31';
20 break;
21 case "med":
22 color = '#dfbf35';
23 break;
24 case "high":
25 color = '#df3936';
26 break;
27 case "critical":
28 color = '#932ebe';
29 break;
30 }
31
32 angular.element(btnSelector).css('background-color', color);
33 angular.element(caretSelector).css('background-color', color);
34 };
35
36
37 uiCommonFact.updateBtnStatusColor = function (status, btnSelector, caretSelector) {
38 var color = undefined;
39 switch (status) {
40 case "opened":
41 color = '#DB3130';
42 break;
43 case "closed":
44 color = '#97F72C';
45 break;
46 case "re-opened":
47 color = '#DBB72F';
48 break;
49 case "risk-accepted":
50 color = '#288DB4';
51 break;
52 default:
53 color = '#aaaaaa';
54 break;
55 }
56
57 angular.element(btnSelector).css('background-color', color);
58 angular.element(caretSelector).css('background-color', color);
59 };
60
61
62 uiCommonFact.populate = function (template, vuln) {
63 for (var key in vuln) {
64 if (key !== "refs" && key !== "policyviolations" && template.hasOwnProperty(key) && vuln.hasOwnProperty(key)) {
65 vuln[key] = template[key];
66 }
67 }
68 // convert refs to an array of objects
69 var refs = [];
70 template.refs.forEach(function (ref) {
71 refs.push(ref);
72 });
73 vuln.refs = refs;
74
75 // convert policyviolations to an array of objects
76 var policyviolations = [];
77 template.policyviolations.forEach(function (policyviolation) {
78 policyviolations.push(policyviolation);
79 });
80 vuln.policyviolations = policyviolations;
81 };
82
83
84 uiCommonFact.newReference = function (newRef, vuln) {
85 if (newRef !== "") {
86 // we need to check if the ref already exists
87 if (vuln.refs.filter(function (ref) {
88 return ref === newRef
89 }).length === 0) {
90 vuln.refs.push(newRef);
91 newRef = "";
92 }
93 }
94 };
95
96
97 uiCommonFact.newPolicyViolation = function (newPolicyViolation, vuln) {
98 if (newPolicyViolation !== "") {
99 // we need to check if the policy violation already exists
100 if (vuln.policyviolations.filter(function (policyviolation) {
101 return policyviolation.value === newPolicyViolation
102 }).length === 0) {
103 vuln.policyviolations.push(newPolicyViolation);
104 newPolicyViolation = "";
105 }
106 }
107 };
108
109
110 uiCommonFact.removeEvidence = function (name, vuln) {
111 delete vuln._attachments[name];
112 };
113
114 uiCommonFact.openEvidence = function (name, vuln, ws) {
115 var currentEvidence = vuln._attachments[name];
116 if (!currentEvidence.newfile)
117 window.open(BASEURL + '_api/v2/ws/' + ws + '/vulns/' + vuln._id + '/attachment/' + encodeURIComponent(name), '_blank');
118 };
119
120
121 return uiCommonFact;
122
123 }]);
00 with (import <nixpkgs> {});
1 let
2 in
31 mkShell {
4 buildInputs = with python27Packages;
2 buildInputs = [pandoc] ++ (with python27Packages;
53 [virtualenv pyopenssl psycopg2 pillow pygobject3 pynacl matplotlib lxml ldap
6 gobjectIntrospection gtk3 gnome3.vte ipython
7 ];
4 gobjectIntrospection gtk3 gnome3.vte ipython gssapi
5 ]);
86 shellHook = ''
97 unset SOURCE_DATE_EPOCH # Required to make pip work
8
9 VENV_PATH=.venv-white
10 grep -q p- VERSION && VENV_PATH=.venv-pink
11 grep -q b- VERSION && VENV_PATH=.venv-black
1012
1113 mkvirtualenv(){
1214 # Reset previous virtualenv
1315 type -t deactivate && deactivate
14 rm -rf venv
16 rm -rf $VENV_PATH
1517
1618 # Build new virtualenv with system packages
17 virtualenv --system-site-packages venv
18 source venv/bin/activate
19 virtualenv --system-site-packages $VENV_PATH
20 source $VENV_PATH/bin/activate
1921 pip install -r requirements_server.txt
2022 pip install -r requirements.txt
2123 pip install -r requirements_dev.txt
2224 }
2325
24 if [[ -d venv ]]; then
25 source venv/bin/activate
26 if [[ -d $VENV_PATH ]]; then
27 source $VENV_PATH/bin/activate
2628 else
2729 echo Creating new virtualenv
2830 mkvirtualenv
1313 res = test_client.get('v2/vulners/exploits/{id}'.format(id=cve_id))
1414 assert res.status_code == 200
1515
16 @pytest.mark.skip()
1617 def test_key_error(self, test_client):
1718 cve_id = "CVE-2018-1999035ERROR"
1819 res = test_client.get('v2/vulners/exploits/{id}'.format(id=cve_id))
1920 assert res.status_code == 400
2021
22 @pytest.mark.skip()
2123 def test_get_exploit_with_modules(self, test_client):
2224 cve_id = "CVE-2016-9299"
2325 res = test_client.get('v2/vulners/exploits/{id}'.format(id=cve_id))
1616 from hypothesis import given
1717 from hypothesis.strategies import text, lists, integers, one_of, none
1818 from depot.manager import DepotManager
19
20 from server.fields import FaradayUploadedFile
1921
2022 try:
2123 from urllib import urlencode
4143 VulnerabilityGeneric,
4244 Vulnerability,
4345 VulnerabilityWeb,
44 Reference, PolicyViolation, CommandObject)
46 Reference, PolicyViolation, CommandObject, File)
4547 from test_cases.factories import ServiceFactory, CommandFactory, \
4648 CommandObjectFactory, HostFactory, EmptyCommandFactory, \
4749 UserFactory, VulnerabilityWebFactory, VulnerabilityFactory, \
396398 assert res.status_code == 200
397399 assert res.data == file_content
398400
401 def test_get_attachments_by_vuln(self, test_client, session, workspace):
402 vuln = VulnerabilityFactory.create(workspace=workspace)
403 session.add(vuln)
404 session.commit()
405
406 with open('test_cases/data/faraday.png', 'r') as file_obj:
407 new_file = FaradayUploadedFile(file_obj.read())
408
409 new_attach = File(object_type='vulnerability', object_id=vuln.id, name='Faraday', filename='faraday.png',
410 content=new_file)
411 session.add(new_attach)
412 session.commit()
413
414 res = test_client.get(self.url(workspace=workspace) + '{0}/attachments/'.format(vuln.id))
415 assert res.status_code == 200
416 assert new_attach.filename in res.json
417 assert 'image/png' in res.json[new_attach.filename]['content_type']
399418
400419
401420 def test_create_vuln_props(self, host_with_hostnames, test_client, session):
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 try:
8 from lxml import etree as ET
9 except ImportError:
10 import xml.etree.ElementTree as ET
11
12 from server.config import FARADAY_BASE
13
14
15 def test_matching_versions():
16 with open(FARADAY_BASE + '/VERSION', 'r') as output:
17 version_file = output.read().strip()
18
19 version_default = parse_element_from_xml('version')
20
21 assert version_file == version_default
22
23
24 def parse_element_from_xml(tag_name):
25 with open(FARADAY_BASE + '/config/default.xml', 'r') as output:
26 default_data = output.read()
27 tree = ET.fromstring(default_data)
28 default_element = tree.find(tag_name).text
29
30 return default_element