Codebase list python-faraday / 45c43f9
Merge tag 'upstream/1.0.17' into kali/master Upstream version 1.0.17 Sophie Brun 8 years ago
46 changed file(s) with 1919 addition(s) and 1315 deletion(s). Raw diff Collapse all Expand all
1717 * Andres Tarantini
1818 * Ezequiel Tavella
1919 * Martin Tartarelli
20 * Ronald Iraheta
00 ![Faraday Logo](https://raw.github.com/wiki/infobyte/faraday/images/Faraday-Logo.png)
11
2 Faraday introduces a new concept (IPE) Integrated Penetration-Test Environment a multiuser Penetration test IDE. Designed for distribution, indexation and analysis of the generated data during the process of a security audit.
2 Faraday introduces a new concept - IPE (Integrated Penetration-Test Environment) a multiuser Penetration test IDE. Designed for distribution, indexation and analysis of the data generated during a security audit.
33
44 The main purpose of Faraday is to re-use the available tools in the community to take advantage of them in a multiuser way.
55
66 Designed for simplicity, users should notice no difference between their own terminal application and the one included in Faraday. Developed with a specialized set of functionalities that help users improve their own work. Do you remember yourself programming without an IDE? Well, Faraday does the same as an IDE does for you when programming, but from the perspective of a penetration test.
77
8 ![GUI - Web](https://raw.github.com/wiki/infobyte/faraday/images/GUI_Dashboard_new.png)
9
10
11 ![GUI - QT](https://raw.github.com/wiki/infobyte/faraday/images/Faraday-Mainwindow.png)
12
138 Please read the [RELEASE notes](https://github.com/infobyte/faraday/blob/master/RELEASE.md)!
149
15 Plugins list:
10 Plugins
1611 ---
17 Right now faraday has more than [40+ supported tools](https://github.com/infobyte/faraday/wiki/Plugin-List), among them you will find:
12 Don't change the way you work today! Faraday plays well with others, right now it has more than [40 supported tools](https://github.com/infobyte/faraday/wiki/Plugin-List), among them you will find:
13
1814 ![](https://raw.github.com/wiki/infobyte/faraday/images/plugins/Plugins.png)
1915
16 There are 3 kind of plugins:
17 * Plugins that intercept commands, fired directly when a command is detected in the console. These are transparent to you and no additional action on your part is needed.
18 * Plugins that import file reports. You have to copy the report to **$HOME/.faraday/report/[workspacename]** (replacing **[workspacename]** with the actual name of your Workspace) and Faraday will automatically detect, process and add it to the HostTree.
19 * Plugin connectors or online (BeEF, Metasploit, Burp), these connect to external APIs or databases, or talk directly to Faraday's RPC API.
2020
21 Installation
21 Getting started
2222 ---
23
24 The following platform are supported - [More information] (https://github.com/infobyte/faraday/wiki/Installation) :
23 The following platforms are supported:
2524
2625 ![platform](https://raw.github.com/wiki/infobyte/faraday/images/platform/supported.png)
2726
27 Read more about [supported platforms and installation specifics] (https://github.com/infobyte/faraday/wiki/Installation).
2828
29 Quick install:
29 #### Quick install
3030
31 Download the latest tarball by clicking [here] (https://github.com/infobyte/faraday/tarball/master)
31 This applies only to Debian, Ubuntu, Kali and Backtrack. For the full installation guide [visit our wiki](https://github.com/infobyte/faraday/wiki/Installation).
3232
33 Preferably, you can download faraday by cloning the [Git] (https://github.com/infobyte/faraday) repository:
33 Download the [latest tarball](https://github.com/infobyte/faraday/tarball/master) or clone the [Faraday Git Project](https://github.com/infobyte/faraday repository):
3434
35 $ git clone https://github.com/infobyte/faraday.git faraday-dev
36 $ cd faraday-dev
37 $ ./install.sh
38
35 ```
36 $ git clone https://github.com/infobyte/faraday.git faraday-dev
37 $ cd faraday-dev
38 $ ./install.sh
39 $ ./faraday.py
40 ```
3941
42 More about Faraday
43 ---
44 Want to read more about the project? Try our [wiki](https://github.com/infobyte/faraday/wiki).
4045
41 Usage
42 -----
46 Already a user and have a question or bug report? Please check out our [FAQ](https://github.com/infobyte/faraday/wiki/FAQ). If you're still having troubles you can [open a ticket](https://github.com/infobyte/faraday/issues/new).
4347
44 To get started, simply execute faraday and use the new console to start working in the pentest:
48 Join our community! Subscribe to our [mailing list](https://groups.google.com/forum/#!forum/faradaysec) or find us on Twitter [@faradaysec] (https://twitter.com/faradaysec) or IRC channel #faraday-dev in [freenode](ircs://irc.freenode.net/faraday-dev).
4549
46 $ ./faraday.py
47
48 Plugins types:
49 ---
50 We have 3 kind of plugins:
51 * Plugins that intercept commands (directly detected when you execute commands in the console)
52 * Plugins that import file reports (you have to copy the report to $HOME/.faraday/report/[workspacename] and faraday will automatically detect the report, process and added to the HostTree.
53 * Plugins connectors or online (BeEF, Metasploit, Burp) connect directly with external API or database or connect with Faraday RPC API.
54
55 Get it now!
56 ---
57 [![Download Tarball](https://raw.github.com/wiki/infobyte/faraday/images/download.png)]
58 (https://github.com/infobyte/faraday/tarball/master)
59
60 Links
61 ---
62
63 * Homepage: http://faradaysec.com
64 * User's manual: https://github.com/infobyte/faraday/wiki
65 * Download: [.tar.gz] (https://github.com/infobyte/faraday/tarball/master)
66 * Commits RSS feed: https://github.com/infobyte/faraday/commits/master.atom
67 * Issue tracker: https://github.com/infobyte/faraday/issues
68 * Frequently Asked Questions (FAQ): https://github.com/infobyte/faraday/wiki/FAQ
69 * Mailing list subscription: https://groups.google.com/forum/#!forum/faradaysec
70 * Twitter: [@faradaysec] (https://twitter.com/faradaysec)
71 * [Demos] (https://github.com/infobyte/faraday/wiki/Demos)
72 * IRC: [ircs://irc.freenode.net/faraday-dev] (ircs://irc.freenode.net/faraday-dev)
73 * Screenshots: https://github.com/infobyte/faraday/wiki/Screenshots
74
88
99 New features in the latest update
1010 =====================================
11
12 Feb 26, 2016:
13 ---
14 * Fixed bug in pip debian
15 * BugFix pip install.
16 * Checks additionals about dependencies in installation.
17 * Warning about a upgrade to experimental in debian installation.
18 * Fixed small bug in CSV importing
19 * Fixed styles for Status Report
20 * Fixed bug on Status Report filter after editing
21 * Added support for Kali Rolling Edition
22 * Notify user when the current Workspace doesn't exist
23 * Show all evidence files in Status Report
24 * Added script to remove all vulns with a specific severity value (parameterized)
25 * Fixed Arachni Plugin bugs
26 * Added new version for Maltego Plugin
27 * Added support for Mint 17
1128
1229 Dec 18, 2015:
1330 ---
4966 * Added Services columns to Status Report
5067 * Added sections of Commercial versions
5168 * Converted references to links in Status Report. Support for CVE, CWE, Exploit Database and Open Source Vulnerability Database
52 * Added Pippingtom, SSHdefaultscan and pasteAnalyzer plugins
69 * Added Peepingtom, SSHdefaultscan and pasteAnalyzer plugins
5370 * Fixed Debian install
5471
5572 Sep 10, 2015:
0 1.0.16
0 1.0.17
11 <faraday>
22
33 <appname>Faraday - Penetration Test IDE</appname>
4 <version>1.0.16</version>
4 <version>1.0.17</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>
1616 import argparse
1717 import platform
1818 import subprocess
19 import pip
2019 import json
2120
2221 from utils.logs import getLogger, setUpLogger
2524 from config.globals import *
2625 from utils.profilehooks import profile
2726 from utils.user_input import query_yes_no
28
2927
3028
3129 USER_HOME = os.path.expanduser(CONST_USER_HOME)
124122 help="Disable the application exception hook that allows to send error \
125123 reports to developers.")
126124
127 parser.add_argument('--disable-login', action="store_true",
128 dest="disable_login",
129 default=False,
130 help="Disable the auth splash screen.")
131
132125 parser.add_argument('--dev-mode', action="store_true", dest="dev_mode",
133126 default=False,
134127 help="Enable dev mode. This will use the user config and plugin folder.")
152145
153146 parser_gui_ex.add_argument('--cli', '--console', action="store_true",
154147 dest="cli",
155 default="false",
148 default=False,
156149 help="Set this flag to avoid gui and use faraday as a cli.")
157150
158151 #args = parser.parse_args(['@parser_args.cfg'])
207200 """
208201
209202 if not args.ignore_deps:
210
211 modules = []
212 f = open(CONST_REQUIREMENTS_FILE)
213 for line in f:
214 if not line.find('#'):
215 break
216 else:
217 modules.append([line[:line.index('=')], (line[line.index('=')+2:]).strip()])
218 f.close()
219
220 pip_dist = [dist.project_name.lower() for dist in pip.get_installed_distributions()]
221
222 for module in modules:
223 if module[0].lower() not in pip_dist:
224 try:
225 __import__(module[0])
226 except ImportError:
227 if query_user_bool("Missing module %s."
228 " Do you wish to install it?" % module[0]):
229 pip.main(['install', "%s==%s" %
230 (module[0], module[1]), '--user'])
231
232 else:
233 return False
203 try:
204 import pip
205 modules = []
206 f = open(CONST_REQUIREMENTS_FILE)
207 for line in f:
208 if not line.find('#'):
209 break
210 else:
211 modules.append([line[:line.index('=')], (line[line.index('=')+2:]).strip()])
212 f.close()
213 pip_dist = [dist.project_name.lower() for dist in pip.get_installed_distributions()]
214
215 for module in modules:
216 if module[0].lower() not in pip_dist:
217 try:
218 __import__(module[0])
219 except ImportError:
220 if query_user_bool("Missing module %s."
221 " Do you wish to install it?" % module[0]):
222 pip.main(['install', "%s==%s" %
223 (module[0], module[1]), '--user'])
224
225 else:
226 return False
227 except ImportError:
228 pass
234229
235230 return True
236231
281276 CONF.setApiConInfoHost(host)
282277 CONF.setApiConInfoPort(port_xmlrpc)
283278 CONF.setApiRestfulConInfoPort(port_rest)
284
285 CONF.setAuth(args.disable_login)
286279
287280
288281 def startFaraday():
547540 getInstanceConfiguration().setAppname("Faraday - Penetration Test IDE Community")
548541 parameter = {"version": getInstanceConfiguration().getVersion()}
549542
550 f.close
543 f.close()
551544 resp = requests.get(uri, params=parameter, timeout=1, verify=True)
552545 resp = resp.text.strip()
553546 except Exception as e:
757757 continue
758758
759759 d = l.split("|")
760
761 if len(d) <=8:
760 if len(d) <8:
762761 api.log("Error vuln line: ("+l+")" )
763762 else:
764763 self._newVulnImport(d[1],d[2],d[3],d[4],d[5],d[6],d[7])
0 #!/usr/bin/env python2.7
1 '''
2 Faraday Penetration Test IDE
3 Copyright (C) 2014 Infobyte LLC (http://www.infobytesec.com/)
4 See the file 'doc/LICENSE' for the license information
5
6 '''
7 '''
8 This script either updates or removes Interfaces, Services and Vulnerabilities in case their parent property is null.
9 If the property is null but a parent is found in Couch, the document is updated.
10 If the parent is not found in Couch the document is deleted, since it is an invalid one.
11 '''
12
13 import argparse
14 import json
15 import requests
16 import os
17
18 def main():
19 #arguments parser
20 parser = argparse.ArgumentParser(prog='removeBySeverity', epilog="Example: ./%(prog)s.py")
21 parser.add_argument('-c', '--couchdburi', action='store', type=str,
22 dest='couchdb',default="http://127.0.0.1:5984",
23 help='Couchdb URL as http://user:password@couch_ip:couch_port (defaults to http://127.0.0.1:5984)')
24 parser.add_argument('-d', '--db', action='store', type=str, required=True,
25 dest='db', help='DB to process')
26 parser.add_argument('-s', '--severity', action='store', type=str, required=True,
27 dest='severity', help='Vulnerability severity')
28 parser.add_argument('-t', '--test', action='store_true',
29 dest='test', help='Dry run, does everything except updating the DB')
30 parser.add_argument('-v', '--verbose', action='store_true',
31 dest='verbose', help='Extended output')
32
33 #arguments put in variables
34 args = parser.parse_args()
35 db = args.db
36 severity = args.severity
37 test = args.test
38 verbose = args.verbose
39
40 #default value from ENV COUCHDB
41 couchdb = os.environ.get('COUCHDB')
42 #Else from argument
43 if not couchdb:
44 couchdb = args.couchdb
45
46 fixDb(couchdb, db, severity, test, verbose)
47
48 def fixDb(couchdb, db, severity, test, verbose):
49 couchdb = str(couchdb)
50 db = str(db)
51
52 #get all broken elements from CouchDB
53 headers = {'Content-Type': 'application/json'}
54 payload = { "map" : """function(doc) { if((doc.type == \"Vulnerability\" && doc.severity == \""""+severity+"""\") ||
55 (doc.type == \"VulnerabilityWeb\" && doc.severity == \""""+severity+"""\")){ emit(doc._id, doc._rev); }}""" }
56
57 r = requests.post(couchdb + '/' + db + '/_temp_view', headers=headers, data=json.dumps(payload))
58 response_code = r.status_code
59
60 if response_code == 200:
61 response = r.json()
62 rows = response['rows']
63 # ID is ID, value is REV
64
65 if len(rows) > 0:
66 print " [*[ Processing " + str(len(rows)) + " documents for " + db + " ]*]"
67
68 for row in rows:
69 id = str(row['id'])
70 rev = str(row['value'])
71
72 # delete vuln
73 if verbose:
74 print " - Deleting vulnerability with ID " + id
75 if not test:
76 delete = requests.delete(couchdb + '/' + db + '/' + id + '?rev=' + rev)
77 if verbose:
78 print " -- " + delete.reason + " (" + str(delete.status_code) + ")"
79 print " Done"
80 else:
81 print "No vulns were found in DB " + db + " with severity " + severity + "!"
82 elif response_code == 401:
83 print " Autorization required to access " + db + ", make sure to add user:pwd to Couch URI using --couchdburi"
84 else:
85 print "Error connecting to CouchDB, please verify the service is up"
86
87 if __name__ == "__main__":
88 main()
33 ## Copyright (C) 2013 Infobyte LLC (http://www.infobytesec.com/)
44 ## See the file 'doc/LICENSE' for the license information
55 ###
6
76
87 #Check if is it root
98 if [ $EUID -ne 0 ]; then
4039 os="$(uname -s) $(uname -r)"
4140 fi
4241
42 #Check if python2 is already installed
43 if ! which python2 > /dev/null; then
44 echo "[-] Please install Python2 or make sure it is in your path"
45 exit 1
46 fi
47
4348 echo "[+] Install $os $arch"
4449 down=0
4550 if [ "$os" = "Ubuntu 10.04.2 LTS" ]; then
4651 version="ubuntu10-04.02$arch"
47 elif [[ "$os" =~ "Kali GNU/Linux 2."* ]]; then
52 elif [[ "$os" =~ "Kali GNU/Linux 2."*|"Kali GNU/Linux Rolling".* ]]; then
4853 version="kali2-$arch"
49 down=1
54 down=1
5055 elif [[ "$os" =~ .*Kali.* ]]; then
5156 version="kali-$arch"
5257 down=1
6368 down=1
6469 # Install pip from github.
6570 # Bug: https://bugs.launchpad.net/ubuntu/+source/python-pip/+bug/1306991
71 wget https://bootstrap.pypa.io/get-pip.py
72 python get-pip.py
73 elif [[ "$os" =~ "Mint 17".* ]]; then
74 version="ubuntu13-10-$arch"
75 down=1
76 # Install pip from github.
77 # Bug: https://bugs.launchpad.net/ubuntu/+source/python-pip/+bug/1306991
6678 wget https://raw.github.com/pypa/pip/master/contrib/get-pip.py
6779 python get-pip.py
6880 elif [[ "$os" =~ "Debian 7".*|"Debian 8".*|"stretch/sid".* ]]; then
6981 version="ubuntu13-10-$arch"
7082 down=1
71 wget https://raw.github.com/pypa/pip/master/contrib/get-pip.py
72 python get-pip.py
83 # Install pip from github.
84 # Bug: https://bugs.launchpad.net/ubuntu/+source/python-pip/+bug/1306991
85 wget https://bootstrap.pypa.io/get-pip.py
86 python get-pip.py
87
88 #Check if user agree with change to experimental
89 read -r -p "We need change your debian to experimental - sid branch (If you are not). You agree?[Y/n] " input
90
91 case $input in
92
93 [nN][oO]|[nN])
94 echo "[!]Faraday install: Aborted"
95 echo "[!]You need agree the update to experimental - sid"
96 exit 1;;
97 esac
98
7399 echo "deb http://ftp.debian.org/debian experimental main" >> /etc/apt/sources.list
74100 echo "deb http://ftp.debian.org/debian sid main" >> /etc/apt/sources.list
75101 apt-get update
76102
77103 if [[ "$os" =~ "Debian 7".* ]]; then
78104 apt-get -t experimental -y install libc6-dev
79 sed -i 's/deb http:\/\/ftp.debian.org\/debian experimental main//' /etc/apt/sources.list
80 sed -i 's/deb http:\/\/ftp.debian.org\/debian sid main//' /etc/apt/sources.list
81 apt-get update
82105 fi
83106 else
84107 echo "[-] Could not find a install for $os ($arch $kernel)"
86109 fi
87110
88111 if [ "$down" -eq 1 ]; then
89
112
90113 if [ -e lib-$version.tgz ]; then
91114 echo "[+] QT Libs already downloaded"
92115 else
93116 echo "[+] Download QT Libs"
94117 wget "https://www.faradaysec.com/down/faraday/lib-$version.tgz" -O lib-$version.tgz
95118 fi
96
119
97120 shav="sha_${version//-/_}"
98121 echo `sha256sum lib-$version.tgz`
99122 if [ -e lib-$version.tgz ]; then
100123 if [ "`echo ${!shav}`" = "`sha256sum lib-$version.tgz | awk -F\" \" \{'print $1'\}`" ]; then
101124 echo "[+] SHA256 ok"
102 tar -xvzf lib-$version.tgz
125 tar -xvzf lib-$version.tgz
103126 mv lib-$version/ external_libs
104127 else
105128 rm lib-$version.tgz
118141 apt-get update
119142 update=1
120143 fi
144
121145 apt-get --ignore-missing -y install ipython python-pip python-dev libpq-dev couchdb
146
147 #Check if python-setuptools not exists.
148 python -c "import setuptools" > /dev/null 2>&1
149
150 if [ "$?" -eq 1 ]; then
151 apt-get install python-setuptools
152 fi
153
154 #Delete debian experimental from sources.
155 if [[ "$os" =~ "Debian 7".*|"Debian 8".*|"stretch/sid".* ]]; then
156 sed -i 's/deb http:\/\/ftp.debian.org\/debian experimental main//' /etc/apt/sources.list
157 sed -i 's/deb http:\/\/ftp.debian.org\/debian sid main//' /etc/apt/sources.list
158 apt-get update
159 fi
160
122161 pip install -r requirements.txt
123162
124163 echo "You can now run Faraday, enjoy!"
1414 import requests
1515 try:
1616 import xml.etree.cElementTree as ET
17
17
1818 except ImportError:
1919 print "cElementTree could not be imported. Using ElementTree instead"
2020 import xml.etree.ElementTree as ET
2424 CONF = getInstanceConfiguration()
2525
2626 class NoReportsWatchException(Exception): pass
27
27
2828 class ReportManager(threading.Thread):
2929 def __init__(self, timer, plugin_controller, path=None):
3030 threading.Thread.__init__(self)
3939 def run(self):
4040 tmp_timer = 0
4141 while not self._stop:
42
42
4343 time.sleep(1)
4444 tmp_timer += 1
4545 if tmp_timer == self.timer:
5252
5353 def stop(self):
5454 self._stop = True
55
55
5656 def watch(self, name):
5757 self._report_path = os.path.join(CONF.getReportPath(), name)
5858 self._report_ppath = os.path.join(self._report_path, "process")
6161 os.mkdir(self._report_path)
6262
6363 if not os.path.exists(self._report_ppath):
64 os.mkdir(self._report_ppath)
64 os.mkdir(self._report_ppath)
6565
6666 def startWatch(self):
6767 if not self._report_path:
6868 raise NoReportsWatchException()
6969 self.start()
70
70
7171 def syncReports(self):
7272 """
7373 Synchronize report directory using the DataManager and Plugins online
7474 We first make sure that all shared reports were added to the repo
7575 """
76
76
7777 for root, dirs, files in os.walk(self._report_path, False):
78
78
7979 if root == self._report_path:
8080 for name in files:
8181 filename = os.path.join(root, name)
8282 model.api.log( "Report file is %s" % filename)
83
84 parser = ReportXmlParser(filename)
83
84 parser = ReportParser(filename)
8585 if (parser.report_type is not None):
86
86
8787 host = CONF.getApiConInfoHost()
8888 port_rest = int(CONF.getApiRestfulConInfoPort())
8989
9393
9494 command_string = "./%s %s" % (parser.report_type.lower(), filename)
9595 model.api.log("Executing %s" % (command_string))
96
97 new_cmd, output_file = client.send_cmd(command_string)
98 client.send_output(command_string, filename)
99 os.rename(filename, os.path.join(self._report_ppath, name))
96
97 new_cmd, output_file = client.send_cmd(command_string)
98 client.send_output(command_string, filename)
99 os.rename(filename, os.path.join(self._report_ppath, name))
100100
101101 self.onlinePlugins()
102102
103
103
104104 def onlinePlugins(self):
105105 """
106106 Process online plugins
108108 _pluginsOn={"MetasploitOn" : "./metasploiton online",}
109109 _pluginsOn.update({"Beef" : "./beef online",})
110110 _psettings=CONF.getPluginSettings()
111
111
112112 for k,v in _pluginsOn.iteritems():
113113 if k in _psettings:
114114 if _psettings[k]['settings']['Enable'] == "1":
116116 "",
117117 v,
118118 False)
119
119
120120 self.plugin_controller.storeCommandOutput("")
121
121
122122 self.plugin_controller.onCommandFinished()
123
124
125
126 class ReportXmlParser(object):
127
128 """Plugin that handles XML report files.
129
130 :param xml_filepath: Xml file.
131
132 :class:`.LoadReportXML`
123
124
125
126 class ReportParser(object):
127
133128 """
134
135 def __init__(self, xml_report_path):
129 Class that handles reports files.
130
131 :param filepath: report file.
132
133 :class:`.LoadReport`
134 """
135
136 def __init__(self, report_path):
136137 self.report_type = ""
137 root_tag,output = self.getRootTag(xml_report_path)
138 root_tag, output = self.getRootTag(report_path)
138139
139140 if root_tag:
140 self.report_type = self.rType(root_tag,output)
141
142 def getRootTag(self, xml_file_path):
143 result = f = None
141 self.report_type = self.rType(root_tag, output)
142
143 def open_file(self, file_path):
144 """
145 This method uses file signatures to recognize file types
146
147 :param file_path: report file.
148 """
149
150 """
151 If you need add support to a new report type
152 add the file signature here
153 and add the code in self.getRootTag() for get the root tag.
154 """
155
156 f = result = None
157
158 signatures = {
159 "\x50\x4B" : "zip" ,
160 "\x3C\x3F\x78\x6D\x6C" : "xml"
161 }
162
144163 try:
145 f = open(xml_file_path, 'rb')
164 f = open(file_path, 'rb')
165 file_signature = f.read(10)
166 f.seek(0)
167
168 for key in signatures:
169 if file_signature.find(key) == 0:
170
171 result = signatures[key]
172 model.api.log("Report type detected: %s" %result)
173 break
174
175 except IOError, err:
176 self.report_type = None
177 model.api.log("Error while opening file.\n%s. %s" % (err, file_path))
178
179 return f, result
180
181 def getRootTag(self, file_path):
182
183 report_type = result = f = None
184
185 f, report_type = self.open_file(file_path)
186
187 #Check error in open_file()
188 if f == None and report_type == None:
189 self.report_type = None
190 return None, None
191
192 #Find root tag based in report_type
193 if report_type == "zip":
194 result = "maltego"
195
196 elif report_type == "xml":
197
146198 try:
147199 for event, elem in ET.iterparse(f, ('start', )):
148200 result = elem.tag
149201 break
202
150203 except SyntaxError, err:
151204 self.report_type = None
152205 model.api.log("Not an xml file.\n %s" % (err))
153206
154 except IOError, err:
155 self.report_type = None
156 model.api.log("Error while opening file.\n%s. %s" % (err, xml_file_path))
157 finally:
158 f.seek(0)
159 output=f.read()
160 if f: f.close()
161
162 return result,output
163
207 f.seek(0)
208 output = f.read()
209 if f: f.close()
210
211 return result, output
212
164213 def rType(self, tag, output):
165214 """Compares report root tag with known root tags.
166
215
167216 :param root_tag
168217 :rtype
169218 """
170 if "arachni_report" == tag:
171 return "arachni"
172 elif "nmaprun" == tag:
219 if "nmaprun" == tag:
173220 return "nmap"
174221 elif "w3af-run" == tag:
175222 return "w3af"
176223 elif "NessusClientData_v2" == tag:
177224 return "nessus"
178225 elif "report" == tag:
179 if re.search("alertitem",output) is None:
226 if re.search("https://raw.githubusercontent.com/Arachni/arachni/", output) != None:
227 return "arachni_faraday"
228 elif re.search("OpenVAS", output) != None:
180229 return "openvas"
181230 else:
182231 return "zap"
208257 return "retina"
209258 elif "netsparker" == tag:
210259 return "netsparker"
260 elif "maltego" == tag:
261 return "maltego_faraday"
211262 else:
212263 return None
22
33 '''
44 Faraday Penetration Test IDE
5 Copyright (C) 2013 Infobyte LLC (http://www.infobytesec.com/)
5 Copyright (C) 2016 Infobyte LLC (http://www.infobytesec.com/)
66 See the file 'doc/LICENSE' for the license information
77 '''
88
1111 from model import api
1212 import socket
1313 import re
14 import os
15 import pprint
16 import sys
1714
1815 try:
1916 import xml.etree.cElementTree as ET
2017 except ImportError:
2118 import xml.etree.ElementTree as ET
2219
23 """Arachni plugin XML Parser.
24
25 Description.
26
27 """
28
29 current_path = os.path.abspath(os.getcwd())
30
31 __author__ = "Matías Ariel Ré Medina"
32 __copyright__ = "Copyright 2011, Faraday Project"
33 __credits__ = ["Matías Ariel Ré Medina"]
34 __license__ = ""
35 __version__ = "1.0.0"
36 __maintainer__ = "Matías Ariel Ré Medina"
37 __email__ = "[email protected]"
38 __status__ = "Development"
39
40 class ArachniXmlParser(object):
41 """Plugin that parses Arachni's XML report files.
42
43 :param arachni_xml_filepath: Xml report generated by Arachni.
44
45 :class:`.ArachniXmlParser`
46 """
20 __author__ = 'Ezequiel Tavella'
21 __copyright__ = 'Copyright 2016, Faraday Project'
22 __credits__ = ['Ezequiel Tavella', 'Matías Ariel Ré Medina', ]
23 __license__ = ''
24 __version__ = '1.0.1'
25 __status__ = 'Development'
26
27 class ArachniXmlParser():
28
4729 def __init__(self, xml_output):
48 tree = self.parse_xml(xml_output)
49
50 if tree:
51 self.issues = self.getIssues(tree)
52 self.system = self.getSystem(tree)
30
31 self.tree = self.parse_xml(xml_output)
32
33 if self.tree:
34 self.issues = self.getIssues(self.tree)
35 self.plugins = self.getPlugins(self.tree)
36 self.system = self.getSystem(self.tree)
37
5338 else:
54 self.issues = []
55 self.system = []
39 self.system = None
40 self.issues = None
41 self.plugins = None
5642
5743 def parse_xml(self, xml_output):
58 """Opens and parses an arachni xml report file.
59
60 :param filepath:
61
62 :rtype xml_tree: An xml tree instance. None if error.
63 """
44
6445 try:
6546 tree = ET.fromstring(xml_output)
6647 except SyntaxError, err:
67 print "SyntaxError: %s. %s" % (err, xml_output)
48 print 'SyntaxError In xml: %s. %s' % (err, xml_output)
6849 return None
6950
7051 return tree
7152
7253 def getIssues(self, tree):
54
55 #Get vulnerabilities.
56 issues_tree = tree.find('issues')
57 for self.issue_node in issues_tree:
58 yield Issue(self.issue_node)
59
60 def getPlugins(self, tree):
61
62 #Get info about plugins executed in scan.
63 plugins_tree = tree.find('plugins')
64 return Plugins(plugins_tree)
65
66 def getSystem(self, tree):
67
68 #Get options of scan.
69 return System(tree)
70
71
72 class Issue():
73
74 def __init__(self, issue_node):
75
76 self.node = issue_node
77
78 self.name = self.getDesc('name')
79 self.severity = self.getDesc('severity')
80 self.cwe = self.getDesc('cwe')
81
82 self.remedy_guidance = self.getDesc('remedy_guidance')
83 self.description = self.getDesc('description')
84
85 self.var = self.getChildTag('vector', 'affected_input_name')
86 self.url = self.getChildTag('vector', 'url')
87 self.method = self.getChildTag('vector', 'method')
88
89 self.references = self.getReferences()
90 self.parameters = self.getParameters()
91
92 self.request = self.getRequest()
93 self.response = self.getResponse()
94
95 def getDesc(self, tag):
96
97 #Get value of tag xml
98 description = self.node.find(tag)
99
100 if description != None and description.text != None:
101 return description.text.encode('ascii', 'ignore')
102 else:
103 return 'None'
104
105 def getChildTag(self, main_tag, child_tag):
106
107 #Get value of tag child xml
108 main_entity = self.node.find(main_tag)
109
110 if not main_entity:
111 return 'None'
112
113 result = main_entity.find(child_tag)
114
115 if result != None and result.text != None:
116 return result.text.encode('ascii', 'ignore')
117 else:
118 return 'None'
119
120 def getReferences(self):
121
73122 """
74 :param tree:
123 Returns current issue references on this format
124 {'url': 'http://www.site.com', 'name': 'WebSite'}.
75125 """
76 for issues in tree.findall('issues'):
77 for self.issue_node in issues.findall('issue'):
78 yield Issue(self.issue_node)
79
80 def getSystem(self, tree):
81 """
82 :param tree:
83 """
84 for self.system_node in tree.findall('system'):
85 yield System(self.system_node)
86
87 def getPlugins(self, tree):
88 """
89 :param tree:
90 """
91 for self.plugin_node in tree.findall('plugins'):
92 yield Plugins(self.plugin_node)
93
94
95
96
97
98
99
100 class Issue(object):
101 def __init__(self, issue_node):
102 """
103 :param issue_node:
104 """
105 self.node = issue_node
106 self.name = self.getDesc(issue_node, 'name')
107 self.var = self.getDesc(issue_node, 'var')
108 self.severity = self.getDesc(issue_node, 'severity')
109 self.url = self.getDesc(issue_node, 'url').lower()
110 self.element = self.getDesc(issue_node, 'element')
111 self.cwe = self.getDesc(issue_node, 'cwe')
112 self.method = self.getDesc(issue_node, 'method')
113 self.tags = self.getTags(issue_node, 'tags', 'tag')
114 self.variable = self.getDesc(issue_node, 'variable')
115 self.remedy_guidance = self.getDesc(issue_node, 'remedy_guidance')
116 self.description = self.getDesc(issue_node, 'description')
117 self.manual_verification = self.getDesc(issue_node, 'manual_verification')
118 self.references = self.getReferences(issue_node)
119 self.variations = self.getVariations(issue_node)
120
121 def getDesc(self, issue_node, tag):
122 """
123 :param issue_node:
124 :param tag:
125 :rtype text: Returns current issue description
126 """
127 desc = issue_node.findall(tag)
128 if desc:
129 return desc[0].text
126
127 result = []
128
129 references = self.node.find('references')
130
131 if not references:
132 return result
133
134 for tag in references.findall('reference'):
135 url = tag.get('url')
136 result.append(url)
137
138 return result
139
140 def getParameters(self):
141
142 #Get parameters of query
143 result = []
144
145 parameters = self.node.find('vector').find('inputs')
146
147 if not parameters:
148 return result
149
150 for param in parameters.findall('input'):
151 name = param.get('name')
152 result.append(name)
153
154 return ' - '.join(result)
155
156 def getRequest(self):
157
158 #Get data about request.
159 try:
160
161 raw_data = self.node.find('page').find('request').find('raw')
162 data = raw_data.text.encode('ascii','ignore')
163 return data
164
165 except:
166 return 'None'
167
168 def getResponse(self):
169
170 #Get data about response.
171 try:
172
173 raw_data = self.node.find('page').find('response').find('raw_headers')
174 data = raw_data.text.encode('ascii','ignore')
175 return data
176
177 except:
178 return 'None'
179
180
181 class System():
182
183 def __init__(self, node):
184
185 self.node = node
186
187 self.user_agent = 'None'
188 self.url = 'None'
189 self.audited_elements = 'None'
190 self.modules = 'None'
191 self.cookies = 'None'
192
193 self.getOptions()
194
195 self.version = self.getDesc('version')
196 self.start_time = self.getDesc('start_datetime')
197 self.finish_time = self.getDesc('finish_datetime')
198
199 self.note = self.getNote()
200
201 def getOptions(self):
202
203 #Get values of options scan
204 options_string = self.node.find('options').text
205
206 if not options_string:
207 return
208
209 regex_modules = re.compile('checks:\n([\w\d\s\W\D\S]{0,})(platforms:)')
210 regex_user_agent = re.compile('user_agent:(.+)')
211 regex_cookies = re.compile('cookies: {()}')
212 regex_url = re.compile('url:(.+)')
213
214 regex_audited_elements = re.compile(
215 'audit:\n([\w\d\s\W\D\S]{0,})input:|session:'
216 )
217
218 result = re.search(regex_modules, options_string)
219 if result.group(1):
220 self.modules = result.group(1)
221
222 result = re.search(regex_user_agent, options_string)
223 if result.group(1):
224 self.user_agent = result.group(1)
225
226 result = re.search(regex_cookies, options_string)
227 if result.group(1):
228 self.cookies = result.group(1)
229
230 result = re.search(regex_url, options_string)
231 if result.group(1):
232 self.url = result.group(1)
233
234 result = re.search(regex_audited_elements, options_string)
235 if result.group(1):
236 self.audited_elements = result.group(1)
237
238 def getDesc(self, tag):
239
240 #Return value of tag
241 description = self.node.find(tag)
242
243 if description != None and description.text != None:
244 return description.text
130245 else:
131246 return 'None'
132247
133 def getTags(self, issue_node, main_tag, child_tag):
134 """
135 :param issue_node:
136 :param main_tag:
137 :param child_tag:
138 :rtype string: Returns current issue tag description
139 """
140 for tags in issue_node.findall(main_tag):
141 for tag in tags.findall(child_tag):
142 tagDesc = tag.attrib['name']
143 if tagDesc:
144 return tagDesc
145 else:
146 return 'None'
147
148 def getReferences(self, issue_node):
149 """Returns current issue references on this format {'url': 'http://www.site.com', 'name': 'WebSite'}.
150
151 :param issue_node: Issue instance.
152 :param main_tag: Container's tag.
153 :param child_tag: Child's tag.
154
155 :rtype dict: Reference
156 """
157 for tags in issue_node.findall('references'):
158 for tag in tags.findall('reference'):
159 reference = tag.attrib
160 if reference:
161 return reference
162 else:
163 return "None"
164
165 def getVariations(self, issue_node):
166 """Returns variations in dict format.
167
168 :param issue_node: Issue instance.
169
170 :rtype dict: Variations, keys : {'url', 'headers' , 'html'}
171
172 """
173 requests = []
174 responses = []
175 html = []
176 url = []
177 headers = [requests, responses]
178 for variations in issue_node.findall('variations'):
179 for variation in variations.findall('variation'):
180 for urltmp in variation.findall('url'):
181 url.append(urltmp.text.lower())
182 for heads in variation.findall('headers'):
183 for request in heads.findall('request'):
184 for field in request.findall('field'):
185 requests.append(field.attrib)
186 for response in heads.findall('response'):
187 for field in response.findall('field'):
188 responses.append(field.attrib)
189 for htmltmp in variation.findall('html'):
190 html.append(htmltmp.text)
191
192 finalVariation = {'url' : url, 'headers' : headers, 'html' : html}
193 return
194
195
196
197
198
199
200 class System(object):
201 def __init__(self, system_node):
202 self.system_node = system_node
203 self.version = self.getDesc('version')
204 self.revision = self.getDesc('revision')
205 self.star_ttime = self.getDesc( 'start_datetime')
206 self.finish_time = self.getDesc('finish_datetime')
207 self.delta_time = self.getDesc('delta_time')
208 self.url = self.getDesc('url')
209 self.user_agent = self.getDesc('user_agent')
210 self.audited_elements = self.getChildDesc('audited_elements', 'element')
211 self.modules = self.getChildDesc('modules', 'module')
212 self.filters = self.getFilters()
213 self.cookies = self.getChildDesc('cookies', 'cookie')
214
215 def getDesc(self, tag):
216 """
217 :param tag:
218 :rtype text: Returns current issue description
219 """
220 desc = self.system_node.findall(tag)
221 if desc:
222 return desc[0].text
223 else:
224 return 'None'
225
226 def getChildDesc(self, father_tag, child_tag):
227 """Returns modules in dict format.
228
229 :param father_tag: Container's tag.
230 :param child_tag: Child's tag.
231 :rtype child: (string/dict)
232
233 """
234 for tags in self.system_node.findall(father_tag):
235 for child in tags.findall(child_tag):
236 if child.tag == 'cookie':
237 return child.attrib
238 elif child.tag == 'element':
239 return child.text
240 else:
241 return child.attrib['name']
242
243 def getFilters(self):
244 """Returns filters in list format.
245
246 :rtype filters:
247 filters[i], i:
248 0 for exclude,
249 1 for include,
250 2 for redundant.
251
252 """
253 exclude = []
254 include = []
255 redundant = []
256 for tags in self.system_node.findall('filters'):
257 for child in tags:
258 if child.tag == 'exclude':
259 for regexp in child:
260 exclude.append(regexp.text)
261 elif child.tag == 'include':
262 for regexp in child:
263 include.append(regexp.text)
264 else:
265 for regexp in child:
266 redundant.append(regexp.text)
267 filters = [('exclude', exclude), ('include', include), ('redundant', redundant)]
268 return filters
269
270
271
272
273
248 def getNote(self):
249
250 #Create string with scan information.
251 result = (
252 'Scan url:\n' +
253 self.url +
254 '\nUser Agent:\n' +
255 self.user_agent +
256 '\nVersion Arachni:\n' +
257 self.version +
258 '\nStart time:\n' +
259 self.start_time +
260 '\nFinish time:\n' +
261 self.finish_time +
262 '\nAudited Elements:\n' +
263 self.audited_elements +
264 '\nModules:\n' +
265 self.modules +
266 '\nCookies:\n' +
267 self.cookies
268 )
269
270 return result
271
274272
275273 class Plugins():
276 def __init__(self, plugin_node):
277 self.plugin_node = plugin_node
278 self.healthmap = self.getHealthmap(self.plugin_node)
279 self.content_types = self.getContentTypes(self.plugin_node)
280 pass
281
274
275 """
276 Support:
277 WAF (Web Application Firewall) Detector (waf_detector)
278 Healthmap (healthmap)
279 """
280
281 def __init__(self, plugins_node):
282
283 self.plugins_node = plugins_node
284
285 self.healthmap = self.getHealthmap()
286 self.waf = self.getWaf()
287
288 def getHealthmap(self):
289
290 #Get info about healthmap
291 healthmap_tree = self.plugins_node.find('healthmap')
292
293 #Create urls list.
294 list_urls = []
295 map_results = healthmap_tree.find('results').find('map')
296
297 for url in map_results:
298
299 if url.tag == 'with_issues':
300 list_urls.append('With Issues: ' + url.text)
301 else:
302 list_urls.append('Without Issues: ' + url.text)
303
304 try:
305
306 result = (
307 'Plugin Name: ' +
308 healthmap_tree.find('name').text +
309 '\nDescription: ' +
310 healthmap_tree.find('description').text +
311 '\nStatistics:' +
312 '\nTotal: ' +
313 healthmap_tree.find('results').find('total').text +
314 '\nWith Issues: ' +
315 healthmap_tree.find('results').find('with_issues').text +
316 '\nWithout Issues: ' +
317 healthmap_tree.find('results').find('without_issues').text +
318 '\nIssues percentage: ' +
319 healthmap_tree.find('results').find('issue_percentage').text +
320 '\nResults Map:\n' +
321 '\n'.join(list_urls)
322 )
323
324 return result
325
326 except:
327 return 'None'
328
329 def getWaf(self):
330
331 #Get info about waf plugin.
332 waf_tree = self.plugins_node.find('waf_detector')
333
334 try:
335
336 result = (
337 'Plugin Name: ' +
338 waf_tree.find('name').text +
339 '\nDescription: ' +
340 waf_tree.find('description').text +
341 '\nResults:' +
342 '\nMessage: ' +
343 waf_tree.find('results').find('message').text +
344 '\nStatus: ' +
345 waf_tree.find('results').find('status').text
346 )
347
348 return result
349
350 except:
351 return 'None'
352
353
282354 class ArachniPlugin(core.PluginBase):
283 """
284 Plugin that parses Arachni's XML report files.
285 """
355
356 #Plugin that parses Arachni's XML report files.
357
286358 def __init__(self):
359
287360 core.PluginBase.__init__(self)
288 self.id = "Arachni"
289 self.name = "Arachni XML Output Plugin"
290 self.plugin_version = "0.0.2"
291 self.version = "0.4.5.2"
292 self.framework_version = "1.0.0"
361 self.id = 'Arachni'
362 self.name = 'Arachni XML Output Plugin'
363 self.plugin_version = '1.0.1'
364 self.version = '1.3.2'
365 self.framework_version = '1.0.0'
293366 self.options = None
294 self._current_output = None
295 self.macaddress = None
367
368 self._command_regex = re.compile(
369 r'^(arachni_faraday |\.\/arachni_faraday).*?'
370 )
371
372 self.protocol = None
296373 self.hostname = None
374 self.port = '80'
375
297376 self.address = None
298 self.port = "80"
299
300
301 self._command_regex = re.compile(r'^(sudo arachni |arachni |\.\/arachni |ruby \.\/arachni |ruby arachni ).*?')
302
303 self._report_regex = re.compile(r"^.*(--report=xml\s*[^\s]+).*$")
304
305 global current_path
306 self._output_file_path = os.path.join(self.data_path, "arachni_report-%s.xml" % self._rid)
307
308 self._completition = {
309 "":"arachni [options] url",
310 "-h":"Help",
311 "--help":"Help",
312 "-v":"Be verbose.",
313 "--version":"Show version information and exit.",
314 "--debug":"Show what is happening internally. (You should give it a shot sometime ;) )",
315 "--only-positives":"Echo positive results *only*.",
316 "--http-username":"&lt;string&gt; Username for HTTP authentication.",
317 "--http-password":"&lt;string&gt; Password for HTTP authentication.",
318 "--http-req-limit":"--http-req-limit=&lt;integer&gt; Concurrent HTTP requests limit. (Default: 20) (Be careful not to kill your server.) (*NOTE*: If your scan seems unresponsive try lowering the limit.)",
319 "--http-timeout":"--http-timeout=&lt;integer&gt; HTTP request timeout in milliseconds.",
320 "--cookie-jar":"--cookie-jar=&lt;filepath&gt; Netscape HTTP cookie file, use curl to create it.",
321 "--cookie-string":"--cookie-string='&lt;name&gt;=&lt;value&gt;; &lt;name2&gt;=&lt;value2&gt;' Cookies, as a string, to be sent to the web application.",
322 "--user-agent":"--user-agent=&lt;string&gt; Specify user agent.",
323 "--custom-header":"--custom-header='&lt;name&gt;=&lt;value&gt;' Specify custom headers to be included in the HTTP requests. (Can be used multiple times.)",
324 "--authed-by":"--authed-by=&lt;string&gt; Who authorized the scan, include name and e-mail address. (It'll make it easier on the sys-admins during log reviews.) (Will be appended to the user-agent string.)",
325 "--login-check-url":"--login-check-url=&lt;url&gt; A URL used to verify that the scanner is still logged in to the web application. (Requires 'login-check-pattern'.)",
326 "--login-check-pattern":"--login-check-pattern=&lt;regexp&gt; A pattern used against the body of the 'login-check-url' to verify that the scanner is still logged in to the web application. (Requires 'login-check-url'.)",
327 "--save-profile":"--save-profile=&lt;filepath&gt; Save the current run profile/options to &lt;filepath&gt;.",
328 "--load-profile":"--load-profile=&lt;filepath&gt; Load a run profile from &lt;filepath&gt;. (Can be used multiple times.) (You can complement it with more options, except for:\n* --modules\n* --redundant)",
329 "--show-profile":"Will output the running profile as CLI arguments.",
330 "-e":"-e &lt;regexp&gt; Exclude urls matching &lt;regexp&gt;. (Can be used multiple times.)",
331 "--exclude":" --exclude=&lt;regexp&gt Exclude urls matching &lt;regexp&gt;.",
332 "--exclude-page":" --exclude-page=&lt;regexp&gt Exclude pages whose content matches &lt;regexp&gt;.",
333 "-i":"-i &lt;regexp&gt; Include *only* urls matching &lt;regex&gt;. (Can be used multiple times.)",
334 "--include":"&lt;regexp&gt; Include *only* urls matching &lt;regex&gt;.",
335 "--redundant":"--redundant=&lt;regexp&gt;:&lt;limit&gt; Limit crawl on redundant pages like galleries or catalogs. (URLs matching &lt;regexp&gt; will be crawled &lt;limit&gt; amount of times.) (Can be used multiple times.)",
336 "--auto-redundant":"--auto-redundant=&lt;limit&gt; Only follow &lt;limit&gt; amount of URLs with identical query parameter names. (Default: inf) (Will default to 10 if no value has been specified.)",
337 "-f":"Follow links to subdomains. (Default: off)",
338 "--depth":"--depth=&lt;integer&gt; Directory depth limit. (Default: inf) (How deep Arachni should go into the site structure.)",
339 "--follow-subdomains":"Follow links to subdomains.",
340 "--link-count":"--link-count=&lt;integer&gt; How many links to follow. (Default: inf)",
341 "--redirect-limit":"--redirect-limit=&lt;integer&gt; How many redirects to follow. (Default: 20)",
342 "--extend-paths":"--extend-paths=&lt;filepath&gt; Add the paths in &lt;file&gt; to the ones discovered by the crawler. (Can be used multiple times.)",
343 "--restrict-paths":"--restrict-paths=&lt;filepath&gt; Use the paths in &lt;file&gt; instead of crawling. (Can be used multiple times.)",
344 "--https-only":"Forces the system to only follow HTTPS URLs.",
345 "-g":"Audit links.",
346 "-p":"Audit forms.",
347 "-c":"Audit cookies.",
348 "--audit-cookies":"Audit cookies.",
349 "--exclude-cookie":"--exclude-cookie=&lt;name&gt; Cookie to exclude from the audit by name. (Can be used multiple times.)",
350 "--exclude-vector":"--exclude-vector=&lt;name&gt; Input vector (parameter) not to audit by name. (Can be used multiple times.)",
351 "--audit-headers":"Audit HTTP headers. (*NOTE*: Header audits use brute force. Almost all valid HTTP request headers will be audited even if there's no indication that the web app uses them.) (*WARNING*: Enabling this option will result in increased requests, maybe by an order of magnitude.)",
352 "--audit-cookies-extensively":"Submit all links and forms of the page along with the cookie permutations. (*WARNING*: This will severely increase the scan-time.)",
353 "--fuzz-methods":"Audit links, forms and cookies using both GET and POST requests. (*WARNING*: This will severely increase the scan-time.)",
354 "--exclude-binaries":"Exclude non text-based pages from the audit. (Binary content can confuse recon modules that perform pattern matching.)",
355 "--lsmod":"--lsmod=&lt;regexp&gt; List available modules based on the provided regular expression. (If no regexp is provided all modules will be listed.) (Can be used multiple times.)",
356 "-m":"-m &lt;modname,modname..&gt; Comma separated list of modules to load. (Modules are referenced by their filename without the '.rb' extension, use '--lsmod' to list all.\nUse '*' as a module name to deploy all modules or as a wildcard, like so:\nxss* to load all xss modules\nsqli* to load all sql injection modules etc.\nYou can exclude modules by prefixing their name with a minus sign:\n--modules=*,-backup_files,-xss\nThe above will load all modules except for the 'backup_files' and 'xss' modules.\nOr mix and match:\n-xss* to unload all xss modules.)",
357 "--lsrep":"--lsrep=&lt;regexp&gt; List available reports based on the provided regular expression. (If no regexp is provided all reports will be listed.) (Can be used multiple times.)",
358 "--repload":"--repload=&lt;filepath&gt; Load audit results from an '.afr' report file. (Allows you to create new reports from finished scans.)",
359 "--report":"--report='&lt;report&gt;:&lt;optname&gt;=&lt;val&gt;,&lt;optname2&gt;=&lt;val2&gt;,...'\n&lt;report&gt;: the name of the report as displayed by '--lsrep'\n(Reports are referenced by their filename without the '.rb' extension, use '--lsrep' to list all.)\n(Default: stdout) (Can be used multiple times.)",
360 "--lsplug":"--lsplug=&lt;regexp&gt; List available plugins based on the provided regular expression.",
361 "--plugin":"--plugin='&lt;plugin&gt;:&lt;optname&gt;=&lt;val&gt;,&lt;optname2&gt;=&lt;val2&gt;,...",
362 '--lsplat':"List available platforms.",
363 "--no-fingerprinting":"Disable platform fingerprinting.",
364 "--proxy":"--proxy=&lt;server:port&gt; Proxy address to use.",
365 "--proxy-auth":"--proxy-auth=&lt;user:passwd&gt; Proxy authentication credentials.",
366 "--proxy-type":"--proxy-type=&lt;type&gt; Proxy type; can be http, http_1_0, socks4, socks5, socks4a (Default: http)",
367 }
368377
369378 def parseOutputString(self, output, debug = False):
370379 """
371 This method will discard the output the shell sends, it will read it from
372 the xml where it expects it to be present.
373
374 NOTE: if 'debug' is true then it is being run from a test case and the
375 output being sent is valid.
380 This method will discard the output the shell sends, it will read it
381 from the xml where it expects it to be present.
376382 """
383
377384 parser = ArachniXmlParser(output)
378 for system in parser.system:
379 self.hostname = self.getHostname(system.url)
380 self.address = self.getAddress(self.hostname)
381
382 h_id = self.createAndAddHost(self.address)
383
384
385 i_id = self.createAndAddInterface(h_id, self.address, ipv4_address=self.address,hostname_resolution=self.hostname )
386
387 s_id = self.createAndAddServiceToInterface(h_id, i_id,
388 self.protocol,
389 "tcp",
390 ports=[self.port],
391 status="open",
392 version="",
393 description="")
394
395 n_id = self.createAndAddNoteToService(h_id,s_id,"website","")
396 n2_id = self.createAndAddNoteToNote(h_id,s_id,n_id,self.hostname,"")
397
398
399 for issue in parser.issues:
400
401 desc=issue.description
402 desc+="\nSolution: " + issue.remedy_guidance if issue.remedy_guidance !="None" else ""
403 ref=[issue.references] if issue.references else []
404 if issue.cwe != "None":
405 ref.append('CWE-'+issue.cwe)
406 v_id = self.createAndAddVulnWebToService(h_id, s_id,
407 website=self.hostname,
408 name=issue.name,
409 desc=desc,
410 ref=ref,
411 pname=issue.var,
412 severity=issue.severity,
413 method=issue.method,
414 path=issue.url)
415
416
417
418
419 return True
420
385
386 #Check xml parsed ok...
387 if not parser.system:
388 print 'Error in xml report... Exiting...'
389 return
390
391 self.hostname = self.getHostname(parser.system.url)
392 self.address = self.getAddress(self.hostname)
393
394 #Create host and interface
395 host_id = self.createAndAddHost(self.address)
396
397 interface_id = self.createAndAddInterface(
398 host_id,
399 self.address,
400 ipv4_address = self.address,
401 hostname_resolution = self.hostname
402 )
403
404 #Create service
405 service_id = self.createAndAddServiceToInterface(
406 host_id,
407 interface_id,
408 self.protocol,
409 'tcp',
410 ports = [self.port],
411 status = 'Open',
412 version = '',
413 description = ''
414 )
415
416 #Scan Note.
417 noteScan_id = self.createAndAddNoteToService(
418 host_id,
419 service_id,
420 'Scan Information',
421 parser.system.note
422 )
423
424 #Plugins Notes
425 note_id = self.createAndAddNoteToService(
426 host_id,
427 service_id,
428 'Plugins arachni',
429 'Plugins used by arachni and results of this.'
430 )
431
432 if parser.plugins.waf != 'None':
433
434 note2_id = self.createAndAddNoteToNote(
435 host_id,
436 service_id,
437 note_id,
438 'Waf Plugin',
439 parser.plugins.waf
440 )
441
442 if parser.plugins.healthmap != 'None':
443
444 note3_id = self.createAndAddNoteToNote(
445 host_id,
446 service_id,
447 note_id,
448 'Healthmap Plugin',
449 parser.plugins.healthmap
450 )
451
452 #Create issues.
453 for issue in parser.issues:
454
455 description = (
456 'Description:\n' +
457 issue.description +
458 '\n\nSolution:\n' +
459 issue.remedy_guidance
460 )
461
462 references = issue.references
463 if issue.cwe != 'None':
464 references.append('CWE-' + issue.cwe)
465
466 issue_id = self.createAndAddVulnWebToService(
467 host_id,
468 service_id,
469 name = issue.name,
470 desc = description,
471 ref = references,
472 severity = issue.severity,
473 website = self.hostname,
474 path = issue.url,
475 method = issue.method,
476 pname = issue.var,
477 params = issue.parameters,
478 request = issue.request,
479 response = issue.response
480 )
481
482 return
483
421484 def processCommandString(self, username, current_path, command_string):
422 """
423 Adds the "--report=xml:outfile=" parameter to set an xml output for
424 the command string that the user has set.
425 If the user has already set a xml report his report will be replaced with faraday's one.
426 """
427
428 arg_match = self._report_regex.match(command_string)
429
430 if arg_match is None:
431 return re.sub(r"(^.*?arachni)", r"\1 --report=xml:outfile=%s" % self._output_file_path, command_string)
432 else:
433 return re.sub(arg_match.group(1),r"--report=xml:outfile=%s" % self._output_file_path, command_string)
434
485
486 return
487
435488 def getHostname(self, url):
436 """
437 Strips protocol and gets hostname from URL.
438 """
439 reg = re.search("(http|https|ftp)\://([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&amp;%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))[\:]*([0-9]+)*([/]*($|[a-zA-Z0-9\.\,\?\'\\\+&amp;%\$#\=~_\-]+)).*?$", url)
489
490 #Strips protocol and gets hostname from URL.
491 reg = re.search(
492 '(http|https|ftp)\://([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&amp;%\$\-]+)*@)*('
493 '(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5'
494 ']|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0'
495 '-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0'
496 '-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+'
497 '\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pr'
498 'o|aero|coop|museum|[a-zA-Z]{2}))[\:]*([0-9]+)*([/]*($|[a-zA-Z0-9\.\,\?'
499 '\'\\\+&amp;%\$#\=~_\-]+)).*?$',
500 url
501 )
502
440503 self.protocol = reg.group(1)
441504 self.hostname = reg.group(4)
442505
443506 if self.protocol == 'https':
444 self.port=443
507 self.port = 443
445508 if reg.group(11) is not None:
446509 self.port = reg.group(11)
447
510
448511 return self.hostname
449512
450
451513 def getAddress(self, hostname):
452 """
453 Returns remote IP address from hostname.
454 """
514
515 #Returns remote IP address from hostname.
455516 try:
456517 return socket.gethostbyname(hostname)
457518 except socket.error, msg:
458
459519 return self.hostname
460520
461521
0 #!/usr/bin/env python
1 # -*- coding: utf-8 -*-
2
3 '''
4 Faraday Penetration Test IDE
5 Copyright (C) 2013 Infobyte LLC (http://www.infobytesec.com/)
6 See the file 'doc/LICENSE' for the license information
7
8 '''
9 from __future__ import with_statement
10 from plugins import core
11 from model import api
12 import re
13 import os
14 import pprint
15 import sys
16
17 try:
18 import xml.etree.cElementTree as ET
19 import xml.etree.ElementTree as ET_ORIG
20 ETREE_VERSION = ET_ORIG.VERSION
21 except ImportError:
22 import xml.etree.ElementTree as ET
23 ETREE_VERSION = ET.VERSION
24
25 ETREE_VERSION = [int(i) for i in ETREE_VERSION.split(".")]
26
27 current_path = os.path.abspath(os.getcwd())
28
29 __author__ = "Francisco Amato"
30 __copyright__ = "Copyright (c) 2013, Infobyte LLC"
31 __credits__ = ["Francisco Amato"]
32 __license__ = ""
33 __version__ = "1.0.0"
34 __maintainer__ = "Francisco Amato"
35 __email__ = "[email protected]"
36 __status__ = "Development"
37
38
39
40
41
42 class MaltegoXmlParser(object):
43 """
44 The objective of this class is to parse an xml file generated by the maltego tool.
45
46 TODO: Handle errors.
47 TODO: Test maltego output version. Handle what happens if the parser doesn't support it.
48 TODO: Test cases.
49
50 @param maltego_xml_filepath A proper xml generated by maltego
51 """
52 def __init__(self, xml_output):
53 self.target = None
54 self.port = "80"
55 self.host = None
56
57 tree = self.parse_xml(xml_output)
58
59 if tree:
60 self.items = [data for data in self.get_items(tree)]
61 else:
62 self.items = []
63
64 def parse_xml(self, xml_output):
65 """
66 Open and parse an xml file.
67
68 TODO: Write custom parser to just read the nodes that we need instead of
69 reading the whole file.
70
71 @return xml_tree An xml tree instance. None if error.
72 """
73 try:
74 tree = ET.fromstring(xml_output)
75 except SyntaxError, err:
76 print "SyntaxError: %s. %s" % (err, xml_output)
77 return None
78
79 return tree
80
81 def get_items(self, tree):
82 """
83 @return items A list of Host instances
84 """
85
86
87 node = tree.findall('graph')[0]
88
89 for n in node.findall('node'):
90 yield Item(n)
91
92
93
94
95 def get_attrib_from_subnode(xml_node, subnode_xpath_expr, attrib_name):
96 """
97 Finds a subnode in the item node and the retrieves a value from it
98
99 @return An attribute value
100 """
101 global ETREE_VERSION
102 node = None
103
104 if ETREE_VERSION[0] <= 1 and ETREE_VERSION[1] < 3:
105
106 match_obj = re.search("([^\@]+?)\[\@([^=]*?)=\'([^\']*?)\'",subnode_xpath_expr)
107 if match_obj is not None:
108 node_to_find = match_obj.group(1)
109 xpath_attrib = match_obj.group(2)
110 xpath_value = match_obj.group(3)
111 for node_found in xml_node.findall(node_to_find):
112 if node_found.attrib[xpath_attrib] == xpath_value:
113 node = node_found
114 break
115 else:
116 node = xml_node.find(subnode_xpath_expr)
117
118 else:
119 node = xml_node.find(subnode_xpath_expr)
120
121 if node is not None:
122 return node.get(attrib_name)
123
124 return None
125
126
127
128
129
130 class Item(object):
131 """
132 An abstract representation of a Item
133
134
135 @param item_node A item_node taken from an maltego xml tree
136 """
137 def __init__(self, item_node):
138 self.node = item_node
139 self.items =None
140
141 self.id = self.get('id')
142 node2 = self.node.findall('data')[0]
143 node3 = node2.findall('mtg:MaltegoEntity')[0]
144 self.node = node3
145 self.type = self.get('type')
146 node4 = node3.findall('mtg:Properties')[0]
147 for n in node4.findall('mtg:Property'):
148 self.node = n
149 dname = self.get('displayName')
150 value = self.get_text_from_subnode('mtg:Value')
151 item = {'dname': dname, 'value' : value}
152 self.items.append(item)
153
154
155 def do_clean(self,value):
156 myreturn =""
157 if value is not None:
158 myreturn = re.sub("\n","",value)
159 return myreturn
160
161 def get_text_from_subnode(self, subnode_xpath_expr):
162 """
163 Finds a subnode in the host node and the retrieves a value from it.
164
165 @return An attribute value
166 """
167 sub_node = self.node.find(subnode_xpath_expr)
168 if sub_node is not None:
169 return sub_node.text
170
171 return None
172
173
174
175 class MaltegoPlugin(core.PluginBase):
176 """
177 Example plugin to parse maltego output.
178 """
179 def __init__(self):
180 core.PluginBase.__init__(self)
181 self.id = "Maltego"
182 self.name = "Maltego XML Output Plugin"
183 self.plugin_version = "0.0.1"
184 self.version = "3.0.4"
185 self.framework_version = "1.0.0"
186 self.options = None
187 self._current_output = None
188 self.target = None
189 self._command_regex = re.compile(r'^(sudo maltego|maltego|\.\/maltego).*?')
190
191 global current_path
192 self._output_file_path = os.path.join(self.data_path,
193 "maltego_output-%s.xml" % self._rid)
194
195
196 def parseOutputString(self, output, debug = False):
197 """
198 This method will discard the output the shell sends, it will read it from
199 the xml where it expects it to be present.
200
201 NOTE: if 'debug' is true then it is being run from a test case and the
202 output being sent is valid.
203 """
204 parser = MaltegoXmlParser(output)
205
206 for item in parser.items:
207 if item.id is not None:
208 h_id = self.createAndAddHost(item.id, "unknown")
209 i_id = self.createAndAddInterface(h_id, item.id,"00:00:00:00:00:00", item.id)
210 for i in item.items:
211 s_id = self.createAndAddServiceToInterface(h_id, i_id,
212 i['dname'],
213 "tcp",
214 ports = [0],
215 status = "status",
216 version = "version",
217 description = i['value'])
218
219 del parser
220
221 def processCommandString(self, username, current_path, command_string):
222 return None
223
224 def setHost(self):
225 pass
226
227
228 def createPlugin():
229 return MaltegoPlugin()
230
231 if __name__ == '__main__':
232 parser = MaltegoXmlParser(sys.argv[1])
233 for item in parser.items:
234 if item.status == 'up':
235 print item
0 #!/usr/bin/env python
1 # -*- coding: utf-8 -*-
2
3 """
4 Faraday Penetration Test IDE
5 Copyright (C) 2015 Infobyte LLC (http://www.infobytesec.com/)
6 See the file 'doc/LICENSE' for the license information
7 """
8
9 from __future__ import with_statement
10 from plugins import core
11 from model import api
12
13 import zipfile
14 import sys
15 import re
16 import os
17
18 try:
19 import xml.etree.cElementTree as ET
20 import xml.etree.ElementTree as ET_ORIG
21 ETREE_VERSION = ET_ORIG.VERSION
22 except ImportError:
23 import xml.etree.ElementTree as ET
24 ETREE_VERSION = ET.VERSION
25
26 ETREE_VERSION = [int(i) for i in ETREE_VERSION.split(".")]
27
28 current_path = os.path.abspath(os.getcwd())
29
30 __author__ = "Ezequiel Tavella"
31 __copyright__ = "Copyright (c) 2015, Infobyte LLC"
32 __credits__ = ["Ezequiel Tavella"]
33 __license__ = ""
34 __version__ = "1.0.1"
35 __maintainer__ = "Ezequiel Tavella"
36 __status__ = "Development"
37
38 def openMtgx(mtgx_file):
39
40 try:
41 file = zipfile.ZipFile(mtgx_file, "r")
42 xml = ET.parse(file.open('Graphs/Graph1.graphml'))
43
44 except:
45 print "Bad report format"
46 sys.exit()
47
48 file.close()
49 return xml
50
51 class Host():
52
53 def __init__(self):
54 self.ip = ""
55 self.node_id = ""
56 self.dns_name = ""
57 self.website = ""
58 self.netblock = ""
59 self.location = ""
60 self.mx_record = ""
61 self.ns_record = ""
62
63 class MaltegoMtgxParser():
64
65 def __init__(self, xml_file):
66
67 self.xml = openMtgx(xml_file)
68
69 self.nodes = self.xml.findall(
70 "{http://graphml.graphdrawing.org/xmlns}graph/"
71 "{http://graphml.graphdrawing.org/xmlns}node"
72 )
73
74 self.edges = self.xml.findall(
75 "{http://graphml.graphdrawing.org/xmlns}graph/"
76 "{http://graphml.graphdrawing.org/xmlns}edge"
77 )
78
79 self.list_hosts = []
80 self.relations = {}
81
82 def getRelations(self):
83
84 """
85 Get relations between nodes.
86 Two ways: Source-> Target
87 Source <- Target
88 """
89 for edge in self.edges:
90
91 source = edge.get("source")
92 target = edge.get("target")
93
94 if source not in self.relations:
95 self.relations.update({source : [target]})
96
97 if target not in self.relations:
98 self.relations.update({target : [source]})
99
100 values = self.relations[source]
101 values.append(target)
102 self.relations.update({source : values})
103
104 values = self.relations[target]
105 values.append(source)
106 self.relations.update({target : values})
107
108 def getIpAndId(self, node):
109
110 #Find node ID and maltego entity
111 node_id = node.get("id")
112 entity = node.find(
113 "{http://graphml.graphdrawing.org/xmlns}data/"
114 "{http://maltego.paterva.com/xml/mtgx}MaltegoEntity"
115 )
116
117 #Check if is IPv4Address
118 if entity.get("type") != "maltego.IPv4Address":
119 return None
120
121 #Get IP value
122 value = entity.find(
123 "{http://maltego.paterva.com/xml/mtgx}Properties/"
124 "{http://maltego.paterva.com/xml/mtgx}Property/"
125 "{http://maltego.paterva.com/xml/mtgx}Value"
126 )
127
128 return {"node_id" : node_id ,"ip" : value.text}
129
130 def getNode(self, node_id):
131
132 #Get node, filter by id
133 for node in self.nodes:
134
135 if node.get("id") == node_id:
136 return node
137
138 def getType(self, node):
139
140 #Get type of this node
141 entity = node.find(
142 "{http://graphml.graphdrawing.org/xmlns}data/"
143 "{http://maltego.paterva.com/xml/mtgx}MaltegoEntity"
144 )
145
146 return entity.get("type")
147
148 def getWebsite(self, target_node):
149
150 #Parse Website Entity
151 result = {"name" : "", "ssl_enabled": "" , "urls": ""}
152
153 props = target_node.find(
154 "{http://graphml.graphdrawing.org/xmlns}data/"
155 "{http://maltego.paterva.com/xml/mtgx}MaltegoEntity/"
156 "{http://maltego.paterva.com/xml/mtgx}Properties"
157 )
158
159 for prop in props:
160
161 name_property = prop.get("name")
162 value = prop.find("{http://maltego.paterva.com/xml/mtgx}Value").text
163
164 if name_property == "fqdn":
165 result["name"] = value
166 elif name_property == "website.ssl-enabled":
167 result["ssl_enabled"] = value
168 elif name_property == "URLS":
169 result["urls"] = value
170
171 return result
172
173 def getNetBlock(self, target_node):
174
175 #Parse Netblock Entity
176 result = {"ipv4_range" : "", "network_owner": "" , "country": ""}
177
178 props = target_node.find(
179 "{http://graphml.graphdrawing.org/xmlns}data/"
180 "{http://maltego.paterva.com/xml/mtgx}MaltegoEntity/"
181 "{http://maltego.paterva.com/xml/mtgx}Properties"
182 )
183
184 for prop in props:
185
186 name_property = prop.get("name")
187 value = prop.find("{http://maltego.paterva.com/xml/mtgx}Value").text
188
189 if name_property == "ipv4-range":
190 result["ipv4_range"] = value
191 elif name_property == "description":
192 result["network_owner"] = value
193 elif name_property == "country":
194 result["country"] = value
195
196 return result
197
198 def getLocation(self, target_node):
199
200 #Parse Location Entity
201 result = {"name" : "", "area": "" , "country_code": "",
202 "longitude" : "", "latitude" : "", "area_2" : ""
203 }
204
205 #Get relations with other nodes
206 node_relations = self.relations[target_node.get("id")]
207
208 #Find location node based in relation with netblock node.
209 located = False
210 for node_id in node_relations:
211
212 target_node = self.getNode(node_id)
213 if self.getType(target_node) == "maltego.Location":
214 located = True
215 break
216
217 if not located:
218 return None
219
220 #Get properties and update data
221 props = target_node.find(
222 "{http://graphml.graphdrawing.org/xmlns}data/"
223 "{http://maltego.paterva.com/xml/mtgx}MaltegoEntity/"
224 "{http://maltego.paterva.com/xml/mtgx}Properties"
225 )
226
227 for prop in props:
228
229 name_property = prop.get("name")
230 value = prop.find("{http://maltego.paterva.com/xml/mtgx}Value").text
231
232 if name_property == "location.name":
233 result["name"] = value
234 elif name_property == "location.area":
235 result["area"] = value
236 elif name_property == "countrycode":
237 result["country_code"] = value
238 elif name_property == "longitude":
239 result["longitude"] = value
240 elif name_property == "latitude":
241 result["latitude"] = value
242 elif name_property == "area":
243 result["area_2"] = value
244
245 return result
246
247 def getValue(self, target_node):
248
249 #Parse Entity
250 result = {"value" : ""}
251
252 value = target_node.find(
253 "{http://graphml.graphdrawing.org/xmlns}data/"
254 "{http://maltego.paterva.com/xml/mtgx}MaltegoEntity/"
255 "{http://maltego.paterva.com/xml/mtgx}Properties/"
256 "{http://maltego.paterva.com/xml/mtgx}Property/"
257 "{http://maltego.paterva.com/xml/mtgx}Value"
258 )
259
260 result["value"] = value.text
261 return result
262
263 def parse(self):
264
265 self.getRelations()
266
267 for node in self.nodes:
268
269 #Get IP Address if not continue with other node...
270 result = self.getIpAndId(node)
271 if not result:
272 continue
273
274 #Create host with values by default
275 host = Host()
276 host.ip = result["ip"]
277 host.node_id = result["node_id"]
278
279 #Get relations with other nodes
280 node_relations = self.relations[host.node_id]
281
282 for node_id in node_relations:
283
284 #Get target node and type of node.
285 target_node = self.getNode(node_id)
286 target_type = self.getType(target_node)
287
288 #Check type of node y add data to host...
289 if target_type == "maltego.DNSName":
290 host.dns_name = self.getValue(target_node)
291 elif target_type == "maltego.Website":
292 host.website = self.getWebsite(target_node)
293 elif target_type == "maltego.Netblock":
294 host.netblock = self.getNetBlock(target_node)
295 #Get location based in relation: netblock -> location
296 host.location = self.getLocation(target_node)
297 elif target_type == "maltego.MXRecord":
298 host.mx_record = self.getValue(target_node)
299 elif target_type == "maltego.NSRecord":
300 host.ns_record = self.getValue(target_node)
301
302 self.list_hosts.append(host)
303
304 return self.list_hosts
305
306 class MaltegoPlugin(core.PluginBase):
307
308 def __init__(self):
309
310 core.PluginBase.__init__(self)
311 self.id = "Maltego"
312 self.name = "Maltego MTGX Output Plugin"
313 self.plugin_version = "1.0.1"
314 self.version = "Maltego 3.6"
315 self.framework_version = "1.0.0"
316 self.current_path = None
317 self.options = None
318 self._current_output = None
319
320 self._command_regex = re.compile(r'^(sudo maltego_faraday|maltego_faraday|\.\/maltego_faraday).*?')
321
322 self.report = None
323 global current_path
324
325 def parseOutputString(self, output, debug = False):
326
327 maltego_parser = MaltegoMtgxParser(self.report)
328 for host in maltego_parser.parse():
329
330 #Create host
331 try:
332 old_hostname = host.dns_name["value"]
333 except:
334 old_hostname = "unknown"
335
336 host_id = self.createAndAddHost(
337 name = host.ip,
338 old_hostname = old_hostname
339 )
340
341 #Create interface
342 try:
343 network_segment = host.netblock["ipv4_range"]
344 hostname_resolution = [host.dns_name["value"]]
345 except:
346 network_segment = "unknown"
347 hostname_resolution = "unknown"
348
349 interface_id = self.createAndAddInterface(
350 host_id = host_id,
351 name = host.ip,
352 ipv4_address = host.ip,
353 network_segment = network_segment ,
354 hostname_resolution = hostname_resolution
355 )
356
357 #Create note with NetBlock information
358 if host.netblock:
359
360 try:
361
362 text = (
363 "Network owner:\n" +
364 host.netblock["network_owner"] or "unknown" +
365 "Country:\n" + host.netblock["country"] or "unknown"
366 )
367 except:
368 text = "unknown"
369
370 self.createAndAddNoteToHost(
371 host_id = host_id,
372 name = "Netblock Information",
373 text = text.encode('ascii', 'ignore')
374 )
375
376 #Create note with host location
377 if host.location:
378
379 try:
380 text = (
381 "Location:\n" +
382 host.location["name"] +
383 "\nArea:\n" +
384 host.location["area"] +
385 "\nArea 2:\n" +
386 host.location["area_2"] +
387 "\nCountry_code:\n" +
388 host.location["country_code"] +
389 "\nLatitude:\n" +
390 host.location["latitude"] +
391 "\nLongitude:\n" +
392 host.location["longitude"]
393 )
394 except:
395 text = "unknown"
396
397 self.createAndAddNoteToHost(
398 host_id = host_id,
399 name = "Location Information",
400 text = text.encode('ascii', 'ignore')
401 )
402
403 #Create service web server
404 if host.website:
405
406 try:
407 description = "SSL Enabled: " + host.website["ssl_enabled"]
408 except:
409 description = "unknown"
410
411 service_id = self.createAndAddServiceToInterface(
412 host_id = host_id,
413 interface_id = interface_id,
414 name = host.website["name"],
415 protocol = "TCP:HTTP",
416 ports = [80],
417 description = description
418 )
419
420 try:
421
422 text =(
423 "Urls:\n" + host.website["urls"]
424 )
425
426 self.createAndAddNoteToService(
427 host_id = host_id,
428 service_id = service_id,
429 name = "URLs",
430 text = text.encode('ascii', 'ignore')
431 )
432
433 except:
434 pass
435
436 if host.mx_record:
437
438 self.createAndAddServiceToInterface(
439 host_id = host_id,
440 interface_id = interface_id,
441 name = host.mx_record["value"],
442 protocol = "SMTP",
443 ports = [25],
444 description = "E-mail Server",
445 )
446
447 if host.ns_record:
448
449 self.createAndAddServiceToInterface(
450 host_id = host_id,
451 interface_id = interface_id,
452 name = host.ns_record["value"],
453 protocol = "DNS",
454 ports = [53],
455 description = "DNS Server",
456 )
457
458 def processCommandString(self, username, current_path, command_string):
459
460 report = command_string.split("maltego_faraday ")[1]
461 self.report = os.path.join(current_path, report)
462
463 def createPlugin():
464 return MaltegoPlugin()
1111 hostsManagerMock,
1212 $workspacesFact,
1313 workspacesFactMock,
14 getCurrentSelection,
1415 vuln1, vuln2, vuln3;
1516
1617 var returnPromise;
2122 //Store the callbacks for later when the user clicks on the OK or Cancel button of the dialog
2223 this.confirmCallBack = confirmCallback;
2324 this.cancelCallback = cancelCallback;
25 return this;
2426 }
2527 },
2628 close: function(item) {
127129 "response": "",
128130 "website": "test.test.com"
129131 };
130
131132
132133 returnPromise = function(res) {
133134 var deferred = _$q_.defer();
199200 hostsManager: hostsManagerMock,
200201 workspacesFact: workspacesFactMock,
201202 $routeParams: {wsId: 'ws1'},
202 $modal: _$modal_
203 $uibModal: _$modal_,
203204 });
204205 });
205206 });
208209 describe('Status report init function without filter', function() {
209210 it('vulns loaded after execution', function() {
210211 $scope.$apply();
211 expect($scope.vulns.length).toEqual(3);
212 expect($scope.vulns).toContain(vuln1);
213 expect($scope.vulns).toContain(vuln2);
214 expect($scope.vulns).toContain(vuln3);
212 expect($scope.gridOptions.data.length).toEqual(3);
213 expect($scope.gridOptions.data).toContain(vuln1);
214 expect($scope.gridOptions.data).toContain(vuln2);
215 expect($scope.gridOptions.data).toContain(vuln3);
215216 });
216217 });
217218
220221 $scope.remove([vuln1]);
221222 $scope.$apply();
222223
223 expect($scope.vulns.length).toEqual(2);
224 expect($scope.vulns).not.toContain(vuln1);
225 expect($scope.vulns).toContain(vuln2);
226 expect($scope.vulns).toContain(vuln3);
224 expect($scope.gridOptions.data.length).toEqual(2);
225 expect($scope.gridOptions.data).not.toContain(vuln1);
226 expect($scope.gridOptions.data).toContain(vuln2);
227 expect($scope.gridOptions.data).toContain(vuln3);
227228 });
228229 it('remove invalid vuln id 9.9.9.9', function() {
229230 vuln = {"_id": "9.9.9.9"}
230231 $scope.remove([vuln]);
231232 $scope.$apply();
232233
233 expect($scope.vulns.length).toEqual(3);
234 expect($scope.vulns).toContain(vuln1);
235 expect($scope.vulns).toContain(vuln2);
236 expect($scope.vulns).toContain(vuln3);
234 expect($scope.gridOptions.data.length).toEqual(3);
235 expect($scope.gridOptions.data).toContain(vuln1);
236 expect($scope.gridOptions.data).toContain(vuln2);
237 expect($scope.gridOptions.data).toContain(vuln3);
237238 });
238239 it('remove valid id 1.2.3.4 and invalid id 9.9.9.9', function() {
239240 vuln = {"_id": "9.9.9.9"}
240241 $scope.remove([vuln1, vuln]);
241242 $scope.$apply();
242243
243 expect($scope.vulns.length).toEqual(2);
244 expect($scope.vulns).not.toContain(vuln1);
245 expect($scope.vulns).toContain(vuln2);
246 expect($scope.vulns).toContain(vuln3);
244 expect($scope.gridOptions.data.length).toEqual(2);
245 expect($scope.gridOptions.data).not.toContain(vuln1);
246 expect($scope.gridOptions.data).toContain(vuln2);
247 expect($scope.gridOptions.data).toContain(vuln3);
247248 });
248249 it('remove valid vulns ids', function() {
249250 $scope.remove([vuln1, vuln2]);
250251 $scope.$apply();
251252
252 expect($scope.vulns.length).toEqual(1);
253 expect($scope.vulns).not.toContain(vuln1);
254 expect($scope.vulns).not.toContain(vuln2);
255 expect($scope.vulns).toContain(vuln3);
253 expect($scope.gridOptions.data.length).toEqual(1);
254 expect($scope.gridOptions.data).not.toContain(vuln1);
255 expect($scope.gridOptions.data).not.toContain(vuln2);
256 expect($scope.gridOptions.data).toContain(vuln3);
256257 });
257258 });
258259
259260 describe('Status report vuln deletion - delete method (modal)', function() {
260 it('call delete with no vulns selected', function() {
261 // we need $scope.vulns to have all the vulns before calling
261 it('call delete by property with no vulns selected', function() {
262 // we need $scope.gridOptions.data to have all the vulns before calling
262263 // the delete method
263264 $scope.$apply();
264 $scope.delete();
265 $scope.$apply();
266
267 expect($scope.vulns.length).toEqual(3);
268 expect($scope.vulns).toContain(vuln1);
269 expect($scope.vulns).toContain(vuln2);
270 expect($scope.vulns).toContain(vuln3);
265 $scope.deleteVuln(vuln1);
266 fakeModal.close();
267 $scope.$apply();
268
269 expect($scope.gridOptions.data.length).toEqual(3);
270 expect($scope.gridOptions.data).toContain(vuln1);
271 expect($scope.gridOptions.data).toContain(vuln2);
272 expect($scope.gridOptions.data).toContain(vuln3);
271273 });
272274 it('call delete with a valid vuln (1.2.3.4) selected and accept modal', function() {
273 // we need $scope.vulns to have all the vulns before calling
275 // we need $scope.gridOptions.data to have all the vulns before calling
274276 // the delete method
275277 vuln1.selected_statusreport_controller = true;
276278 $scope.$apply();
277 $scope.delete();
279 $scope.deleteVuln();
278280 fakeModal.close();
279281 $scope.$apply();
280282
281 expect($scope.vulns.length).toEqual(2);
282 expect($scope.vulns).not.toContain(vuln1);
283 expect($scope.vulns).toContain(vuln2);
284 expect($scope.vulns).toContain(vuln3);
283 expect($scope.gridOptions.data.length).toEqual(2);
284 expect($scope.gridOptions.data).not.toContain(vuln1);
285 expect($scope.gridOptions.data).toContain(vuln2);
286 expect($scope.gridOptions.data).toContain(vuln3);
285287 });
286288 it('call delete with a valid vuln (1.2.3.4) selected and cancel modal', function() {
287 // we need $scope.vulns to have all the vulns before calling
289 // we need $scope.gridOptions.data to have all the vulns before calling
288290 // the delete method
289291 vuln1.selected_statusreport_controller = true;
290292 $scope.$apply();
292294 fakeModal.dismiss();
293295 $scope.$apply();
294296
295 expect($scope.vulns.length).toEqual(3);
296 expect($scope.vulns).toContain(vuln1);
297 expect($scope.vulns).toContain(vuln2);
298 expect($scope.vulns).toContain(vuln3);
297 expect($scope.gridOptions.data.length).toEqual(3);
298 expect($scope.gridOptions.data).toContain(vuln1);
299 expect($scope.gridOptions.data).toContain(vuln2);
300 expect($scope.gridOptions.data).toContain(vuln3);
299301 });
300302 it('call delete with valid vulns selected and accept modal', function() {
301303 vuln1.selected_statusreport_controller = true;
305307 fakeModal.close();
306308 $scope.$apply();
307309
308 expect($scope.vulns.length).toEqual(1);
309 expect($scope.vulns).not.toContain(vuln1);
310 expect($scope.vulns).not.toContain(vuln2);
311 expect($scope.vulns).toContain(vuln3);
310 expect($scope.gridOptions.data.length).toEqual(1);
311 expect($scope.gridOptions.data).not.toContain(vuln1);
312 expect($scope.gridOptions.data).not.toContain(vuln2);
313 expect($scope.gridOptions.data).toContain(vuln3);
312314 });
313315 });
314316
341343 $scope.insert(vulnNew);
342344 $scope.$apply();
343345
344 expect($scope.vulns.length).toEqual(4);
345 expect($scope.vulns).toContain(vulnNew);
346 expect($scope.gridOptions.data.length).toEqual(4);
347 expect($scope.gridOptions.data).toContain(vulnNew);
346348 });
347349 it('create a duplicated vuln', function() {
348350 var vulnNew = {
376378 $scope.insert(vulnNew);
377379 $scope.$apply();
378380
379 expect($scope.vulns.length).toEqual(3);
380 expect($scope.vulns).not.toContain(vulnNew);
381 });
382 });
383
381 expect($scope.gridOptions.data.length).toEqual(3);
382 expect($scope.gridOptions.data).not.toContain(vulnNew);
383 });
384 });
385
384386 describe('Status report vuln creation - new method (modal)', function() {
385387 it('create a valid vuln and accept modal', function() {
386388 var vulnNew = {
411413 fakeModal.close(vulnNew);
412414 $scope.$apply();
413415
414 expect($scope.vulns.length).toEqual(4);
415 expect($scope.vulns).toContain(vulnNew);
416 expect($scope.gridOptions.data.length).toEqual(4);
417 expect($scope.gridOptions.data).toContain(vulnNew);
416418 });
417419 it('create a valid vuln but cancel modal', function() {
418420 var vulnNew = {
444446 fakeModal.dismiss();
445447 $scope.$apply();
446448
447 expect($scope.vulns.length).toEqual(3);
448 expect($scope.vulns).not.toContain(vulnNew);
449 expect($scope.gridOptions.data.length).toEqual(3);
450 expect($scope.gridOptions.data).not.toContain(vulnNew);
449451 });
450452 });
451453
452454 describe('Status report vuln edition - update method', function() {
453455 //TODO: test each editable property
454456 });
455
457
456458 describe('Status report vuln edition - edit method (modal)', function() {
457459 it('edit a vuln and accept modal', function() {
458460 var vulnData = {
465467 "owned": true,
466468 "severity": "high"
467469 };
468
470
469471 vuln1.selected_statusreport_controller = true;
472
473 $scope.getCurrentSelection = function() {
474 return [vuln1];
475 };
470476
471477 $scope.$apply();
472478 $scope.edit();
473479 fakeModal.close(vulnData);
474480 $scope.$apply();
475
476 expect($scope.vulns.length).toEqual(3);
477 $scope.vulns.forEach(function(vuln) {
481
482 expect($scope.gridOptions.data.length).toEqual(3);
483 $scope.gridOptions.data.forEach(function(vuln) {
478484 if (vuln._id == "1.2.3.4") {
479485 expect(vuln.name).toEqual("Changed name");
480486 expect(vuln.resolution).toEqual("New resolution");
502508 //$scope.edit();
503509 //fakeModal.dismiss();
504510 //$scope.$apply();
505
506 expect($scope.vulns.length).toEqual(3);
507 $scope.vulns.forEach(function(vuln) {
511
512 expect($scope.gridOptions.data.length).toEqual(3);
513 $scope.gridOptions.data.forEach(function(vuln) {
508514 if (vuln._id == "1.2.3.4") {
509515 expect(vuln.name).not.toEqual("Changed name");
510516 expect(vuln.resolution).not.toEqual("New resolution");
516522 });
517523 });
518524 });
519 });
520
521
522 describe('statusReportCtrl check all function', function() {
523 var $controller,
524 $scope;
525
526 var $vulnsManager,
527 vulnsManagerMock,
528 $workspacesFact,
529 workspacesFactMock;
530
531 var returnPromise;
532
533 beforeEach(function () {
534 module('faradayApp');
535
536 inject(function(_$rootScope_, _$controller_, _$q_, _$modal_) {
537 // The injector unwraps the underscores (_) from around the parameter names when matching
538 $scope = _$rootScope_.$new();
539 // workspaces variables
540
541 returnPromise = function(res) {
542 var deferred = _$q_.defer();
543 deferred.resolve(res);
544 return deferred.promise;
545 }
546
547 rejectPromise = function(res) {
548 var deferred = _$q_.defer();
549 deferred.reject(res);
550 return deferred.promise;
551 }
552
553 workspacesFactMock = {
554 list: function() {
555 return returnPromise(['ws1', 'ws2'])
525
526 describe('statusReportCtrl check all function', function() {
527 var $controller,
528 $scope;
529
530 var $vulnsManager,
531 vulnsManagerMock,
532 $workspacesFact,
533 workspacesFactMock;
534
535 var returnPromise;
536
537 beforeEach(function () {
538 module('faradayApp');
539
540 inject(function(_$rootScope_, _$controller_, _$q_, _$modal_) {
541 // The injector unwraps the underscores (_) from around the parameter names when matching
542 $scope = _$rootScope_.$new();
543 // workspaces variables
544
545 returnPromise = function(res) {
546 var deferred = _$q_.defer();
547 deferred.resolve(res);
548 return deferred.promise;
556549 }
557 }
558
559 vulnsManagerMock = {
560 vulns: [],
561 getVulns: function(workspace) {
562 vulnsManagerMock.vulns = [];
563 for (var i=0; i < 10; i++) {
564 var vuln1 = {
565 "_id": "1.2.3." + i,
566 "_rev": "1-abe16726389e434ca3f37384ea76128e",
567 "name": "vuln " + i,
568 "parent": "1.2.3",
569 "resolution": "Be careful",
570 "refs": [
571 "CVE-2002-1623",
572 "7423",
573 "OSVDB:3820, CERT:886601"
574 ],
575 "metadata": {
576 "update_time": 1429643049.395857,
577 "update_user": "john",
578 "update_action": 0,
579 "creator": "john",
580 "create_time": 1429643049.395857 + i,
581 "update_controller_action": "ModelControler.newVuln",
582 "owner": "john"
583 },
584 "owned": false,
585 "severity": "med",
586 "type": "Vulnerability",
587 "owner": "john",
588 "desc": "I'm scared!",
589 "data": "",
590 "description": "I'm scared!"
591 };
592 var vuln2 = {
593 "_id": "2.2.3." + i,
594 "_rev": "1-abe16726389e434ca3f37384ea76128e",
595 "name": "vuln " + i,
596 "parent": "2.2.3",
597 "resolution": "Be careful",
598 "refs": [
599 "CVE-2002-1623",
600 "7423",
601 "OSVDB:3820, CERT:886601"
602 ],
603 "metadata": {
604 "update_time": 1429643049.395857,
605 "update_user": "john",
606 "update_action": 0,
607 "creator": "john",
608 "create_time": 1429643049.395857 + i + 10,
609 "update_controller_action": "ModelControler.newVuln",
610 "owner": "john"
611 },
612 "owned": false,
613 "severity": "high",
614 "type": "Vulnerability",
615 "owner": "john",
616 "desc": "I'm scared!",
617 "data": "",
618 "description": "I'm scared!"
619 };
620 vulnsManagerMock.vulns.push(vuln1);
621 vulnsManagerMock.vulns.push(vuln2);
550
551 rejectPromise = function(res) {
552 var deferred = _$q_.defer();
553 deferred.reject(res);
554 return deferred.promise;
555 }
556
557 workspacesFactMock = {
558 list: function() {
559 return returnPromise(['ws1', 'ws2'])
622560 }
623 return returnPromise(vulnsManagerMock.vulns);
624561 }
625 };
626
627 $controller = _$controller_('statusReportCtrl', {
628 $scope: $scope,
629 vulnsManager: vulnsManagerMock,
630 hostsManager: {},
631 workspacesFact: workspacesFactMock,
632 $routeParams: {wsId: 'ws1'},
633 $modal: _$modal_
562
563 vulnsManagerMock = {
564 vulns: [],
565 getVulns: function(workspace) {
566 vulnsManagerMock.vulns = [];
567 for (var i=0; i < 10; i++) {
568 var vuln1 = {
569 "_id": "1.2.3." + i,
570 "_rev": "1-abe16726389e434ca3f37384ea76128e",
571 "name": "vuln " + i,
572 "parent": "1.2.3",
573 "resolution": "Be careful",
574 "refs": [
575 "CVE-2002-1623",
576 "7423",
577 "OSVDB:3820, CERT:886601"
578 ],
579 "metadata": {
580 "update_time": 1429643049.395857,
581 "update_user": "john",
582 "update_action": 0,
583 "creator": "john",
584 "create_time": 1429643049.395857 + i,
585 "update_controller_action": "ModelControler.newVuln",
586 "owner": "john"
587 },
588 "owned": false,
589 "severity": "med",
590 "type": "Vulnerability",
591 "owner": "john",
592 "desc": "I'm scared!",
593 "data": "",
594 "description": "I'm scared!"
595 };
596 var vuln2 = {
597 "_id": "2.2.3." + i,
598 "_rev": "1-abe16726389e434ca3f37384ea76128e",
599 "name": "vuln " + i,
600 "parent": "2.2.3",
601 "resolution": "Be careful",
602 "refs": [
603 "CVE-2002-1623",
604 "7423",
605 "OSVDB:3820, CERT:886601"
606 ],
607 "metadata": {
608 "update_time": 1429643049.395857,
609 "update_user": "john",
610 "update_action": 0,
611 "creator": "john",
612 "create_time": 1429643049.395857 + i + 10,
613 "update_controller_action": "ModelControler.newVuln",
614 "owner": "john"
615 },
616 "owned": false,
617 "severity": "high",
618 "type": "Vulnerability",
619 "owner": "john",
620 "desc": "I'm scared!",
621 "data": "",
622 "description": "I'm scared!"
623 };
624 vulnsManagerMock.vulns.push(vuln1);
625 vulnsManagerMock.vulns.push(vuln2);
626 }
627 return returnPromise(vulnsManagerMock.vulns);
628 }
629 };
630
631 $controller = _$controller_('statusReportCtrl', {
632 $scope: $scope,
633 vulnsManager: vulnsManagerMock,
634 hostsManager: {},
635 workspacesFact: workspacesFactMock,
636 $routeParams: {wsId: 'ws1'},
637 $modal: _$modal_
638 });
634639 });
635640 });
636641 });
652657 return {};
653658 };
654659 });
655 it('when current page is 0', function() {
656 $scope.currentPage = 0;
657 $scope.$apply();
658 $scope.checkAll();
659
660 $scope.vulns.forEach(function(v) {
661 if(v._id === "1.2.3.0" || v._id === "1.2.3.1" || v._id === "1.2.3.2" || v._id === "1.2.3.3" || v._id === "1.2.3.4") {
662 expect(search_elem($scope.vulns, v._id).selected_statusreport_controller).toEqual(true);
663 } else {
664 expect(search_elem($scope.vulns, v._id).selected_statusreport_controller).not.toEqual(true);
665 }
666 });
667 });
668 it('when current page is 1', function() {
669 $scope.currentPage = 1;
670 $scope.$apply();
671 $scope.checkAll();
672
673 $scope.vulns.forEach(function(v) {
674 if(v._id === "1.2.3.5" || v._id === "1.2.3.6" || v._id === "1.2.3.7" || v._id === "1.2.3.8" || v._id === "1.2.3.9") {
675 expect(search_elem($scope.vulns, v._id).selected_statusreport_controller).toEqual(true);
676 } else {
677 expect(search_elem($scope.vulns, v._id).selected_statusreport_controller).not.toEqual(true);
678 }
679 });
680 });
681 it('when current page is 0 and filtering', function() {
682 $scope.currentPage = 0;
683 $scope.expression = {severity:"med"};
684 $scope.$apply();
685 $scope.checkAll();
686
687 $scope.vulns.forEach(function(v) {
688 if(v._id === "1.2.3.0" || v._id === "1.2.3.1" || v._id === "1.2.3.2" || v._id === "1.2.3.3" || v._id === "1.2.3.4") {
689 expect(search_elem($scope.vulns, v._id).selected_statusreport_controller).toEqual(true);
690 } else {
691 expect(search_elem($scope.vulns, v._id).selected_statusreport_controller).not.toEqual(true);
692 }
693 });
694 });
695 it('when current page is 1 and filtering', function() {
696 $scope.currentPage = 1;
697 $scope.expression = {severity:"high"};
698 $scope.$apply();
699 $scope.checkAll();
700
701 $scope.vulns.forEach(function(v) {
702 if(v._id === "2.2.3.5" || v._id === "2.2.3.6" || v._id === "2.2.3.7" || v._id === "2.2.3.8" || v._id === "2.2.3.9") {
703 expect(search_elem($scope.vulns, v._id).selected_statusreport_controller).toEqual(true);
704 } else {
705 expect(search_elem($scope.vulns, v._id).selected_statusreport_controller).not.toEqual(true);
706 }
707 });
708 });
709 it('when page size is the total of vulns', function() {
710 $scope.currentPage = 0;
711 $scope.pageSize = 20;
712 $scope.expression = {severity:"high"};
713 $scope.$apply();
714 $scope.checkAll();
715
716 $scope.vulns.forEach(function(v) {
717 if(v._id.split(".")[0] === "2") {
718 expect(search_elem($scope.vulns, v._id).selected_statusreport_controller).toEqual(true);
719 } else {
720 expect(search_elem($scope.vulns, v._id).selected_statusreport_controller).not.toEqual(true);
721 }
722 });
723 });
660 // it('when current page is 0', function() {
661 // $scope.currentPage = 0;
662 // $scope.$apply();
663 // $scope.checkAll();
664
665 // $scope.gridOptions.data.forEach(function(v) {
666 // if(v._id === "1.2.3.0" || v._id === "1.2.3.1" || v._id === "1.2.3.2" || v._id === "1.2.3.3" || v._id === "1.2.3.4") {
667 // expect(search_elem($scope.gridOptions.data, v._id).selected_statusreport_controller).toEqual(true);
668 // } else {
669 // expect(search_elem($scope.gridOptions.data, v._id).selected_statusreport_controller).not.toEqual(true);
670 // }
671 // });
672 // });
673 // it('when current page is 1', function() {
674 // $scope.currentPage = 1;
675 // $scope.$apply();
676 // $scope.checkAll();
677
678 // $scope.gridOptions.data.forEach(function(v) {
679 // if(v._id === "1.2.3.5" || v._id === "1.2.3.6" || v._id === "1.2.3.7" || v._id === "1.2.3.8" || v._id === "1.2.3.9") {
680 // expect(search_elem($scope.gridOptions.data, v._id).selected_statusreport_controller).toEqual(true);
681 // } else {
682 // expect(search_elem($scope.gridOptions.data, v._id).selected_statusreport_controller).not.toEqual(true);
683 // }
684 // });
685 // });
686 // it('when current page is 0 and filtering', function() {
687 // $scope.expression = {severity:"med"};
688 // $scope.$apply();
689 // $scope.checkAll();
690
691 // $scope.gridOptions.data.forEach(function(v) {
692 // if(v._id === "1.2.3.0" || v._id === "1.2.3.1" || v._id === "1.2.3.2" || v._id === "1.2.3.3" || v._id === "1.2.3.4") {
693 // expect(search_elem($scope.gridOptions.data, v._id).selected_statusreport_controller).toEqual(true);
694 // } else {
695 // expect(search_elem($scope.gridOptions.data, v._id).selected_statusreport_controller).not.toEqual(true);
696 // }
697 // });
698 // });
699 // it('when current page is 1 and filtering', function() {
700 // $scope.currentPage = 1;
701 // $scope.expression = {severity:"high"};
702 // $scope.$apply();
703 // $scope.checkAll();
704
705 // $scope.gridOptions.data.forEach(function(v) {
706 // if(v._id === "2.2.3.5" || v._id === "2.2.3.6" || v._id === "2.2.3.7" || v._id === "2.2.3.8" || v._id === "2.2.3.9") {
707 // expect(search_elem($scope.gridOptions.data, v._id).selected_statusreport_controller).toEqual(true);
708 // } else {
709 // expect(search_elem($scope.gridOptions.data, v._id).selected_statusreport_controller).not.toEqual(true);
710 // }
711 // });
712 // });
713 // it('when page size is the total of vulns', function() {
714 // $scope.currentPage = 0;
715 // $scope.pageSize = 20;
716 // $scope.expression = {severity:"high"};
717 // $scope.$apply();
718 // $scope.checkAll();
719
720 // $scope.gridOptions.data.forEach(function(v) {
721 // if(v._id.split(".")[0] === "2") {
722 // expect(search_elem($scope.gridOptions.data, v._id).selected_statusreport_controller).toEqual(true);
723 // } else {
724 // expect(search_elem($scope.gridOptions.data, v._id).selected_statusreport_controller).not.toEqual(true);
725 // }
726 // });
727 // });
724728 });
725729
726730 });
66 var vulnsManager,
77 Vuln,
88 WebVuln,
9 hostsManager;
10
9 hostsManager,
10 servicesManager;
11
1112 var $filter,
1213 $httpBackend,
1314 $q,
2021 couchVuln2,
2122 couchVulnEmpty;
2223
23 var hosts, interfaces,
24 var hosts, interfaces,
2425 hostnames = [];
2526
2627 // Set up the module
127128
128129 hosts = [
129130 {
130 "_id": "1",
131 "_id": "1",
131132 "name": "Host parent"
132133 }
133134 ];
157158 }
158159 ];
159160
161 services = [];
162
160163 interfaces.forEach(function(interf) {
161164 interf.hostnames.forEach(function(hostname) {
162165 if(hostnames.indexOf(hostname) < 0) hostnames.push(hostname);
173176 deferred.resolve(hosts);
174177 return deferred.promise;
175178 },
176 getAllInterfaces: function() {
179 getAllInterfaces: function(ws) {
177180 var deferred = $q.defer();
178181 deferred.resolve(interfaces);
179182 return deferred.promise;
180183 }
181184 };
182185
186 var servicesManagerMock = {
187 getServices: function(ws) {
188 var deferred = $q.defer();
189 deferred.resolve(services);
190 return deferred.promise;
191 }
192 };
193
183194 module(function($provide) {
184195 $provide.factory('hostsManager', function($q) { return hostsManagerMock; });
185 });
186
187 inject(function(_vulnsManager_, _Vuln_, _WebVuln_, _$filter_, _$httpBackend_, _$q_, _hostsManager_) {
196 $provide.factory('servicesManager', function($q) { return servicesManagerMock; });
197 });
198
199 inject(function(_vulnsManager_, _Vuln_, _WebVuln_, _$filter_, _$httpBackend_, _$q_, _hostsManager_, _servicesManager_) {
188200 $filter = _$filter_;
189201 $httpBackend = _$httpBackend_;
190202 $q = _$q_;
192204 Vuln = _Vuln_;
193205 WebVuln = _WebVuln_;
194206 hostsManager = _hostsManager_;
195 BASEURL = 'http://localhost:9876/';
207 servicesManager = _servicesManager_;
208 BASEURL = 'http://localhost:9876/';
196209 });
197210
198211 });
282295
283296 // delete vuln
284297 $httpBackend.expect('DELETE', BASEURL + 'ws/' + id + "?rev=" + vuln1._rev).respond(200);
285
298
286299 vulnsManager.deleteVuln(vulnsManager.vulns[0]);
287300 $httpBackend.flush();
288301
303316
304317 // update vuln
305318 $httpBackend.expect('PUT', BASEURL + 'ws/' + id).respond(200, {"rev": "1-abe16726389e434ca3f37384ea76128e"});
306
319
307320 var vulns = vulnsManager.updateVuln(vulnsManager.vulns[0], vuln2);
308321 $httpBackend.flush();
309322
0 // // Faraday Penetration Test IDE
1 // // Copyright (C) 2013 Infobyte LLC (http://www.infobytesec.com/)
2 // // See the file 'doc/LICENSE' for the license information
0 // Faraday Penetration Test IDE
1 // Copyright (C) 2013 Infobyte LLC (http://www.infobytesec.com/)
2 // See the file 'doc/LICENSE' for the license information
33
4 // describe('workspacesFact', function() {
5 // var $httpBackend, createFactory;
4 describe('workspacesFact', function() {
5 var $httpBackend, createFactory;
66
7 // // Set up the module
8 // beforeEach(module('faradayApp'));
7 // Set up the module
8 beforeEach(module('faradayApp'));
99
10 // beforeEach(inject(function($injector) {
11 // // Set up the mock http service responses
12 // $httpBackend = $injector.get('$httpBackend');
13 // var $workspacesFact = $injector.get('workspacesFact');
10 beforeEach(inject(function($injector) {
11 // Set up the mock http service responses
12 $httpBackend = $injector.get('$httpBackend');
13 var $workspacesFact = $injector.get('workspacesFact');
1414
15 // createFactory = function() {
16 // return $injector.get('workspacesFact', {'BASEURL' : 'http://localhost:9876/',
17 // '$http': $httpBackend});
18 // };
19 // }));
15 createFactory = function() {
16 return $injector.get('workspacesFact', {'BASEURL' : 'http://localhost:9876/',
17 '$http': $httpBackend});
18 };
19 }));
2020
2121
22 // afterEach(function() {
23 // $httpBackend.verifyNoOutstandingExpectation();
24 // $httpBackend.verifyNoOutstandingRequest();
25 // });
22 afterEach(function() {
23 $httpBackend.verifyNoOutstandingExpectation();
24 $httpBackend.verifyNoOutstandingRequest();
25 });
2626
27 // describe('Workspaces Service CRUD', function() {
28 // it('Tests if factory is well created', function() {
29 // fact = createFactory();
30 // });
27 describe('Workspaces Service CRUD', function() {
28 it('Tests if factory is well created', function() {
29 fact = createFactory();
30 });
3131
32 // it('Tests if existence is well asked', function() {
33 // $httpBackend.when('HEAD', 'http://localhost:9876/tuvieja')
34 // .respond(200, '');
32 it('Tests if existence is well asked', function() {
33 $httpBackend.when('HEAD', 'http://localhost:9876/tuvieja')
34 .respond(200, '');
3535
36 // $httpBackend.expectHEAD('http://localhost:9876/tuvieja');
37 // fact = createFactory();
38 // workspace_exists = fact.exists('tuvieja');
39 // expect(workspace_exists).toBe(true);
40 // $httpBackend.flush();
41 // });
36 $httpBackend.expectHEAD('http://localhost:9876/tuvieja');
37 fact = createFactory();
38 fact.exists('tuvieja').then(function(exist){
39 expect(exist).toBe(true);
40 });
41 $httpBackend.flush();
42 });
4243
43 // it('Tests if OK Inserts are well done', function() {
44 // var workspace = {
45 // "_id": "test_workspace",
46 // "customer": "",
47 // "sdate": 1415901244.040532,
48 // "name": "test_workspace",
49 // "fdate": 1415901244.040532,
50 // "type": "Workspace",
51 // "children": [
52 // ],
53 // "description": ""
54 // };
44 it('Tests if OK Inserts are well done', function() {
45 var workspace = {
46 "_id": "test_workspace",
47 "customer": "",
48 "sdate": 1415901244.040532,
49 "name": "test_workspace",
50 "fdate": 1415901244.040532,
51 "type": "Workspace",
52 "children": [
53 ],
54 "description": ""
55 };
5556
56 // $httpBackend.expectPUT('http://localhost:9876/test_workspace',
57 // workspace).respond(200, {"ok": true});
57 $httpBackend.expectPUT('http://localhost:9876/test_workspace',
58 workspace).respond(200, {"ok": true});
5859
59 // $httpBackend.expectPUT('http://localhost:9876/test_workspace/test_workspace',
60 // workspace).respond(200, {"ok": true});
60 $httpBackend.expectPUT('http://localhost:9876/test_workspace/test_workspace',
61 workspace).respond(200, {"ok": true});
6162
62 // fact = createFactory();
63 // var workspace_exists = false;
64 // onSuccess = function(){ workspace_exists = true;};
63 fact = createFactory();
6564
66 // fact.put(workspace, onSuccess);
67 // $httpBackend.flush();
68 // expect(workspace_exists).toBe(true);
69 // });
65 fact.put(workspace);
66 $httpBackend.flush();
67 expect(workspace_exists).toBe(true);
68 });
7069
71 // it('Tests if OK Delete are well done', function() {
72 // $httpBackend.expectDELETE('http://localhost:9876/test_workspace').
73 // respond(200, {"ok": true});
70 it('Tests if OK Delete are well done', function() {
71 $httpBackend.expectDELETE('http://localhost:9876/test_workspace').
72 respond(200, {"ok": true});
7473
75 // fact = createFactory();
76 // var workspace_exists = true;
77 // onSuccess = function(){ workspace_exists = false;};
74 fact = createFactory();
7875
79 // workspace_exists = fact.delete('test_workspace', onSuccess);
80 // $httpBackend.flush();
81 // expect(workspace_exists).toBe(false);
82 // });
83 // });
76 fact.delete('test_workspace').then(function(resp) {
77 expect(resp).toBe('test_workspace');
78 });
79 $httpBackend.flush();
80 });
81 });
8482
85 // });
83 });
2525 '../views/reports/_attachments/script/angular-hotkeys.js',
2626 '../views/reports/_attachments/script/cryptojs-sha1.js',
2727 '../views/reports/_attachments/script/Chart.js',
28 '../views/reports/_attachments/script/angular-chart.min.js'
28 '../views/reports/_attachments/script/angular-chart.min.js',
29 '../views/reports/_attachments/script/sanitize.js',
30 '../views/reports/_attachments/script/ui-grid.js'
2931 ],
3032
3133 autoWatch : true,
66
77 '''
88 import subprocess
9 import pip
109 import couchdbkit
1110 import model.workspace
1211 import persistence.mappers.data_mappers as dm
3332 logger.info('Checking qt3 libs')
3433 QT().run()
3534
36 logger.info('Installing missing dependencies in pip')
37 pip.main(['install', '-r', CONST_REQUIREMENTS_FILE, '--user'])
35 try:
36 import pip
37 logger.info('Installing missing dependencies in pip')
38 pip.main(['install', '-r', CONST_REQUIREMENTS_FILE, '--user'])
39 except ImportError:
40 logger.error("Checking missing dependencies in pip")
41 pass
42
3843
3944 # logger.info('Upgrading DBs to latest version')
4045 # DB().run()
4343 import requests
4444 import hashlib
4545 import platform
46 import pip
4746
4847 text = StringIO()
4948 traceback.print_exception(type, value, tb, file=text)
5857 exception_hash = hashlib.sha256(excepts).hexdigest()
5958 os_dist = " ".join(platform.dist())
6059 python_version = platform.python_version()
61 modules_info = ",".join([ "%s=%s" % (x.key, x.version)
62 for x in pip.get_installed_distributions()])
60 modules_info = ""
61 try:
62 import pip
63 modules_info = ",".join([ "%s=%s" % (x.key, x.version)
64 for x in pip.get_installed_distributions()])
65 except ImportError:
66 pass
67
6368
6469 python_dist = "Python %s \n Modules: [ %s ]" % (python_version, modules_info)
6570
8994 import requests
9095 import hashlib
9196 import platform
92 import pip
9397
9498 uri = CONF.getTktPostUri()
9599 headers = json.loads(CONF.getApiParams())
10391039 overflow-y: auto!important;
10401040 }
10411041 div.ui-grid-header-cell .ui-grid-cell-contents{white-space: normal;}
1042 div.alert.alert-danger.alert-dismissible .ws-list{text-align: center; text-transform: uppercase; padding: 10px}
1043 div.alert.alert-danger.alert-dismissible .ws-list a:hover{text-decoration: none}
1044 a.button-disable{cursor: not-allowed;pointer-events: none;opacity: 0.5}
99 cweFact.get = function() {
1010 var deferred = $q.defer();
1111 var cwe_url = BASEURL + 'cwe/_all_docs?include_docs=true';
12
13 $http.get(cwe_url).then(function(res) {
14 res.data.rows.forEach(function(obj) {
15 var c = {
16 id: obj.id,
17 cwe: obj.doc.cwe,
18 name: obj.doc.name,
19 desc: "Summary: " + obj.doc.desc_summary + "\n\n" + obj.doc.description,
20 resolution: obj.doc.resolution,
21 exploitation: obj.doc.exploitation,
22 refs: obj.doc.references
23 };
24 if (typeof(obj.doc.references) == "string") {
25 c.refs = [];
26 obj.doc.references.split('\n').forEach(function(ref) {
27 if (ref != "") {
28 c.refs.push(ref);
29 }
30 });
31 }
32 cweFact.cweList.push(c);
12 if (cweFact.cweList.length > 0) {
13 deferred.resolve(cweFact.cweList);
14 } else {
15 $http.get(cwe_url).then(function(res) {
16 res.data.rows.forEach(function(obj) {
17 var c = {
18 id: obj.id,
19 cwe: obj.doc.cwe,
20 name: obj.doc.name,
21 desc: "Summary: " + obj.doc.desc_summary + "\n\n" + obj.doc.description,
22 resolution: obj.doc.resolution,
23 exploitation: obj.doc.exploitation,
24 refs: obj.doc.references
25 };
26 if (typeof(obj.doc.references) == "string") {
27 c.refs = [];
28 obj.doc.references.split('\n').forEach(function(ref) {
29 if (ref != "") {
30 c.refs.push(ref);
31 }
32 });
33 }
34 cweFact.cweList.push(c);
35 });
36 deferred.resolve(cweFact.cweList);
3337 });
34 deferred.resolve(cweFact.cweList);
35 });
38 }
3639
3740 return deferred.promise;
3841 };
22 // See the file 'doc/LICENSE' for the license information
33
44 angular.module('faradayApp')
5 .controller('navigationCtrl', ['$scope', '$http', '$route', '$routeParams', '$cookies', '$location', '$interval', 'configSrv',
6 function($scope, $http, $route, $routeParams, $cookies, $location, $interval, configSrv) {
5 .controller('navigationCtrl', ['$scope', '$http', '$route', '$routeParams', '$cookies', '$location', '$interval', '$uibModal', 'configSrv', 'workspacesFact',
6 function($scope, $http, $route, $routeParams, $cookies, $location, $interval, $uibModal, configSrv, workspacesFact) {
77
88 $scope.workspace = "";
99 $scope.component = "";
10 var componentsNeedsWS = ["dashboard","status","hosts"];
1011
1112 $scope.checkCwe = function() {
1213 $http.get("https://www.faradaysec.com/scripts/updatedb.php?version=" + configSrv.faraday_version).then(function() {
2526 });
2627
2728 $scope.$on('$routeChangeSuccess', function() {
29 if(componentsNeedsWS.indexOf($location.path().split("/")[1]) != -1 && $routeParams.wsId !== undefined) {
30 workspacesFact.list().then(function(wss) {
31 $scope.wss = wss;
32 });
33
34 workspacesFact.exists($routeParams.wsId).then(function(resp){
35 if(resp !== true) {
36 $scope.modalWsNoExist();
37 }
38 });
39 }
2840 $scope.updateWorkspace();
2941 $scope.updateComponent();
3042 });
43
44 $scope.modalWsNoExist = function() {
45 $scope.modalInstance = $uibModal.open({
46 templateUrl: 'scripts/navigation/partials/wsNo-exist.html',
47 scope: $scope,
48 backdrop: 'static',
49 keyboard: false
50 });
51 };
52
53 $scope.cancel = function() {
54 $scope.modalInstance.dismiss('cancel');
55 };
3156
3257 $scope.updateWorkspace = function() {
3358 if($routeParams.wsId != undefined) {
6994 // if(navigator.userAgent.toLowerCase().indexOf('iceweasel') > -1) {
7095 // $scope.isIceweasel = "Your browser is not supported, please use Firefox or Chrome";
7196 // }
72
73 }]);
97 }]);
1212 <a href="#/status/ws/{{workspace}}" class="status-report" style="color: #ffffff !important" uib-tooltip="Status Report" tooltip-placement="right">
1313 <img src="images/ico-status-menu.svg" alt="Status Report"/>
1414 </a>
15 </li>
15 </li>
1616 <li>
1717 <a href="#/workspaces" class="workspaces" style="color: #ffffff !important" uib-tooltip="Workspaces" tooltip-placement="right">
1818 <img src="images/ico-workspaces-menu.svg" alt="Workspaces"/>
4141 <li>
4242 <a href="#/comparison" class="executive-report" style="color: #ffffff !important" uib-tooltip="Workspaces Comparison" tooltip-placement="right">
4343 <img src="images/ico-workspace-comparison-menu.svg" alt="Workspaces Comparison"/>
44 </a>
44 </a>
4545 </li>
4646 <li>
4747 <a href="#/webshell" class="executive-report" style="color: #ffffff !important" uib-tooltip="Web Shell" tooltip-placement="right">
4848 <img src="images/ico-web-shell-menu.svg" alt="Webshell"/>
49 </a>
49 </a>
5050 </li>
5151 </ul>
5252 </nav>
0 <!-- Faraday Penetration Test IDE -->
1 <!-- Copyright (C) 2013 Infobyte LLC (http://www.infobytesec.com/) -->
2 <!-- See the file 'doc/LICENSE' for the license information -->
3
4 <div class="modal-header">
5 <h4 class="modal-title">This workspace does not exist. Select one of the list</h4>
6 </div>
7 <div class="modal-body">
8 <ul class="ws-list">
9 <li ng-repeat="ws in wss"><a href="#/{{component}}/ws/{{ws}}" ng-click="cancel()"><span ng-class-even="'label label-unclassified'" ng-class-odd="'label label-high'" style="text-transform: uppercase">{{ws}}</span></a></li>
10 </ul>
11 </div><!-- .modal-body -->
3535 </div><!-- .form-group -->
3636 <div class="form-group">
3737 <div class="col-md-3">
38 <h5>Ports</h5>
39 <span class="input-group-addon button-radius" ng-click="newPort($event)">Add Port</span>
38 <h5>Port</h5>
4039 <div class="input-margin" ng-repeat="port in service.ports">
41 <div class="input-group margin-bottom-sm">
42 <label class="sr-only" for="port">Ports</label>
43 <input type="number" class="form-control" id="port" placeholder="Port" ng-model="port.key"/>
44 <span class="input-group-addon" ng-click="service.ports.splice($index, 1)" ng-hide="service.ports.length == 1"><i class="fa fa-minus-circle"></i></span>
45 </div>
40 <label class="sr-only" for="port">Port</label>
41 <input type="number" class="form-control" id="port" placeholder="Port" ng-model="port.key"/>
4642 </div>
4743 </div>
4844 <div class="col-md-3 protocol">
3535 </div><!-- .form-group -->
3636 <div class="form-group">
3737 <div class="col-md-3">
38 <h5>Ports</h5>
39 <span class="input-group-addon button-radius" ng-click="newPort($event)">Add Port</span>
38 <h5>Port</h5>
4039 <div class="input-margin" ng-repeat="port in service.ports" ng-class="{'has-error': form.port.$invalid }">
41 <div class="input-group margin-bottom-sm">
42 <label class="sr-only" for="port">Ports</label>
43 <input type="number" class="form-control" id="port" name="port" placeholder="Port" ng-model="port.key" required/>
44 <span class="input-group-addon" ng-click="service.ports.splice($index, 1)" ng-hide="service.ports.length == 1"><i class="fa fa-minus-circle"></i></span>
45 </div>
40 <label class="sr-only" for="port">Port</label>
41 <input type="number" class="form-control" id="port" name="port" placeholder="Port" ng-model="port.key" required/>
4642 </div>
4743 </div>
4844 <div class="col-md-3 protocol" ng-class="{'has-error': form.protocol.$invalid }">
22 // See the file 'doc/LICENSE' for the license information
33
44 angular.module('faradayApp')
5 .controller('statusReportCtrl',
5 .controller('statusReportCtrl',
66 ['$scope', '$filter', '$routeParams',
77 '$location', '$uibModal', '$cookies', '$q', '$window', 'BASEURL',
88 'SEVERITIES', 'EASEOFRESOLUTION', 'hostsManager',
3838 $scope.easeofresolution = EASEOFRESOLUTION;
3939 $scope.propertyGroupBy = $routeParams.groupbyId;
4040 $scope.sortField = 'metadata.create_time';
41 $scope.colProperties = ["date","name","severity","service","target","desc","resolution","data","status","website","path","request","method","params","pname","query","response"];
4241 $scope.reverse = true;
4342 $scope.vulns = [];
4443 $scope.selected = false;
45
46 var deleteRow = '<div ng-if="row.entity._id != undefined" class="ui-grid-cell-contents row-tooltip text-center">'+
47 '<span ng-click="grid.appScope.deleteVuln(row.entity)" class="glyphicon glyphicon-trash cursor" uib-tooltip="Delete"></span>'+
48 '</div>';
49 var editRow = '<div ng-if="row.entity._id != undefined" class="ui-grid-cell-contents row-tooltip text-center">'+
50 '<span ng-click="grid.appScope.editVuln(row.entity)" class="glyphicon glyphicon-pencil cursor" uib-tooltip="Edit"></span>'+
51 '</div>';
52
53 var filterRow = '<div ng-if="row.entity._id != undefined" class="ui-grid-cell-contents row-tooltip text-center">'+
54 '<span ng-click="grid.appScope.toggleConfirmVuln(row.entity, row.entity.confirmed)" class="glyphicon glyphicon-filter cursor" uib-tooltip="{{grid.appScope.confirmedTooltip(row.entity.confirmed)}}" tooltip-placement="right" ng-class="{ disabled:row.entity.confirmed === false }"></span>'+
55 '</div>';
5644
5745 $scope.gridOptions = {
5846 multiSelect: true,
6957 };
7058 $scope.gridOptions.columnDefs = [];
7159
72 $scope.showObjects = function(object, property, IdEvidence) {
73 var partial = "";
74 if(angular.isArray(object) === false) {
75 for(key in object) {
76 if(object.hasOwnProperty(key)) {
77 if(object[key] === true) {
78 partial += "<p class='pos-middle crop-text'>" + key + "</p>";
79 } else if(property === "evidence") {
80 partial += "<p class='pos-middle crop-text'><a href='http://127.0.0.1:5984/"+$scope.workspace+"/"+IdEvidence+"/"+$scope.encodeUrl(key)+"' target='_blank'>" + key + "</a></p>";
81 }
82 }
83 }
84 } else {
85 object.forEach(function(key) {
86 if(key === "") return;
87 if(property === "hostnames") {
88 partial += "<p><a href='//www.shodan.io/search?query=" + key + "' class=\"pos-middle crop-text\" uib-tooltip=\"Search in Shodan\" target=\"_blank\">" +
89 "<img src=\"../././reports/images/shodan.png\" height=\"15px\" width=\"15px\" style=\"margin-left:5px\"/></a>"+
90 "<a href=\""+ $scope.hash + "/search/"+ property +"=" + key + "\">" + key + "</a></p>";
91 } else if(property === "refs"){
92 partial += "<p class='pos-middle crop-text'><a href='" + $scope.processReference(key) + "' target=\"_blank\">" + key + "</a></p>";
93 } else {
94 partial += "<p class='pos-middle crop-text'>" + key + "</p>";
95 }
96 });
97 }
98 return partial;
99 };
60 if ($cookies.get('pageSize') !== undefined) $scope.gridOptions.paginationPageSize = parseInt($cookies.get('pageSize'));
10061
10162 $scope.gridOptions.onRegisterApi = function(gridApi){
10263 //set gridApi on scope
11576 }
11677 });
11778 $scope.gridApi.pagination.on.paginationChanged($scope, function (pageNumber, pageSize) {
79 $cookies.put('pageSize', pageSize);
11880 $scope.gridApi.selection.clearSelectedRows();
11981 });
12082 };
152114
153115 // load all vulnerabilities
154116 vulnsManager.getVulns($scope.workspace).then(function(vulns) {
155 tmp_data = $filter('orderObjectBy')(vulnsManager.vulns, $scope.propertyGroupBy, true);
156 $scope.gridOptions.data = $filter('filter')(tmp_data, $scope.expression);
157
117 $scope.filterVulns();
158118 $scope.gridOptions.total = vulns.length;
159119 if($scope.gridOptions.total > $scope.gridOptions.paginationPageSize && $scope.gridOptions.total > 100) {
160120 $scope.gridOptions.paginationPageSizes.push($scope.gridOptions.total);
161121 }
162122 });
163123
164 // created object for columns cookie columns
165 if(typeof($cookies.get('SRcolumns')) != 'undefined'){
166 var objectoSRColumns = {};
167 var arrayOfColumns = $cookies.get('SRcolumns').replace(/[{}"']/g, "").split(',');
168 arrayOfColumns.forEach(function(column){
169 var columnFinished = column.split(':');
170 if(columnFinished[1] == "true") objectoSRColumns[columnFinished[0]] = true; else objectoSRColumns[columnFinished[0]] = false;
171 });
172 }
173 // set columns to show and hide by default
174 $scope.columns = objectoSRColumns || {
124 $scope.columns = {
175125 "date": true,
176126 "name": true,
177127 "severity": true,
196146 "response": false,
197147 "web": false
198148 };
199 $scope.gridOptions.columnDefs.push({ name: ' ', width: '20', headerCellTemplate: "<i class=\"fa fa-check cursor\" ng-click=\"grid.appScope.selectAll()\" ng-style=\"{'opacity':(grid.appScope.selected === true) ? '1':'0.6'}\"></i>", pinnedLeft:true });
200 $scope.gridOptions.columnDefs.push({ name: ' ', width: '40', cellTemplate: filterRow });
201 $scope.gridOptions.columnDefs.push({ name: ' ', width: '40', cellTemplate: deleteRow });
202 $scope.gridOptions.columnDefs.push({ name: ' ', width: '30', cellTemplate: editRow });
149
150 // created object for columns cookie columns
151 if(typeof($cookies.get('SRcolumns')) != 'undefined'){
152 var arrayOfColumns = $cookies.get('SRcolumns').replace(/[{}"']/g, "").split(',');
153 arrayOfColumns.forEach(function(column){
154 var columnFinished = column.split(':');
155 if ($scope.columns.hasOwnProperty(columnFinished[0])) {
156 $scope.columns[columnFinished[0]] = columnFinished[1] === "true" ? true: false;
157 }
158 });
159 }
160
161 $scope.gridOptions.columnDefs.push({ name: 'selectAll', width: '20', headerCellTemplate: "<i class=\"fa fa-check cursor\" ng-click=\"grid.appScope.selectAll()\" ng-style=\"{'opacity':(grid.appScope.selected === true) ? '1':'0.6'}\"></i>", pinnedLeft:true });
162 $scope.gridOptions.columnDefs.push({ name: 'confirmVuln', width: '40', headerCellTemplate: "<div></div>", cellTemplate: 'scripts/statusReport/partials/ui-grid/confirmbutton.html' });
163 $scope.gridOptions.columnDefs.push({ name: 'deleteVuln', width: '40', headerCellTemplate: "<div></div>", cellTemplate: 'scripts/statusReport/partials/ui-grid/deletebutton.html' });
164 $scope.gridOptions.columnDefs.push({ name: 'editVuln', width: '30', headerCellTemplate: "<div></div>", cellTemplate: 'scripts/statusReport/partials/ui-grid/editbutton.html' });
165
166 var header = '<div ng-class="{ \'sortable\': sortable }">'+
167 ' <div class="ui-grid-cell-contents" col-index="renderIndex" title="TOOLTIP">{{ col.displayName CUSTOM_FILTERS }}'+
168 ' <a href="" ng-click="grid.appScope.toggleShow(col.displayName, true)">'+
169 ' <span style="color:#000;" class="glyphicon glyphicon-remove"></span>'+
170 ' </a>'+
171 ' <span ui-grid-visible="col.sort.direction" ng-class="{ \'ui-grid-icon-up-dir\': col.sort.direction == asc, \'ui-grid-icon-down-dir\': col.sort.direction == desc, \'ui-grid-icon-blank\': !col.sort.direction }">&nbsp;</span>'+
172 ' </div>'+
173 ' <div class="ui-grid-column-menu-button" ng-if="grid.options.enableColumnMenus && !col.isRowHeader && col.colDef.enableColumnMenu !== false" ng-click="toggleMenu($event)" ng-class="{\'ui-grid-column-menu-button-last-col\': isLastCol}">'+
174 ' <i class="ui-grid-icon-angle-down">&nbsp;</i>'+
175 ' </div>'+
176 ' <div ui-grid-filter></div>'+
177 ' </div>';
178
179 $scope.gridOptions.columnDefs.push({ name : 'metadata.create_time',
180 displayName : "date",
181 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/datecolumn.html',
182 headerCellTemplate: header,
183 width: '90',
184 visible: $scope.columns["date"]
185 });
186 $scope.gridOptions.columnDefs.push({ name : 'name',
187 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/namecolumn.html',
188 headerCellTemplate: header,
189 maxWidth: '230',
190 visible: $scope.columns["name"]
191 });
192 $scope.gridOptions.columnDefs.push({ name : 'severity',
193 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/severitycolumn.html',
194 headerCellTemplate: header,
195 type: 'string',
196 width: '110',
197 visible: $scope.columns["severity"],
198 sortingAlgorithm: compareSeverities
199 });
200 $scope.gridOptions.columnDefs.push({ name : 'service',
201 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/servicecolumn.html',
202 headerCellTemplate: header,
203 width: '110',
204 visible: $scope.columns["service"]
205 });
206 $scope.gridOptions.columnDefs.push({ name : 'target',
207 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/targetcolumn.html',
208 headerCellTemplate: header,
209 width: '140',
210 visible: $scope.columns["target"]
211 });
212 $scope.gridOptions.columnDefs.push({ name : 'desc',
213 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/desccolumn.html',
214 headerCellTemplate: header,
215 minWidth: '300',
216 maxWidth: '400',
217 visible: $scope.columns["desc"]
218 });
219 $scope.gridOptions.columnDefs.push({ name : 'resolution',
220 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/resolutioncolumn.html',
221 headerCellTemplate: header,
222 visible: $scope.columns["resolution"]
223 });
224 $scope.gridOptions.columnDefs.push({ name : 'data',
225 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/resolutioncolumn.html',
226 headerCellTemplate: header,
227 visible: $scope.columns["data"]
228 });
229 $scope.gridOptions.columnDefs.push({ name : 'easeofresolution',
230 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/defaultcolumn.html',
231 headerCellTemplate: header,
232 visible: $scope.columns["easeofresolution"]
233 });
234 $scope.gridOptions.columnDefs.push({ name : 'status',
235 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/defaultcolumn.html',
236 headerCellTemplate: header,
237 visible: $scope.columns["status"]
238 });
239 $scope.gridOptions.columnDefs.push({ name : 'website',
240 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/defaultcolumn.html',
241 headerCellTemplate: header,
242 visible: $scope.columns["website"]
243 });
244 $scope.gridOptions.columnDefs.push({ name : 'path',
245 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/defaultcolumn.html',
246 headerCellTemplate: header,
247 visible: $scope.columns["path"]
248 });
249 $scope.gridOptions.columnDefs.push({ name : 'request',
250 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/resolutioncolumn.html',
251 headerCellTemplate: header,
252 visible: $scope.columns["request"]
253 });
254 $scope.gridOptions.columnDefs.push({ name : 'refs',
255 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/refscolumn.html',
256 headerCellTemplate: header,
257 visible: $scope.columns["refs"]
258 });
259 $scope.gridOptions.columnDefs.push({ name : '_attachments',
260 displayName: "evidence",
261 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/evidencecolumn.html',
262 headerCellTemplate: header,
263 visible: $scope.columns["evidence"]
264 });
265 $scope.gridOptions.columnDefs.push({ name : 'hostnames',
266 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/hostnamescolumn.html',
267 headerCellTemplate: header,
268 visible: $scope.columns["hostnames"]
269 });
270 $scope.gridOptions.columnDefs.push({ name : 'impact',
271 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/impactcolumn.html',
272 headerCellTemplate: header,
273 visible: $scope.columns["impact"]
274 });
275 $scope.gridOptions.columnDefs.push({ name : 'method',
276 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/defaultcolumn.html',
277 headerCellTemplate: header,
278 visible: $scope.columns["method"]
279 });
280 $scope.gridOptions.columnDefs.push({ name : 'params',
281 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/defaultcolumn.html',
282 headerCellTemplate: header,
283 visible: $scope.columns["params"]
284 });
285 $scope.gridOptions.columnDefs.push({ name : 'pname',
286 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/defaultcolumn.html',
287 headerCellTemplate: header,
288 visible: $scope.columns["pname"]
289 });
290 $scope.gridOptions.columnDefs.push({ name : 'query',
291 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/defaultcolumn.html',
292 headerCellTemplate: header,
293 visible: $scope.columns["query"]
294 });
295 $scope.gridOptions.columnDefs.push({ name : 'response',
296 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/resolutioncolumn.html',
297 headerCellTemplate: header,
298 visible: $scope.columns["response"]
299 });
300 $scope.gridOptions.columnDefs.push({ name : 'web',
301 cellTemplate: 'scripts/statusReport/partials/ui-grid/columns/webcolumn.html',
302 headerCellTemplate: header,
303 width: '80',
304 visible: $scope.columns["web"]
305 });
306
307 $scope.vulnWebSelected = false;
308
203309 var count = 0;
204310 for(key in $scope.columns) {
205311 if($scope.columns.hasOwnProperty(key) && $scope.columns[key] == true) {
206312 count++;
207 _addColumn(key);
208313 if(key === $scope.propertyGroupBy) {
209314 $scope.gridOptions.columnDefs[count + 3].grouping = { groupPriority: 0 };
210315 $scope.gridOptions.columnDefs[count + 3].sort = { priority: 0, direction: 'asc' }
211316 }
212317 }
213 }
214 $scope.vulnWebSelected = false;
215 };
216
217 _addColumn = function(column) {
218
219 var myHeader = "<div ng-class=\"{ 'sortable': sortable }\">"+
220 "<div class=\"ui-grid-cell-contents\" col-index=\"renderIndex\" title=\"TOOLTIP\">{{ col.displayName CUSTOM_FILTERS }}"+
221 "<a href=\"\" ng-click=\"grid.appScope.toggleShow(col.displayName, true)\"><span style=\"color:#000;\" class=\"glyphicon glyphicon-remove\"></span></a>"+
222 "<span ui-grid-visible=\"col.sort.direction\" ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\">&nbsp;</span>"+
223 "</div>"+
224 "<div class=\"ui-grid-column-menu-button\" ng-if=\"grid.options.enableColumnMenus && !col.isRowHeader && col.colDef.enableColumnMenu !== false\" ng-click=\"toggleMenu($event)\" ng-class=\"{'ui-grid-column-menu-button-last-col': isLastCol}\">"+
225 "<i class=\"ui-grid-icon-angle-down\">&nbsp;</i>"+
226 "</div>"+
227 "<div ui-grid-filter></div>"
228 "</div>";
229
230 if(column === 'date') {
231 $scope.gridOptions.columnDefs.push({ 'name' : 'metadata.create_time', 'displayName' : column, type: 'date', cellFilter: 'date:"MM/dd/yyyy"', headerCellTemplate: myHeader, width: '90'
232 });
233 } else if(column === 'name') {
234 $scope.gridOptions.columnDefs.push({ 'name' : column,
235 'cellTemplate': '<div ng-if="row.entity._id != undefined"><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" uib-tooltip="{{COL_FIELD}}"><a ng-href=' + $scope.hash + '/search/name={{row.entity.name}}>{{COL_FIELD CUSTOM_FILTERS}}</a></div></div><div ng-if=\"row.groupHeader && col.grouping.groupPriority !== undefined\" class="ui-grid-cell-contents white-space">{{COL_FIELD CUSTOM_FILTERS}}</div>',
236 headerCellTemplate: myHeader,
237 maxWidth: '230'
238 });
239 } else if(column === 'severity') {
240 $scope.gridOptions.columnDefs.push({ 'name' : column,
241 'cellTemplate': '<div ng-if="row.entity._id != undefined">'+
242 '<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 text-center"><a href=\"#/status/ws/' + $scope.workspace + '/search/severity={{COL_FIELD}}\"><span class=\"label vuln fondo-{{COL_FIELD}}\">{{COL_FIELD | uppercase}}</span></a></div>'+
243 '</div>'+
244 '<div ng-if=\"row.groupHeader && col.grouping.groupPriority !== undefined\"><span class=\"label vuln fondo-{{COL_FIELD}}\">{{COL_FIELD | uppercase}}</span></div>',
245 headerCellTemplate: myHeader,
246 type: 'string',
247 width: '110',
248 sortingAlgorithm: compareSeverities
249 });
250 } else if(column === 'target') {
251 $scope.gridOptions.columnDefs.push({ 'name' : column, 'cellTemplate': "<div ng-if='row.entity._id != undefined' class='ui-grid-cell-contents row-tooltip'><a ng-href=" + $scope.hash + "/search/target={{row.entity.target}}>{{COL_FIELD CUSTOM_FILTERS}}</a>" +
252 "<a ng-href=\"//www.shodan.io/search?query={{row.entity.target}}\" uib-tooltip=\"Search in Shodan\" target=\"_blank\">" +
253 "<img ng-src=\"../././reports/images/shodan.png\" height=\"15px\" width=\"15px\" style='margin-left:5px'/>" +
254 "</a></div>"+
255 "<div ng-if=\"row.groupHeader && col.grouping.groupPriority !== undefined\">{{COL_FIELD CUSTOM_FILTERS}}</div>", headerCellTemplate: myHeader,
256 width: '115',
257 });
258 } else if(column === 'impact' || column === 'refs' || column === 'hostnames') {
259 $scope.gridOptions.columnDefs.push({ 'name' : column, 'displayName': column, 'cellTemplate': "<div class=\"ui-grid-cell-contents center\" ng-bind-html=\"grid.appScope.showObjects(COL_FIELD, col.name)\"></div><div ng-if=\"row.groupHeader && col.grouping.groupPriority !== undefined\">{{COL_FIELD CUSTOM_FILTERS}}</div>", headerCellTemplate: myHeader });
260 } else if(column === 'evidence') {
261 $scope.gridOptions.columnDefs.push({ 'name' : column, 'displayName': column, 'cellTemplate': "<div class=\"ui-grid-cell-contents center\" ng-bind-html=\"grid.appScope.showObjects(row.entity._attachments, col.name, row.entity._id)\"></div><div ng-if=\"row.groupHeader && col.grouping.groupPriority !== undefined\">{{COL_FIELD CUSTOM_FILTERS}}</div>", headerCellTemplate: myHeader });
262 } else if(column === 'service') {
263 $scope.gridOptions.columnDefs.push({ 'name' : column, 'displayName': column, 'cellTemplate': "<div class='ui-grid-cell-contents'><a href=" + $scope.hash + "/search/service={{grid.appScope.encodeUrl(row.entity.service)}}>{{COL_FIELD CUSTOM_FILTERS}}</a></div><div ng-if='row.groupHeader && col.grouping.groupPriority !== undefined'>{{COL_FIELD CUSTOM_FILTERS}}</div>", headerCellTemplate: myHeader, width: '110' });
264 } else if(column === 'web') {
265 $scope.gridOptions.columnDefs.push({ 'name' : column, 'displayName': column, width: '80',
266 'cellTemplate': "<div ng-if='row.entity._id != undefined' class=\"ui-grid-cell-contents center\">"+
267 "<span class=\"glyphicon glyphicon-ok\" ng-show=\"row.entity.type === 'VulnerabilityWeb'\"></span>"+
268 "<span class=\"glyphicon glyphicon-remove\" ng-show=\"row.entity.type !== 'VulnerabilityWeb'\"></span>"+
269 "</div>",
270 headerCellTemplate: myHeader
271 });
272 } else if(column === 'desc') {
273 $scope.gridOptions.columnDefs.push({ 'name' : column, headerCellTemplate: myHeader,
274 cellTemplate: '<div><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 overflow-cell white-space" uib-tooltip=\"{{grid.appScope.ifTooltip(COL_FIELD)}}\">{{COL_FIELD CUSTOM_FILTERS}}</div></div>',
275 minWidth: '300',
276 maxWidth: '400'
277 });
278 } else if(column === 'data' || column === 'resolution' || column === 'request' || column === 'response') {
279 $scope.gridOptions.columnDefs.push({ 'name' : column, headerCellTemplate: myHeader,
280 cellTemplate: '<div><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" uib-tooltip="{{COL_FIELD}}">{{COL_FIELD CUSTOM_FILTERS}}</div></div>'
281 });
282 } else {
283 $scope.gridOptions.columnDefs.push({ 'name' : column, headerCellTemplate: myHeader,
284 cellTemplate: '<div ng-if="row.entity._id != undefined"><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" uib-tooltip="{{COL_FIELD}}"><a href=' + $scope.hash + '/search/{{col.name}}={{grid.appScope.encodeUrl(row.entity[col.name])}}>{{COL_FIELD CUSTOM_FILTERS}}</a></div></div><div ng-if=\"row.groupHeader && col.grouping.groupPriority !== undefined\" class="ui-grid-cell-contents white-space">{{COL_FIELD CUSTOM_FILTERS}}</div>', });
285318 }
286319 };
287320
318351 $scope.selected = false;
319352 }
320353 };
321
354
322355 $scope.processReference = function(text) {
323356 var url = 'http://google.com/',
324357 url_pattern = new RegExp('^(http|https):\\/\\/?');
346379 } else {
347380 url += 'search?q=' + text;
348381 }
349
382
350383 return url;
351384 };
352385
507540 });
508541 modal.result.then(function(data) {
509542 vulnsManager.updateVuln(vulns[0], data).then(function(){
543 $scope.filterVulns();
510544 }, function(errorMsg){
511545 showMessage("Error updating vuln " + vulns[0].name + " (" + vulns[0]._id + "): " + errorMsg);
512546 });
513
514547 });
515548 } else {
516549 showMessage('A vulnierabilty must be selected in order to edit');
545578 }
546579
547580 vulnsManager.updateVuln(vuln, obj).then(function(vulns){
581 $scope.filterVulns();
548582 }, function(errorMsg){
549583 // TODO: show errors somehow
550584 console.log("Error updating vuln " + vuln._id + ": " + errorMsg);
552586 });
553587 });
554588 }
555
589
590 $scope.filterVulns = function() {
591 tmp_data = $filter('orderObjectBy')(vulnsManager.vulns, $scope.propertyGroupBy, true);
592 $scope.gridOptions.data = $filter('filter')(tmp_data, $scope.expression);
593 };
594
556595 $scope.editSeverity = function() {
557596 editProperty(
558597 'scripts/commons/partials/editOptions.html',
688727 references.push(ref);
689728 }
690729 });
691 data.refs = references;
730 data.refs = references;
692731
693732 vulnsManager.updateVuln(vuln, data).then(function(vulns){
694733 }, function(errorMsg){
834873
835874 $location.path(url);
836875 };
837
876
838877 // toggles column show property
839878 $scope.toggleShow = function(column, show) {
840879 column = column.toLowerCase();
841880 $scope.columns[column] = !show;
842881 for (i = 0;i < $scope.gridOptions.columnDefs.length; i++) {
843 if($scope.gridOptions.columnDefs[i].name === column) {
844 $scope.gridOptions.columnDefs.splice(i, 1);
845 } else {
846 if(show === false) {
847 _addColumn(column);
848 break;
849 }
882 if($scope.gridOptions.columnDefs[i].name === column || $scope.gridOptions.columnDefs[i].displayName === column) {
883 $scope.gridOptions.columnDefs[i].visible = !$scope.gridOptions.columnDefs[i].visible;
884 $scope.gridApi.grid.refresh();
850885 }
851886 }
852887 $cookies.put('SRcolumns', JSON.stringify($scope.columns));
6262 </ul>
6363 </div>
6464 <div id="group-by" class="btn-group btn-small-margin">
65 <button type="button" class="btn btn-default" title="Group by" ng-click="clearGroupBy()">
66 {{ !propertyGroupBy ? "Group By" : "Clear"}}
65 <button type="button" ng-if="propertyGroupBy" class="btn btn-danger" title="Clear" ng-click="clearGroupBy()">
66 <i class="fa fa-times"></i>
67 </button>
68 <button type="button" class="btn btn-default" title="{{propertyGroupBy || 'Group By'}}" >
69 {{ (propertyGroupBy | uppercase) || "Group By"}}
6770 </button>
6871 <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" title="Group By">
6972 <span class="caret"></span>
7073 </button>
7174 <ul class="dropdown-menu dropdown-menu-right" role="menu">
72 <li ng-repeat="column in colProperties"><a class="ws" ng-click="groupBy(column)">{{column}}</a></li>
75 <li ng-repeat="(column, show) in columns">
76 <a class="ws" ng-show="show && (column !== 'evidence' && column !== 'impact' && column !== 'web' && column !== 'easeofresolution' && column !== 'date')" ng-click="groupBy(column)">{{column}}</a>
77 </li>
7378 </ul>
7479 </div>
7580 <button id="new" type="button" class="btn btn-success" title="New Vulns" ng-click="new()">
0 <div ng-if="row.entity._id != undefined"><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">{{COL_FIELD * 1000 | date:"MM/dd/yyyy"}}</div></div><div ng-if="row.groupHeader && col.grouping.groupPriority !== undefined" class="ui-grid-cell-contents white-space">{{COL_FIELD.split(" ")[0] * 1000 | date:"MM/dd/yyyy"}}</div>
0 <div ng-if="row.entity._id != undefined"><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" uib-tooltip="{{COL_FIELD}}"><a href='{{grid.appScope.hash}}/search/{{col.name}}={{grid.appScope.encodeUrl(row.entity[col.name])}}'>{{COL_FIELD CUSTOM_FILTERS}}</a></div></div><div ng-if="row.groupHeader && col.grouping.groupPriority !== undefined" class="ui-grid-cell-contents white-space">{{COL_FIELD.split("(")[0] !== " " ? COL_FIELD : "EMPTY" + COL_FIELD}}</div>
0 <div><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 overflow-cell white-space" uib-tooltip="{{grid.appScope.ifTooltip(COL_FIELD)}}">{{COL_FIELD CUSTOM_FILTERS}}</div></div>
0 <div class="ui-grid-cell-contents center overflow-cell">
1 <p ng-repeat="(key, value) in COL_FIELD" class='pos-middle crop-text'><a href='{{grid.appScope.baseurl}}{{grid.appScope.workspace}}/{{row.entity._id}}/{{key | encodeURIComponent}}' target='_blank'>{{key | decodeURIComponent}}</a></p>
2 </div>
3 <div ng-if="row.groupHeader && col.grouping.groupPriority !== undefined">{{COL_FIELD CUSTOM_FILTERS}}</div>
0 <div ng-if="row.entity._id != undefined">
1 <div class="ui-grid-cell-contents center">
2 <p ng-repeat="hostname in COL_FIELD"><a href='//www.shodan.io/search?query={{hostname}}' class="pos-middle crop-text" uib-tooltip="Search in Shodan" target="_blank"><img src="../././reports/images/shodan.png" height="15px" width="15px" style="margin-left:5px"/></a><a href="{{grid.appScope.hash}}/search/hostnames={{hostname}}">{{hostname}}</a></p>
3 </div>
4 </div>
5 <div ng-if="row.groupHeader && col.grouping.groupPriority !== undefined" class="ui-grid-cell-contents white-space">{{COL_FIELD.split('(')[0] !== ' ' ? COL_FIELD : 'EMPTY' + COL_FIELD}}</div>
0 <div ng-if="row.entity._id != undefined">
1 <div class="ui-grid-cell-contents center">
2 <p ng-repeat="(key, value) in COL_FIELD" class='pos-middle crop-text' ng-if='value === true'>{{key}}</p>
3 </div>
4 </div>
5 <div ng-if="row.groupHeader && col.grouping.groupPriority !== undefined" class="ui-grid-cell-contents white-space">{{COL_FIELD.split('(')[0] !== ' ' ? COL_FIELD : 'EMPTY' + COL_FIELD}}</div>
0 <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" uib-tooltip="{{COL_FIELD}}"><a ng-href="{{grid.appScope.hash}}/search/name={{grid.appScope.encodeUrl(row.entity.name)}}">{{COL_FIELD CUSTOM_FILTERS}}</a></div>
2 </div>
3 <div ng-if="row.groupHeader && col.grouping.groupPriority !== undefined" class="ui-grid-cell-contents white-space">{{COL_FIELD CUSTOM_FILTERS}}</div>
0 <div ng-if="row.entity._id != undefined">
1 <div class="ui-grid-cell-contents center overflow-cell">
2 <p ng-repeat="ref in COL_FIELD" class='pos-middle crop-text'><a href='{{grid.appScope.processReference(ref)}}' target="_blank">{{ref}}</a></p>
3 </div>
4 </div>
5 <div ng-if="row.groupHeader && col.grouping.groupPriority !== undefined" class="ui-grid-cell-contents white-space">{{COL_FIELD.split('(')[0] !== ' ' ? COL_FIELD : 'EMPTY' + COL_FIELD}}</div>
0 <div><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" uib-tooltip="{{COL_FIELD}}">{{COL_FIELD.split("(")[0] !== " " ? COL_FIELD : "EMPTY" + COL_FIELD}}</div></div>
0 <div ng-if="row.entity._id != undefined"><div class='ui-grid-cell-contents'><a href="{{grid.appScope.hash}}/search/service={{grid.appScope.encodeUrl(row.entity.service)}}">{{COL_FIELD CUSTOM_FILTERS}}</a></div></div><div ng-if='row.groupHeader && col.grouping.groupPriority !== undefined' class='ui-grid-cell-contents white-space'>{{COL_FIELD.split('(')[0] !== ' ' ? COL_FIELD : 'EMPTY' + COL_FIELD}}</div>
0 <div ng-if="row.entity._id != undefined"><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 text-center"><a href="#/status/ws/{{grid.appScope.workspace}}/search/severity={{COL_FIELD}}\"><span class="label vuln fondo-{{COL_FIELD}}">{{COL_FIELD | uppercase}}</span></a></div></div><div ng-if="row.groupHeader && col.grouping.groupPriority !== undefined"><span class="label vuln fondo-{{COL_FIELD}}">{{COL_FIELD | uppercase}}</span></div>
0 <div ng-if='row.entity._id != undefined' class='ui-grid-cell-contents row-tooltip'><a ng-href="{{grid.appScope.hash}}/search/target={{row.entity.target}}">{{COL_FIELD CUSTOM_FILTERS}}</a><a ng-href="//www.shodan.io/search?query={{row.entity.target}}" uib-tooltip="Search in Shodan" target="_blank"><img ng-src="../././reports/images/shodan.png" height="15px" width="15px" style='margin-left:5px'/></a></div><div ng-if="row.groupHeader && col.grouping.groupPriority !== undefined" class="ui-grid-cell-contents white-space">{{COL_FIELD CUSTOM_FILTERS}}</div>
0 <div ng-if='row.entity._id != undefined' class="ui-grid-cell-contents center"><span class="glyphicon glyphicon-ok" ng-show="row.entity.type === 'VulnerabilityWeb'"></span><span class="glyphicon glyphicon-remove" ng-show="row.entity.type !== 'VulnerabilityWeb'"></span></div>
0 <div ng-if="row.entity._id != undefined" class="ui-grid-cell-contents row-tooltip text-center">
1 <span ng-click="grid.appScope.toggleConfirmVuln(row.entity, row.entity.confirmed)" class="glyphicon glyphicon-filter cursor" uib-tooltip="{{grid.appScope.confirmedTooltip(row.entity.confirmed)}}" tooltip-placement="right" ng-class="{ disabled:row.entity.confirmed === false }"></span>
2 </div>
0 <div ng-if="row.entity._id != undefined" class="ui-grid-cell-contents row-tooltip text-center">
1 <span ng-click="grid.appScope.deleteVuln(row.entity)" class="glyphicon glyphicon-trash cursor" uib-tooltip="Delete"></span>
2 </div>
0 <div ng-if="row.entity._id != undefined" class="ui-grid-cell-contents row-tooltip text-center">
1 <span ng-click="grid.appScope.editVuln(row.entity)" class="glyphicon glyphicon-pencil cursor" uib-tooltip="Edit"></span>
2 </div>
44 angular.module('faradayApp')
55 .factory('WebVuln', ['Vuln', 'BASEURL', '$http', function(Vuln, BASEURL, $http) {
66 WebVuln = function(ws, data) {
7 Vuln.call(this, data);
78 if(data) {
89 if(data.name === undefined || data.name === "") {
910 throw new Error("Unable to create Vuln without a name");
1718 'request', 'response', 'website'
1819 ];
1920
20 WebVuln.prototype = new Vuln();
21 WebVuln.prototype = Object.create(Vuln.prototype);
2122
2223 WebVuln.prototype.public_properties = Vuln.prototype.public_properties.concat(public_properties);
2324
5859 return vuln;
5960 };
6061
62 WebVuln.prototype.constructor = WebVuln;
63
6164 return WebVuln;
6265 }]);
7575 };
7676
7777 workspacesFact.exists = function(workspace_name) {
78 var deferred = $q.defer();
7879 var request = {
7980 method: 'HEAD',
8081 url: BASEURL + workspace_name
8182 };
82 var exists_workspace = false;
83 return $http(request).success(function(data) {
84 exists_workspace = true;
85 });
83 $http(request).success(function(data) {
84 deferred.resolve(true);
85 })
86 .error(function() {
87 deferred.resolve(false);
88 });
89 return deferred.promise;
8690 };
8791
8892 errorHandler = function(response) {