Codebase list python-faraday / fa6a584
Imported Upstream version 1.0.22 Sophie Brun 7 years ago
25 changed file(s) with 1395 addition(s) and 863 deletion(s). Raw diff Collapse all Expand all
2222 * Ronald Iraheta
2323 * Thierry Beauquier
2424 * Brice Samulenok
25 * Ulisses Albuquerque
88
99 New features in the latest update
1010 =====================================
11
12 Jul 1, 2016:
13 ---
14 * GTK is the default interface now.
15 * Added new plugin : Ndiff.
16 * Added new plugin : Netcat (Gnu netcat - OpenBSD netcat - Original netcat)
17 * Added button to edit your host in the GTK interface.
18 * Hosts sidebar now can be sorted by amout of vulnerabilities and OS.
19 * Changes in installation: install.sh now installs only GTK, QT is considered deprecated.
20 * Changes in installation: Faraday now runs with the last versions of Python modules.
21 * Changes in installation: fixed names of packages in setup_server.sh
22 * Usability: Enter key in GTK dialogs works as OK button
23 * Improved handling of lost connection to CouchDB database
24 * First steps towards deprecating Filesystem databases
25 * Fixed a bug when workspace was changed
26 * Fixed a bug with Import Reports Dialog in GTK GUI on OS X.
27 * Fixed a bug with Ctrl+Shift+C and Ctrl+Shift+V in some desktops managers.
28 * Fixed a bug with mapper of vulnerabilities.
1129
1230 Jun 13, 2016:
1331 ---
0 1.0.21
0 1.0.22
11 <faraday>
22
33 <appname>Faraday - Penetration Test IDE</appname>
4 <version>1.0.21</version>
4 <version>1.0.22</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>
5959 elif (change.getChangeType() != CHANGETYPE.UNKNOWN):
6060 model.guiapi.notification_center.editHost(host)
6161
62 def manageConnectionLost(self):
63 """All it does is send a notification to the notification center"""
64 model.guiapi.notification_center.CouchDBConnectionProblem()
65
6266 def watch(self, mapper, dbConnector):
6367 self.mapper_manager = mapper
6468 self.dbConnector = dbConnector
6569 self.changesWatcher = ChangeWatcher(dbConnector.waitForDBChange)
6670 dbConnector.setChangesCallback(self.loadChange)
71 dbConnector.setCouchExceptionCallback(self.manageConnectionLost)
6772 self.changesWatcher.start()
6873
6974 def unwatch(self):
139139 help="Path to the valid CouchDB certificate")
140140
141141 parser.add_argument('--gui', action="store", dest="gui",
142 default="qt3",
142 default="gtk",
143143 help="Select interface to start faraday. Supported values are "
144 "qt3 (deprecated), gtk and 'no' (no GUI at all). Defaults to qt3")
144 "qt3 (deprecated), gtk and 'no' (no GUI at all). Defaults to GTK")
145145
146146 parser.add_argument('--cli', action="store_true",
147147 dest="cli",
220220 if not line.find('#'):
221221 break
222222 else:
223 modules.append([line[:line.index('=')], (line[line.index('=')+2:]).strip()])
223 modules.append(line.strip('\n'))
224224 f.close()
225225 pip_dist = [dist.project_name.lower() for dist in pip.get_installed_distributions()]
226
227226 for module in modules:
228 if module[0].lower() not in pip_dist:
227 if module.lower() not in pip_dist:
229228 try:
230 __import__(module[0])
229 __import__(module)
231230 except ImportError:
232231 if query_user_bool("Missing module %s."
233 " Do you wish to install it?" % module[0]):
234 pip.main(['install', "%s==%s" %
235 (module[0], module[1]), '--user'])
232 " Do you wish to install it?" % module):
233 pip.main(['install', "%s" %
234 module, '--user'])
236235
237236 else:
238237 return False
455454 shutil.copytree(FARADAY_BASE_IMAGES, FARADAY_USER_IMAGES)
456455
457456
458 def checkConfiguration():
457 def checkConfiguration(gui_type):
459458 """Checks if the environment is ready to run Faraday.
460459
461460 Checks different environment requirements and sets them before starting
462461 Faraday. This includes checking for plugin folders, libraries, QT
463462 configuration and ZSH integration.
464463 """
465
466464 logger.info("Checking configuration.")
467465 logger.info("Setting up plugins.")
468466 setupPlugins(args.dev_mode)
469 logger.info("Setting up Qt configuration.")
470 setupQtrc()
467 if gui_type == "qt3":
468 logger.info("Setting up Qt configuration.")
469 setupQtrc()
471470 logger.info("Setting up ZSH integration.")
472471 setupZSH()
473472 logger.info("Setting up user configuration.")
474473 setupXMLConfig()
475474 logger.info("Setting up libraries.")
476475 setupLibs()
477 logger.info("Setting up icons for QT interface.")
478 setupImages()
476 if gui_type == "qt3":
477 logger.info("Setting up icons for QT interface.")
478 setupImages()
479479
480480
481481 def setupFolders(folderlist):
617617 Main function for launcher.
618618
619619 """
620
621620 os.chdir(FARADAY_BASE)
622621
623622 init()
626625 logger.info("Dependencies met.")
627626 if args.cert_path:
628627 os.environ[REQUESTS_CA_BUNDLE_VAR] = args.cert_path
629 checkConfiguration()
628 checkConfiguration(args.gui)
630629 setConf()
631630 checkCouchUrl()
632631 checkVersion()
2929 EDITHOST = 4102
3030 CHANGEFROMINSTANCE = 5100
3131 UPDATEMODEL_ID = 54321
32 CONNECTION_REFUSED = 42424
3233
3334
3435 class CustomEvent(object):
7273 if error_name is not None:
7374 self.error_name = error_name
7475
76 # this is probably a bad name for the class
77 # maybe ConnectionRefusedCustomEven would've been better
78 class ShowExceptionConnectionRefusedCustomEvent(CustomEvent):
79 def __init__(self, problem=None):
80 CustomEvent.__init__(self, CONNECTION_REFUSED)
81 self.problem = problem
7582
7683
7784 class RenameHostsRootCustomEvent(CustomEvent):
4141 from gui.gui_app import FaradayUi
4242 from config.configuration import getInstanceConfiguration
4343 from utils.logs import getLogger
44 from persistence.persistence_managers import CouchDbManager
4445 from appwindow import AppWindow
4546
4647 from dialogs import PreferenceWindowDialog
4950 from dialogs import NotificationsDialog
5051 from dialogs import aboutDialog
5152 from dialogs import helpDialog
52 from dialogs import ImportantErrorDialog
5353 from dialogs import ConflictsDialog
5454 from dialogs import HostInfoDialog
5555 from dialogs import errorDialog
56 from dialogs import ImportantErrorDialog
5657
5758 from mainwidgets import Sidebar
5859 from mainwidgets import WorkspaceSidebar
6364
6465 from gui.loghandler import GUIHandler
6566 from utils.logs import addHandler
67 from utils.common import checkSSL
6668
6769 CONF = getInstanceConfiguration()
6870
112114 def updateHosts(self):
113115 """Reassings the value of self.all_hosts to a current one to
114116 catch workspace changes, new hosts added via plugins or any other
115 external interference with out host list"""
117 external interference with our host list"""
116118 self.all_hosts = self.model_controller.getAllHosts()
119 return self.all_hosts
117120
118121 def createWorkspace(self, name, description="", w_type=""):
119122 """Pretty much copy/pasted from the QT3 GUI.
143146
144147 return status
145148
146 def removeWorkspace(self, button, ws_name):
149 def remove_workspace(self, button, ws_name):
147150 """Removes a workspace. If the workspace to be deleted is the one
148151 selected, it moves you first to the default. The clears and refreshes
149152 sidebar"""
155158 self.ws_sidebar.clearSidebar()
156159 self.ws_sidebar.refreshSidebar()
157160
161 def is_workspace_couch(self, workspace_name):
162 """Return if the workspace named workspace_name is associated to a
163 CouchDB.
164 """
165 type_ = self.workspace_manager.getWorkspaceType(workspace_name)
166 if type_ == "CouchDB":
167 is_couch = True
168 else:
169 is_couch = False
170 return is_couch
171
172 def get_active_workspace(self):
173 """Return the currently active workspace"""
174 return self.workspace_manager.getActiveWorkspace()
175
158176 def do_startup(self):
159177 """
160178 GTK calls this method after Gtk.Application.run()
166184 Gtk.Application.do_startup(self) # deep GTK magic
167185
168186 self.ws_sidebar = WorkspaceSidebar(self.workspace_manager,
169 self.changeWorkspace,
170 self.removeWorkspace,
187 self.change_workspace,
188 self.remove_workspace,
171189 self.on_new_button,
172190 CONF.getLastWorkspace())
173191
239257 # Windows are associated with the application
240258 # when the last one is closed the application shuts down
241259 self.window = AppWindow(self.sidebar,
260 self.ws_sidebar,
261 self.hosts_sidebar,
242262 self.terminal,
243263 self.console_log,
244264 self.statusbar,
258278 model.guiapi.notification_center.registerWidget(self.window)
259279
260280 def postEvent(self, receiver, event):
261 """Handles the events from gui/customevents."""
281 """Handles the events from gui/customevents.
282
283 DO NOT, AND I REPEAT, DO NOT REDRAW *ANYTHING* FROM THE GUI
284 FROM HERE. If you must do it, you should to it via the emit method
285 to the appwindow or maybe using Glib.idle_add, a misterious function
286 with outdate documentation."""
287
262288 if receiver is None:
263289 receiver = self.getMainWindow()
264290
277303
278304 elif event.type() == 4100 or event.type() == 3140: # newinfo or changews
279305 host_count, service_count, vuln_count = self.update_counts()
280 self.updateHosts()
281 self.hosts_sidebar.update(self.all_hosts)
282 receiver.emit("update_ws_info", host_count,
283 service_count, vuln_count)
306 self.window.receive_hosts(self.updateHosts())
307 receiver.emit("update_hosts_sidebar")
308 receiver.emit("update_ws_info", host_count, service_count, vuln_count)
284309
285310 elif event.type() == 3132: # error
286311 self.window.emit("normal_error", event.text)
287312
288313 elif event.type() == 3134: # important error, uncaught exception
289 self.window.prepare_important_error(event)
314 GObject.idle_add(self.window.prepare_important_error, event)
290315 self.window.emit("important_error")
316
317 elif event.type() == 42424: # lost connection to couch db
318 GObject.idle_add(self.window.prepare_important_error, event,
319 self.handle_connection_lost)
320
321 self.window.emit("lost_db_connection", event.problem)
322 self.change_to_default_ws_on_connection_lost()
323
324 def change_to_default_ws_on_connection_lost(self):
325 """Reloads the workspace and opens the default ws"""
326 ws = self.openDefaultWorkspace()
327 self.reloadWorkspaces()
328 CONF.setLastWorkspace(ws.name)
329 CONF.saveConfig()
330
331 def connect_to_couch(self, couch_uri):
332 """Tries to connect to a CouchDB on a specified Couch URI.
333 Returns the success status of the operation, False for not successful,
334 True for successful
335 """
336
337 if not CouchDbManager.testCouch(couch_uri):
338 errorDialog(self.window, "Could not connect to CouchDB.",
339 ("Are you sure it is running and that you can "
340 "connect to it? \n Make sure your username and "
341 "password are still valid."))
342 success = False
343 elif couch_uri.startswith("https://"):
344 if not checkSSL(couch_uri):
345 errorDialog(self.window,
346 "The SSL certificate validation has failed")
347 success = False
348 else:
349 CONF.setCouchUri(couch_uri)
350 CONF.saveConfig()
351 self.reloadWorkspaces()
352 success = True
353 return success
354
355 def handle_connection_lost(self, button=None, dialog=None):
356 """Tries to connect to Couch using the same URI"""
357 couch_uri = CONF.getCouchURI()
358 if self.connect_to_couch(couch_uri):
359 if dialog is not None:
360 dialog.destroy()
361 reconnected = True
362 else:
363 reconnected = False
364 return reconnected
291365
292366 def update_counts(self):
293367 """Update the counts for host, services and vulns"""
310384 dialog = Gtk.Dialog("Select plugin", self.window, 0)
311385
312386 combo_box = Gtk.ComboBoxText()
387 combo_box.set_wrap_width(3)
313388 for plugin_id in plugins_id:
314389 combo_box.append_text(plugin_id)
315390 combo_box.show()
316391
317 dialog.vbox.pack_start(combo_box, True, True, 10)
392 dialog.vbox.pack_start(combo_box, False, True, 10)
318393
319394 dialog.add_button("Cancel", Gtk.ResponseType.DELETE_EVENT)
320395 dialog.add_button("OK", Gtk.ResponseType.ACCEPT)
338413 plugin_response, plugin_id = select_plugin()
339414 else:
340415 if plugin_response == Gtk.ResponseType.ACCEPT:
341 dialog = Gtk.FileChooserNative()
342 dialog.set_title("Import a report")
416 dialog = Gtk.FileChooserDialog(title="Import a report",
417 parent=self.window,
418 action=Gtk.FileChooserAction.OPEN,
419 buttons=("Open", Gtk.ResponseType.ACCEPT,
420 "Cancel", Gtk.ResponseType.CANCEL)
421 )
343422 dialog.set_modal(True)
344 dialog.set_transient_for(self.window)
345 dialog.set_action(Gtk.FileChooserAction.OPEN)
346423
347424 res = dialog.run()
348425 if res == Gtk.ResponseType.ACCEPT:
351428
352429 def on_about(self, action, param):
353430 """ Defines what happens when you press 'about' on the menu"""
354
355431 about_dialog = aboutDialog(self.window)
356432 about_dialog.run()
357433 about_dialog.destroy()
358434
359435 def on_help(self, action, param):
360436 """Defines what happens when user press 'help' on the menu"""
361
362437 help_dialog = helpDialog(self.window)
363438 help_dialog.run()
364439 help_dialog.destroy()
370445 new workspaces available"""
371446
372447 preference_window = PreferenceWindowDialog(self.reloadWorkspaces,
448 self.connect_to_couch,
373449 self.window)
374450 preference_window.show_all()
375451
376452 def show_host_info(self, host_id):
377453 """Looks up the host selected in the HostSidebar by id and shows
378454 its information on the HostInfoDialog"""
455 current_ws_name = self.get_active_workspace().name
456 is_ws_couch = self.is_workspace_couch(current_ws_name)
379457
380458 for host in self.all_hosts:
381459 if host_id == host.id:
382460 selected_host = host
383461 break
384462
385 info_window = HostInfoDialog(self.window, selected_host)
463 info_window = HostInfoDialog(self.window, current_ws_name,
464 is_ws_couch, selected_host)
386465 info_window.show_all()
387466
388467 def reloadWorkspaces(self):
413492 instance of the Terminal and tells the window to add it as a new tab
414493 for the notebook"""
415494 new_terminal = Terminal(CONF)
416 the_new_terminal = new_terminal.getTerminal()
417 AppWindow.new_tab(self.window, the_new_terminal)
495 terminal_scrolled = new_terminal.getTerminal()
496 self.window.new_tab(terminal_scrolled)
418497
419498 def on_click_notifications(self, button):
420499 """Defines what happens when the user clicks on the notifications
456535 self.notificationsModel.clear()
457536 self.window.emit("clear_notifications")
458537
459 def changeWorkspace(self, workspaceName):
538 def change_workspace(self, workspaceName):
460539 """Changes workspace in a separate thread. Emits a signal
461540 to present a 'Loading workspace' dialog while Faraday processes
462541 the change"""
463542
464543 def background_process():
544 """Change workspace. This function runs on a separated thread
545 created by the parent function. DO NOT call any Gtk methods
546 withing its scope, except by emiting signals to the window
547 """
465548 self.window.emit("loading_workspace", 'show')
466549 try:
467550 ws = super(GuiApp, self).openWorkspace(workspaceName)
551 self.window.emit("loading_workspace", "destroy")
468552 except Exception as e:
469553 model.guiapi.notification_center.showDialog(str(e))
470554 ws = self.openDefaultWorkspace()
555 self.window.emit("loading_workspace", "destroy")
471556
472557 workspace = ws.name
473558 CONF.setLastWorkspace(workspace)
474559 CONF.saveConfig()
475 self.window.emit("loading_workspace", "destroy")
476560
477561 return True
478562
4444 "update_ws_info": (GObject.SIGNAL_RUN_FIRST, None, (int, int, int, )),
4545 "set_conflict_label": (GObject.SIGNAL_RUN_FIRST, None, (int, )),
4646 "loading_workspace": (GObject.SIGNAL_RUN_FIRST, None, (str, )),
47 "lost_db_connection": (GObject.SIGNAL_RUN_FIRST, None, (str,)),
48 "update_hosts_sidebar": (GObject.SIGNAL_RUN_FIRST, None, ()),
4749 "normal_error": (GObject.SIGNAL_RUN_FIRST, None, (str, )),
4850 "important_error": (GObject.SIGNAL_RUN_FIRST, None, ()),
4951 }
5052
51 def __init__(self, sidebar, terminal, console_log, statusbar,
52 *args, **kwargs):
53 def __init__(self, sidebar, ws_sidebar, hosts_sidebar, terminal,
54 console_log, statusbar, *args, **kwargs):
5355 super(Gtk.ApplicationWindow, self).__init__(*args, **kwargs)
5456
5557 # This will be in the windows group and have the "win" prefix
6163 self.maximize()
6264
6365 self.sidebar = sidebar
66 self.ws_sidebar = ws_sidebar
67 self.hosts_sidebar = hosts_sidebar
6468 self.terminal = terminal
6569 self.log = console_log
6670 self.statusbar = statusbar
124128 self.tab_number = 0 # 0 indexed, even when it shows 1 to the user
125129
126130 self.show_all()
131
132 def receive_hosts(self, hosts):
133 """Attaches the hosts to an object value, so it can be used by
134 do_update_hosts_sidebar, a signal. GTK won't alow anything
135 more than primitive names to be passed on by signals"""
136 self.current_hosts = hosts
137
138 def do_update_hosts_sidebar(self):
139 self.hosts_sidebar.update(self.current_hosts)
127140
128141 def terminalBox(self, terminal):
129142 """Given a terminal, creates an EventBox for the Box that has as a
180193 currentTerminal = currentScrolledWindow.get_child()
181194 return currentTerminal
182195
183 def prepare_important_error(self, event):
196 def prepare_important_error(self, event, *callbacks):
184197 """Attaches an event to the class, so it can be used by the signal
185198 callbacks even if they cannot be passed directly.
186199 """
187200 self.event = event
201 self.error_callbacks = callbacks
188202
189203 def do_important_error(self):
190204 """Creates an importan error dialog with a callback to send
195209 response = dialog.run()
196210 if response == 42:
197211 error = self.event.error_name
198 event.callback(error, *self.event.exception_objects)
212 self.event.callback(error, *self.event.exception_objects)
199213 dialog.destroy()
200214
201215 def do_normal_error(self, dialog_text):
207221 dialog.run()
208222 dialog.destroy()
209223
224 def do_lost_db_connection(self, explanatory_message):
225 """Creates a simple dialog with an error message to inform the user
226 some kind of problem has happened and the connection was lost.
227 Uses the first callback on self.error_callbacks, which should
228 point to the application's handle_connection_lost method.
229 """
230
231 def destroy_dialog(button=None):
232 """Necessary 'cause button.connect method passes the button
233 as a paramether even when I don't need it.
234 """
235 dialog.destroy()
236
237 handle_connection_lost = self.error_callbacks[0]
238 if explanatory_message:
239 explanation = "\n The specific error was: " + explanatory_message
240 else:
241 explanation = ""
242
243 dialog = Gtk.MessageDialog(self, 0,
244 Gtk.MessageType.ERROR,
245 Gtk.ButtonsType.NONE,
246 "Faraday has lost connection to CouchDB. "
247 "The program has reverted back to the "
248 "filesystem database. Fix the connection "
249 "and re-enter the CouchDB URL in the "
250 "preferences settings." + explanation)
251 dialog.set_modal(True)
252
253 retry_button = dialog.add_button("Retry connection?", 42)
254 retry_button.connect("clicked", handle_connection_lost, dialog)
255
256 cancel_button = dialog.add_button("Cancel", 0)
257 cancel_button.connect("clicked", destroy_dialog)
258
259 dialog.run()
260
210261 def do_new_log(self, text):
211262 """To be used on a new_log signal. Calls a method on log to append
212263 to it"""
325376 return toolbar
326377
327378 def new_tab(self, scrolled_window):
328 """The on_new_terminal_button redirects here. Tells the window
329 to create pretty much a clone of itself when the user wants a new
330 tab"""
379 """The on_new_terminal_button redirects here from the application.
380 The scrolled_window will be a scrolled window containing only a VTE
381 terminal.
382 """
331383
332384 terminal = scrolled_window.get_children()[0]
333385 terminal.connect("child_exited", self.on_terminal_exit)
334386 self.tab_number += 1
335 tab_number = self.tab_number
336387 pageN = self.terminalBox(scrolled_window)
337 self.notebook.append_page(pageN, Gtk.Label(str(tab_number+1)))
388 self.notebook.append_page(pageN, Gtk.Label(str(self.tab_number+1)))
338389 self.notebook.show_all()
339390
340391 def delete_tab(self, button=None):
382433
383434 def on_terminal_exit(self, terminal, status):
384435 """Really, it is *very* similar to delete_tab, but in this case
385 we want to make sure that we restart Faraday is the user
436 we want to make sure that we restart Faraday if the user
386437 is not sure if he wants to exit"""
387
388438 self.delete_tab()
389439 terminal.startFaraday()
0 from gi.repository import Gtk
1 from functools import wraps
2
3
4 def scrollable(width=-1, height=-1):
5 """A function that takes optinal width and height and returns
6 the scrollable decorator. -1 is the default GTK option for both
7 width and height."""
8
9 def scrollable_decorator(func):
10 """Takes a function and returns the scroll_object_wrapper."""
11
12 @wraps(func)
13 def scroll_object_wrapper(*args, **kwargs):
14 """Takes arguments and obtains the original object from
15 func(*args, **kwargs). Creates a box and puts the original
16 inside that box. Creates a scrolled window and puts the
17 box inside it.
18 """
19
20 box = Gtk.Box()
21 original = func(*args, **kwargs)
22 scrolled_box = Gtk.ScrolledWindow(None, None)
23 scrolled_box.set_min_content_width(width)
24 scrolled_box.set_min_content_height(height)
25 scrolled_box.add(original)
26 box.pack_start(scrolled_box, True, True, 0)
27 return box
28
29 return scroll_object_wrapper
30
31 return scrollable_decorator
77 '''
88 import gi
99 import re
10 import webbrowser
1011
1112 gi.require_version('Gtk', '3.0')
1213
1314 from gi.repository import Gtk, GdkPixbuf, Gdk
1415 from persistence.persistence_managers import CouchDbManager
15 from utils.common import checkSSL
1616 from config.configuration import getInstanceConfiguration
1717 from model import guiapi
18 from decorators import scrollable
1819
1920
2021 CONF = getInstanceConfiguration()
22
2123
2224 class PreferenceWindowDialog(Gtk.Window):
2325 """Sets up a preference dialog with basically nothing more than a
2527 Takes a callback function to the mainapp so that it can refresh the
2628 workspace list and information"""
2729
28 def __init__(self, callback, parent):
30 def __init__(self, reload_ws_callback, connect_to_couch, parent):
2931 Gtk.Window.__init__(self, title="Preferences")
3032 self.parent = parent
3133 self.set_modal(True)
3234 self.set_size_request(400, 100)
3335 self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
34 self.connect("key_press_event", on_scape_destroy)
36 self.connect("key_press_event", key_reactions)
3537 self.set_transient_for(parent)
36 self.timeout_id = None
37 self.reloadWorkspaces = callback
38
39 vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
40 self.add(vbox)
41
42 self.label = Gtk.Label()
43 self.label.set_text("Your Couch IP")
44 vbox.pack_start(self.label, True, False, 10)
38 self.reloadWorkspaces = reload_ws_callback
39 self.connectCouchCallback = connect_to_couch
40
41 main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
42
43 ip_label = Gtk.Label()
44 ip_label.set_text("Your Couch IP")
45 main_box.pack_start(ip_label, True, False, 10)
4546
4647 couch_uri = CONF.getCouchURI()
47 self.entry = Gtk.Entry()
48 self.ip_entry = Gtk.Entry()
4849 text = couch_uri if couch_uri else "http://127.0.0.1:5050"
49 self.entry.set_text(text)
50 vbox.pack_start(self.entry, True, False, 10)
51
52 hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
53 vbox.pack_end(hbox, False, True, 10)
54
55 self.OK_button = Gtk.Button.new_with_label("OK")
56 self.OK_button.connect("clicked", self.on_click_OK)
57
58 hbox.pack_start(self.OK_button, False, True, 10)
59
60 self.cancel_button = Gtk.Button.new_with_label("Cancel")
61 self.cancel_button.connect("clicked", self.on_click_cancel)
62 hbox.pack_end(self.cancel_button, False, True, 10)
63
64 def on_click_OK(self, button):
65 """Defines what happens when user clicks OK button"""
66 repourl = self.entry.get_text()
67 if not CouchDbManager.testCouch(repourl):
68 errorDialog(self, "The provided URL is not valid",
69 "Are you sure CouchDB is running?")
70 elif repourl.startswith("https://"):
71 if not checkSSL(repourl):
72 errorDialog("The SSL certificate validation has failed")
73 else:
74 CONF.setCouchUri(repourl)
75 CONF.saveConfig()
76 self.reloadWorkspaces()
50 self.ip_entry.set_text(text)
51 main_box.pack_start(self.ip_entry, True, False, 10)
52
53 button_box = Gtk.Box(spacing=6)
54 main_box.pack_end(button_box, False, True, 10)
55
56 OK_button = Gtk.Button.new_with_label("OK")
57 OK_button.connect("clicked", self.on_click_ok)
58
59 button_box.pack_start(OK_button, False, True, 10)
60
61 cancel_button = Gtk.Button.new_with_label("Cancel")
62 cancel_button.connect("clicked", self.on_click_cancel)
63 button_box.pack_end(cancel_button, False, True, 10)
64
65 self.add(main_box)
66
67 def on_click_ok(self, button=None):
68 """Button is useless, only there because GTK likes it. Takes the
69 repourl (Couch IP) from self.ip_entry and connect to it if possible.
70 """
71 repourl = self.ip_entry.get_text()
72 if self.connectCouchCallback(repourl): # success!
7773 self.destroy()
7874
79 def on_click_cancel(self, button):
75 def on_click_cancel(self, button=None):
8076 self.destroy()
8177
8278
8581 a description and a type for a new workspace. Also checks that the
8682 those attributes don't correspond to an existing workspace"""
8783
88 def __init__(self, callback, workspace_manager, sidebar, parent,
84 def __init__(self, create_ws_callback, workspace_manager, sidebar, parent,
8985 title=None):
9086
9187 Gtk.Window.__init__(self, title="Create New Workspace")
9288 self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
9389 self.set_transient_for(parent)
9490 self.set_modal(True)
95 self.connect("key_press_event", on_scape_destroy)
91 self.connect("key_press_event", key_reactions)
9692 self.set_size_request(200, 200)
97 self.timeout_id = None
98 self.callback = callback
93 self.create_ws_callback = create_ws_callback
9994 self.sidebar = sidebar
100
101 self.mainBox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
102
103 self.nameBox = Gtk.Box(spacing=6)
104 self.name_label = Gtk.Label()
105 self.name_label.set_text("Name: ")
95 self.workspace_manager = workspace_manager
96 self.title = title
97
98 self.warning_label = self.create_warning_label()
99 self.main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
100
101 name_box = self.create_name_box()
102 description_box = self.create_description_box()
103 type_box = self.create_type_box()
104 button_box = self.create_button_box()
105
106 self.main_box.pack_start(name_box, False, False, 10)
107 self.main_box.pack_start(description_box, False, False, 10)
108 self.main_box.pack_start(type_box, False, False, 10)
109 self.main_box.pack_start(self.warning_label, False, False, 10)
110 self.main_box.pack_end(button_box, False, False, 10)
111
112 self.main_box.show()
113 self.add(self.main_box)
114
115 def create_name_box(self):
116 """Return a box with a Name label left of an entry."""
117 name_box = Gtk.Box(spacing=6)
118 name_label = Gtk.Label()
119 name_label.set_text("Name: ")
106120 self.name_entry = Gtk.Entry()
107 if title is not None:
121 if self.title is not None:
108122 self.name_entry.set_text(title)
109 self.nameBox.pack_start(self.name_label, False, False, 10)
110 self.nameBox.pack_end(self.name_entry, True, True, 10)
111 self.nameBox.show()
112
113 self.descrBox = Gtk.Box(spacing=6)
114 self.descr_label = Gtk.Label()
115 self.descr_label.set_text("Description: ")
116 self.descr_entry = Gtk.Entry()
117 self.descrBox.pack_start(self.descr_label, False, False, 10)
118 self.descrBox.pack_end(self.descr_entry, True, True, 10)
119 self.descrBox.show()
120
121 self.typeBox = Gtk.Box(spacing=6)
122 self.type_label = Gtk.Label()
123 self.type_label.set_text("Type: ")
124 self.comboBox = Gtk.ComboBoxText()
125 for w in workspace_manager.getAvailableWorkspaceTypes():
126 self.comboBox.append_text(w)
127 self.typeBox.pack_start(self.type_label, False, False, 10)
128 self.typeBox.pack_end(self.comboBox, True, True, 10)
129 self.typeBox.show()
130
131 self.buttonBox = Gtk.Box(spacing=6)
132 self.OK_button = Gtk.Button.new_with_label("OK")
133 self.OK_button.connect("clicked", self.on_click_OK)
134 self.cancel_button = Gtk.Button.new_with_label("Cancel")
135 self.cancel_button.connect("clicked", self.on_click_cancel)
136 self.buttonBox.pack_start(self.OK_button, False, False, 10)
137 self.buttonBox.pack_end(self.cancel_button, False, False, 10)
138 self.buttonBox.show()
139
140 self.mainBox.pack_start(self.nameBox, False, False, 10)
141 self.mainBox.pack_start(self.descrBox, False, False, 10)
142 self.mainBox.pack_start(self.typeBox, False, False, 10)
143 self.mainBox.pack_end(self.buttonBox, False, False, 10)
144
145 self.mainBox.show()
146 self.add(self.mainBox)
147
148 def on_click_OK(self, button):
123 name_box.pack_start(name_label, False, False, 10)
124 name_box.pack_end(self.name_entry, True, True, 10)
125 return name_box
126
127 def create_description_box(self):
128 """Return a box with a Description label left of an entry."""
129 description_box = Gtk.Box(spacing=6)
130 description_label = Gtk.Label()
131 description_label.set_text("Description: ")
132 self.description_entry = Gtk.Entry()
133 description_box.pack_start(description_label, False, False, 10)
134 description_box.pack_end(self.description_entry, True, True, 10)
135 return description_box
136
137 def create_type_box(self):
138 """Return a box with a Type label left of a combo box"""
139 type_box = Gtk.Box(spacing=6)
140 type_label = Gtk.Label()
141 type_label.set_text("Type: ")
142 self.type_comboBox = Gtk.ComboBoxText()
143 self.type_comboBox.connect("changed", self.on_select_ws_type)
144 for w in self.workspace_manager.getAvailableWorkspaceTypes():
145 self.type_comboBox.append_text(w)
146 self.type_comboBox.set_active(0)
147 type_box.pack_start(type_label, False, False, 10)
148 type_box.pack_end(self.type_comboBox, True, True, 10)
149 return type_box
150
151 def create_warning_label(self):
152 """Return a label with a warning if the user has FS selected as the
153 desired WS type.
154 """
155 warning_label = Gtk.Label()
156 warning_label.set_no_show_all(True)
157 warning_label.set_markup("<b>WARNING: </b> The FS (Filesystem) "
158 "databases are deprecated and strongly "
159 "discouraged. \n You will <b>not</b> be able "
160 "to edit the information provided by Faraday "
161 "with a FileSystem DB. \n Please "
162 "set up CouchDB and use it as the database "
163 "for your workspaces.")
164 return warning_label
165
166 def create_button_box(self):
167 """Return a box with OK and cancel buttons."""
168 button_box = Gtk.Box(spacing=6)
169 OK_button = Gtk.Button.new_with_label("OK")
170 OK_button.connect("clicked", self.on_click_ok)
171 cancel_button = Gtk.Button.new_with_label("Cancel")
172 cancel_button.connect("clicked", self.on_click_cancel)
173 button_box.pack_start(OK_button, False, False, 10)
174 button_box.pack_end(cancel_button, False, False, 10)
175 return button_box
176
177 def on_click_ok(self, button=None):
178 """Check if the name provided for the WS is valid. If so,
179 create it and add it to the sidebar. If not, show error.
180 """
149181 letters_or_numbers = r"^[a-z][a-z0-9\_\$()\+\-\/]*$"
150182 res = re.match(letters_or_numbers, str(self.name_entry.get_text()))
151183 if res:
152 if self.callback is not None:
153 self.__name_txt = str(self.name_entry.get_text())
154 self.__desc_txt = str(self.descr_entry.get_text())
155 self.__type_txt = str(self.comboBox.get_active_text())
156 creation_ok = self.callback(self.__name_txt,
157 self.__desc_txt,
158 self.__type_txt)
159 if creation_ok:
160 self.sidebar.addWorkspace(self.__name_txt)
161 self.destroy()
184 ws_name = str(self.name_entry.get_text())
185 ws_desc = str(self.description_entry.get_text())
186 ws_type = str(self.type_comboBox.get_active_text())
187 creation_ok = self.create_ws_callback(ws_name,
188 ws_desc,
189 ws_type)
190 if creation_ok:
191 self.sidebar.addWorkspace(ws_name)
192 else:
193 errorDialog(self, "Something went wrong when creating "
194 "the new workspace.")
195 self.destroy()
162196 else:
163197 errorDialog(self, "Invalid workspace name",
164198 "A workspace must be named with "
167201 "characters. The name has to start"
168202 " with a lowercase letter")
169203
204 def on_select_ws_type(self, combo_box):
205 if combo_box.get_active_text() == 'FS':
206 self.warning_label.show()
207 else:
208 self.warning_label.hide()
209
170210 def on_click_cancel(self, button):
171211 self.destroy()
172212
184224 self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
185225 self.set_transient_for(parent)
186226 self.set_modal(True)
187 self.connect("key_press_event", on_scape_destroy)
227 self.connect("key_press_event", key_reactions)
188228 self.set_size_request(800, 300)
229 self.plugin_manager = plugin_manager
189230
190231 if plugin_manager is not None:
191232 self.plugin_settings = plugin_manager.getSettings()
198239 self.setSettingsView()
199240
200241 plugin_info = self.createPluginInfo(plugin_manager)
201 pluginList = self.createPluginListView(plugin_info)
202 scroll_pluginList = Gtk.ScrolledWindow(None, None)
203 scroll_pluginList.add(pluginList)
204 scroll_pluginList.set_min_content_width(300)
205 pluginListBox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
206 pluginListBox.pack_start(scroll_pluginList, True, True, 0)
242 plugin_list = self.createPluginListView(plugin_info)
243 left_side_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
244 left_side_box.pack_start(plugin_list, True, True, 0)
207245
208246 buttonBox = Gtk.Box()
209247 OK_button = Gtk.Button.new_with_label("OK")
210248 cancel_button = Gtk.Button.new_with_label("Cancel")
211 OK_button.connect("clicked", self.on_click_OK, plugin_manager)
249 OK_button.connect("clicked", self.on_click_ok)
212250 cancel_button.connect("clicked", self.on_click_cancel)
213251 buttonBox.pack_start(OK_button, True, True, 10)
214252 buttonBox.pack_start(cancel_button, True, True, 10)
215 pluginListBox.pack_start(buttonBox, False, False, 10)
253
254 left_side_box.pack_start(buttonBox, False, False, 10)
216255
217256 infoBox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
218257 nameBox, versionBox, pluginVersionBox = [Gtk.Box() for i in range(3)]
243282 self.pluginSpecsBox.pack_start(self.settings_view, True, True, 0)
244283
245284 self.mainBox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
246 self.mainBox.pack_start(pluginListBox, False, True, 10)
285 self.mainBox.pack_start(left_side_box, False, True, 10)
247286 self.mainBox.pack_end(self.pluginSpecsBox, True, True, 10)
248287
249288 self.add(self.mainBox)
250289
251 def on_click_OK(self, button, plugin_manager):
290 def on_click_ok(self, button=None):
252291 """On click OK button update the plugins settings and then destroy"""
253 if plugin_manager is not None:
254 plugin_manager.updateSettings(self.plugin_settings)
292 if self.plugin_manager is not None:
293 self.plugin_manager.updateSettings(self.plugin_settings)
255294 self.destroy()
256295
257296 def on_click_cancel(self, button):
275314 sorted_plugin_info.set_sort_column_id(1, Gtk.SortType.ASCENDING)
276315 return sorted_plugin_info
277316
317 @scrollable(width=300)
278318 def createPluginListView(self, plugin_info):
279319 """Creates the view for the left-hand side list of the dialog.
280320 It uses an instance of the plugin manager to get a list
383423
384424 class HostInfoDialog(Gtk.Window):
385425 """Sets the blueprints for a simple host info window. It will display
386 basic information in labels as well as interfaces/services in a treeview
426 basic information in labels as well as interfaces/services in a treeview.
427
428 While working in this class, keep in mind the distinction between
429 selections (which are part of a model that holds data about an object as
430 strings and ints) and the object per se, which are in the model folder and
431 are totally alien to GTK.
387432 """
388 def __init__(self, parent, host):
433 def __init__(self, parent, active_ws_name, is_ws_couch, host):
389434 """Creates a window with the information about a given hosts.
390435 The parent is needed so the window can set transient for
391436 """
392 Gtk.Window.__init__(self,
393 title="Host " + host.name + " information")
437
438 window_title = "Host " + host.name + " information"
439 Gtk.Window.__init__(self, title=window_title)
440
394441 self.set_transient_for(parent)
395442 self.set_size_request(1200, 500)
396443 self.set_modal(True)
397 self.connect("key_press_event", on_scape_destroy)
444 self.connect("key_press_event", key_reactions)
445
446 self.is_ws_couch = is_ws_couch
447
398448 self.host = host
449 self.model = self.create_model(self.host)
450 host_info = self.model[0]
451
452 host_id = self.model[0][0]
453 couch_url = CONF.getCouchURI()
454 base_url = couch_url + "/reports/_design/reports/index.html#/host/ws/"
455 self.edit_url = base_url + active_ws_name + "/hid/" + host_id
456
457 host_info_frame = self.create_host_info_frame(host_info)
399458
400459 self.specific_info = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
401460 self.specific_info_frame = self.create_scroll_frame(
402461 self.specific_info,
403462 "Service Information")
404463
405 self.specific_vuln_info = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
406 self.specific_vuln_info_frame = self.create_scroll_frame(
407 self.specific_vuln_info,
464 self.vuln_info = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
465 self.vuln_info_frame = self.create_scroll_frame(
466 self.vuln_info,
408467 "Vulnerability Information")
409468
410 basic_info_frame = self.create_basic_info_box(host)
411 children_of_host_tree = self.create_display_tree_box(host)
412 button = Gtk.Button.new_with_label("OK")
413 button.connect("clicked", self.on_click_ok)
469 main_tree = self.create_main_tree_view(self.model)
470 vuln_list = self.create_vuln_list()
471
472 button_box = self.create_button_box()
414473
415474 main_box = Gtk.Box()
416475
417476 info_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
418 info_box.pack_start(basic_info_frame, True, True, 10)
477 info_box.pack_start(host_info_frame, True, True, 10)
419478 info_box.pack_start(self.specific_info_frame, True, True, 10)
420 info_box.pack_start(self.specific_vuln_info_frame, True, True, 10)
421 info_box.pack_start(button, False, False, 10)
479 info_box.pack_start(self.vuln_info_frame, True, True, 10)
480 info_box.pack_start(button_box, False, False, 10)
422481
423482 main_tree_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
424 main_tree_box.pack_start(children_of_host_tree, True, True, 10)
483 main_tree_box.pack_start(main_tree, True, True, 10)
425484 main_tree_box.pack_start(Gtk.Box(), False, False, 10)
426485
427486 vuln_list_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
428 vuln_list_box.pack_start(self.create_vuln_tree_box(), True, True, 10)
487 vuln_list_box.pack_start(vuln_list, True, True, 10)
429488 vuln_list_box.pack_start(Gtk.Box(), False, False, 10)
430489
431490 main_box.pack_start(main_tree_box, False, False, 5)
434493
435494 self.add(main_box)
436495
496 def create_button_box(self):
497 """Creates an horizontal box to hold the buttons."""
498 button_box = Gtk.Box()
499
500 ok_button = Gtk.Button.new_with_label("OK")
501 ok_button.connect("clicked", self.on_click_ok)
502
503 html_edit_url = '<a href="' + self.edit_url + '"> Edit host </a>'
504 edit_button = Gtk.Button()
505 edit_label = Gtk.Label()
506 edit_label.set_markup(html_edit_url)
507 edit_button.add(edit_label)
508 edit_button.connect("clicked", self.on_edit_host)
509 if not self.is_ws_couch:
510 edit_button.set_sensitive(False)
511 edit_button.set_tooltip_text("You need to be on a CouchDB "
512 "workspace to edit information")
513
514 button_box.pack_start(edit_button, True, True, 0)
515 button_box.pack_start(ok_button, True, True, 0)
516 return button_box
517
518 def on_edit_host(self, button):
519 """Tries to open self.edit_url (url which directs to the host in the
520 web ui) in the default browser."""
521 webbrowser.open(self.edit_url, new = 2)
522
523
437524 def create_scroll_frame(self, inner_box, label_str):
438 """Create a scrollable frame.
439
440 inner_box will be the scrollable frame content.
441 label_str will be the scrollable frame title.
442
443 Scrollable will be set to always show vertical scrollbars and will
444 have disabled overlay scrolling
445 """
525 """Create a scrollable frame containing inner_box and with label_str
526 as its title.
527 """
528
446529 label = Gtk.Label()
447530 label.set_markup("<big>" + label_str + "</big>")
448531
459542
460543 return frame
461544
462 def create_basic_info_box(self, host):
463 """Creates a box where the basic information about the host
464 lives in labels. It include names, OS, Owned status and vulnarability
545 def create_host_info_frame(self, host_info):
546 """Return a box where the basic information about the host
547 lives in labels. It include names, OS, Owned status and vulnerability
465548 count.
466549 """
467550 box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
468551
469 name_box = Gtk.Box()
470 name_label = Gtk.Label()
471 name_label.set_markup("<b>%s</b>: %s" % ("Name", host.getName()))
472 name_label.set_selectable(True)
473 name_box.pack_start(name_label, False, False, 5)
474
475 os_box = Gtk.Box()
476 os_label = Gtk.Label()
477 os_label.set_markup("<b>%s</b>: %s" % ("OS", host.getOS()))
478 os_label.set_selectable(True)
479 os_box.pack_start(os_label, False, False, 5)
480
481 owned_box = Gtk.Box()
482 owned_label = Gtk.Label()
483 owned_status = ("Yes" if host.isOwned() else "No")
484 owned_label.set_markup("<b>%s: </b>%s" % ("Owned", owned_status))
485 owned_label.set_selectable(True)
486 owned_box.pack_start(owned_label, False, False, 5)
487
488 vulns_box = Gtk.Box()
489 vulns_label = Gtk.Label()
490 vulns_count = str(len(host.getVulns()))
491 vulns_label.set_markup("<b>%s</b>: %s" %
492 ("Vulnerabilities", vulns_count))
493 vulns_label.set_selectable(True)
494
495 vulns_box.pack_start(vulns_label, False, False, 5)
496
497 box.pack_start(name_box, False, True, 0)
498 box.pack_start(os_box, False, True, 0)
499 box.pack_start(owned_box, False, True, 0)
500 box.pack_start(vulns_box, False, False, 0)
501
502 basic_info_frame = self.create_scroll_frame(box, "Host Information")
503
504 return basic_info_frame
505
506 def create_vuln_tree_box(self):
507 """Creates a simple view a vulnerabilities"""
508 box = Gtk.Box()
552 prop_names = self.get_properties_names("Host")
553 self.show_info_in_box(host_info, prop_names, box)
554
555 host_info_frame = self.create_scroll_frame(box, "Host Information")
556
557 return host_info_frame
558
559 @scrollable(width=250)
560 def create_vuln_list(self):
561 """Creates a simple view of vulnerabilities for the object
562 and returns a box containing it. The vuln_list will be a value of the
563 instance.
564 """
565
509566 self.vuln_list = Gtk.TreeView()
510567 self.vuln_list.set_activate_on_single_click(True)
511568 renderer = Gtk.CellRendererText()
512569 column = Gtk.TreeViewColumn("Vulnerabilities", renderer, text=1)
570 column.set_sort_column_id(1)
513571 self.vuln_list.append_column(column)
514572
515573 vuln_selection = self.vuln_list.get_selection()
516574 vuln_selection.connect("changed", self.on_vuln_selection)
517575
518 scrolled_view = Gtk.ScrolledWindow(None, None)
519 scrolled_view.add(self.vuln_list)
520 scrolled_view.set_min_content_width(250)
521 box.pack_start(scrolled_view, True, True, 10)
522
523 return box
524
525 def create_display_tree_box(self, host):
526 """Creates a model and a view for the interfaces/services of the host.
527 Puts a scrolled window containing the view into a box and returns
528 that. The models holds quite a bit of information. It has 11 columns
529 holding the host ID and name as parent, all the information about
530 the interfaces of that host and all the information about
531 the services of those interfaces.
532 """
533
534 box = Gtk.Box()
535 interfaces = host.getAllInterfaces()
536 # those are 15 strings
576 return self.vuln_list
577
578 def create_model(self, host):
579 """Return a model for the given host. It holds quite a bit of info.
580 It has 15 columns holding the host ID and name as parent,
581 all the information about the interfaces of that host and all the
582 information about the services of those interfaces.
583
584 The model is difficult to draw because of its nested nature, but
585 you can think of it like this, keeping in mind each node has
586 several columns
587
588 HOST
589 -----> INTERFACE1
590 ------------> SERVICE1
591 ------------> SERVICE2
592 -----> INTERFACE2
593 -----------> SERVICE1
594 -----------> SERVICE2
595
596 And so on and so on, like Zizek says.
597 """
598
599 # those are 13 strings
537600 model = Gtk.TreeStore(str, str, str, str, str, str, str,
538601 str, str, str, str, str, str)
539602
542605 # the other columns with dummy info
543606
544607 display_str = host.getName() + " (" + str(len(host.getVulns())) + ")"
545 host_iter = model.append(None, [host.getID(), host.getName(),
546 "", "", "", "", "", "",
547 "", "", "", "", display_str])
608 owned_status = ("Yes" if host.isOwned() else "No")
609 host_position = model.append(None, [host.getID(), host.getName(),
610 host.getOS(), owned_status,
611 str(len(host.getVulns())), "",
612 "", "", "", "", "", "",
613 display_str])
614
615 # some convenient functions just to separate and clarify what
616 # the code does. they are used in the nested for loop directly
617 # below them.
548618
549619 def lst_to_str(lst):
550620 """Convenient function to avoid this long line everywhere"""
551621 return ', '.join([str(word) for word in lst if word])
552622
553 for interface in interfaces:
623 def add_interface_to_host_in_model(interface, host_pos, model):
624 """Append an interface to the host within a model.
625 Return the tree_iter represeting the position of the interface
626 within the model. Modifies the model.
627 """
554628 ipv4_dic = interface.getIPv4()
555629 ipv6_dic = interface.getIPv6()
556630 vulns = interface.getVulns()
557631 display_str = interface.getName() + " (" + str(len(vulns)) + ")"
558632
559 tree_iter = model.append(host_iter, [interface.getID(),
560 interface.getName(),
561 interface.getDescription(),
562 interface.getMAC(),
563 ipv4_dic['mask'],
564 ipv4_dic['gateway'],
565 lst_to_str(ipv4_dic['DNS']),
566 ipv4_dic['address'],
567 ipv6_dic['prefix'],
568 ipv6_dic['gateway'],
569 lst_to_str(ipv6_dic['DNS']),
570 ipv6_dic['address'],
571 display_str])
572
573 services = interface.getAllServices()
574 for service in services:
575 # Same as with the host, empty strings are there
576 # just to agree with the number of columns the model should
577 # have
578 vulns = service.getVulns()
579 display_str = service.getName() + " (" + str(len(vulns)) + ")"
580 model.append(tree_iter, [service.getID(),
633 position = model.append(host_pos, [interface.getID(),
634 interface.getName(),
635 interface.getDescription(),
636 interface.getMAC(),
637 ipv4_dic['mask'],
638 ipv4_dic['gateway'],
639 lst_to_str(ipv4_dic['DNS']),
640 ipv4_dic['address'],
641 ipv6_dic['prefix'],
642 ipv6_dic['gateway'],
643 lst_to_str(ipv6_dic['DNS']),
644 ipv6_dic['address'],
645 display_str])
646 return position
647
648 def add_service_to_interface_in_model(service, interface_pos, model):
649 """Append a service to an interface at interface_pos in the given
650 model. Return None. Modifies the model"""
651 vulns = service.getVulns()
652 display_str = service.getName() + " (" + str(len(vulns)) + ")"
653 model.append(interface_pos, [service.getID(),
581654 service.getName(),
582655 service.getDescription(),
583656 service.getProtocol(),
587660 "Yes" if service.isOwned() else "No",
588661 "", "", "", "", display_str])
589662
590 self.view = Gtk.TreeView(model)
591 self.view.set_activate_on_single_click(True)
663 interfaces = host.getAllInterfaces()
664 for interface in interfaces:
665 interface_position = add_interface_to_host_in_model(interface,
666 host_position,
667 model)
668 services = interface.getAllServices()
669 for service in services:
670 add_service_to_interface_in_model(service, interface_position,
671 model)
672
673 return model
674
675 @scrollable(width=250)
676 def create_main_tree_view(self, model):
677 """Return a box containing the main tree (the one showing
678 Host/Interfaces/Services) as its content.
679 """
680 view = Gtk.TreeView(model)
681 view.set_activate_on_single_click(True)
682 view.set_enable_tree_lines(True)
683 view.expand_all()
592684
593685 renderer = Gtk.CellRendererText()
594686 column = Gtk.TreeViewColumn("Host/Interfaces/Services",
595687 renderer, text=12)
596688
597 self.view.append_column(column)
598 selection = self.view.get_selection()
599 selection.connect("changed", self.on_selection)
600
601 scrolled_view = Gtk.ScrolledWindow(None, None)
602 scrolled_view.add(self.view)
603 scrolled_view.set_min_content_width(250)
604 box.pack_start(scrolled_view, True, True, 10)
605
606 return box
607
608 def on_selection(self, tree_selection):
609 """Defines what happens when the user clicks on a row. Shows
610 the interface or service information according to what the user
611 selected. Before calling the corresponding functions, will clear
612 the current specific_info box.
613 """
689 view.append_column(column)
690 view.set_expander_column(column)
691 selection = view.get_selection()
692 selection.connect("changed", self.on_main_tree_selection)
693
694 return view
695
696 def on_main_tree_selection(self, tree_selection):
697 """Fire up neccesary actions when selection on the main tree changes"""
614698 model, tree_iter = tree_selection.get_selected()
699 object_info = model[tree_iter]
700
615701 iter_depth = model.iter_depth(tree_iter)
616 selected = model[tree_iter]
617 self.specific_info.foreach(self.reset_info) # delete what was there
618 if iter_depth == 0:
702 object_type = {0: 'Host', 1: 'Interface', 2: 'Service'}[iter_depth]
703
704 if object_type == 'Host':
619705 self.set_vuln_model(self.create_vuln_model(self.host))
620 elif iter_depth == 1:
621 label = self.specific_info_frame.get_label_widget()
622 label.set_markup("<big>Interface information</big>")
623 self.show_interface_info(selected)
624 interface = self.host.getInterface(selected[0])
625 self.set_vuln_model(self.create_vuln_model(interface))
626 elif iter_depth == 2:
627 label = self.specific_info_frame.get_label_widget()
628 label.set_markup("<big>Service information</big>")
629 self.show_service_info(selected)
630 parent_interface_iter = selected.get_parent()
631 parent_interface_id = parent_interface_iter[0]
632 parent_interface = self.host.getInterface(parent_interface_id)
633 service = parent_interface.childs.get(selected[0], None)
634 self.set_vuln_model(self.create_vuln_model(service))
706
707 elif object_type == 'Interface' or object_type == 'Service':
708 self.clear(self.specific_info)
709 self.change_label_in_frame(self.specific_info_frame, object_type)
710 prop_names = self.get_properties_names(object_type)
711 self.show_info_in_box(object_info, prop_names, self.specific_info)
712 actual_object = self.get_object(object_info, object_type)
713 vuln_model = self.create_vuln_model(actual_object)
714 self.set_vuln_model(vuln_model)
635715
636716 def on_vuln_selection(self, vuln_selection):
637 """Sets up the information necesarry to show the detailed information
638 of the vulnerability. The try/except block is necesary 'cause GTK
639 is silly and will emit the selection changed signal if the model
640 changes even if nothing is selected"""
717 """Fill the vuln_info box with the vulnerability selected.
718
719 The try/except block is necesary 'cause GTK
720 is silly (ie: doesn't behave like it would be best for me now)
721 and will emit the selection changed signal if the model
722 changes even if nothing is selected.
723 """
641724
642725 model, vuln_iter = vuln_selection.get_selected()
643 self.specific_vuln_info.foreach(self.reset_vuln_info)
644726 try:
645727 selected = model[vuln_iter]
646 self.show_vuln_info(selected)
728 vuln_type = selected[0]
729 self.clear(self.vuln_info)
730 is_vuln_web = vuln_type == "VulnerabilityWeb"
731 frame_title = "Vulnerability Web" if is_vuln_web else "Vulnerability"
732 self.change_label_in_frame(self.vuln_info_frame,
733 frame_title)
734 prop_names = self.get_properties_names(vuln_type)
735 self.show_info_in_box(selected, prop_names,
736 self.vuln_info)
647737 except TypeError:
648738 return False
649739
650740 def set_vuln_model(self, model):
741 """Sets the vulnerability view to show the given model"""
651742 self.vuln_list.set_model(model)
652743
653744 def create_vuln_model(self, obj):
654 """Creates a model for the vulnerabilities of the selected object"""
745 """Return the model for the vulnerabilities of the obj object.
746 It will be sorted alphabetically.
747 """
655748 # those are 15 strings
656749 model = Gtk.ListStore(str, str, str, str, str, str, str, str,
657750 str, str, str, str, str, str, str)
660753 for vuln in vulns:
661754 _type = vuln.class_signature
662755 if _type == "Vulnerability":
756 # again filling up the model with dumb strings
757 # because gtk
663758 model.append([_type, vuln.getName(), vuln.getDescription(),
664759 vuln.getData(), vuln.getSeverity(),
665760 ', '.join(vuln.getRefs()),
673768 vuln.getResponse(), vuln.getMethod(),
674769 vuln.getPname(), vuln.getParams(),
675770 vuln.getQuery(), vuln.getCategory()])
676 return model
677
678 def show_interface_info(self, selected):
679 """Creates labels for each of the properties of an interface. Appends
680 them to the specific_info_box.
681 """
682 for prop in enumerate(["Name: ", "Description: ", "MAC: ",
683 "IPv4 Mask: ", "IPv4 Gateway: ", "IPv4 DNS: ",
684 "IPv4 Address: ", "IPv6 Prefix: ",
685 "IPv6 Gateway", "IPv6 DNS: ",
686 "IPv6 Address: "], start=1):
687 self.append_info_to_box(selected, prop, self.specific_info)
688
689 def show_service_info(self, selected):
690 """Creates labels for each of the properties of a service. Appends
691 them to the specific_info_box.
692 """
693 for prop in enumerate(["Name: ", "Description: ", "Protocol: ",
694 "Status: ", "Port: ", "Version: ",
695 "Is Owned?: "], start=1):
696 self.append_info_to_box(selected, prop, self.specific_info)
697
698 def show_vuln_info(self, selected):
699 """Sends the information about the selected vuln to
700 append_info_to_box.
701 """
702 if selected[0] == "Vulnerability":
703 for prop in enumerate(["Name: ", "Description: ",
704 "Data: ", "Severity: ",
705 "Refs: "], start=1):
706 self.append_info_to_box(selected, prop,
707 self.specific_vuln_info)
708 if selected[0] == "VulnerabilityWeb":
709 for prop in enumerate(["Name: ", "Description: ",
710 "Data: ", "Severity: ",
711 "Refs: ", "Path: ",
712 "Website: ", "Request: ",
713 "Response: ", "Method: ",
714 "Pname: ", "Params: ",
715 "Query: ", "Category: "], start=1):
716 self.append_info_to_box(selected, prop,
717 self.specific_vuln_info)
718
719 def append_info_to_box(self, selected, prop, box):
720 """Gets selected and prop and creates a label and appends
721 them to the box parameter.
722 """
723 prop_box = Gtk.Box()
724 prop_label = Gtk.Label()
725 prop_label.set_markup("<b> %s </b>" % (prop[1]))
726 prop_label.set_selectable(True)
727 value_label = Gtk.Label(selected[prop[0]])
728 value_label.set_selectable(True)
729 prop_box.pack_start(prop_label, False, False, 0)
730 prop_box.pack_start(value_label, False, False, 0)
731 box.pack_start(prop_box, True, True, 0)
771 #sort it!
772 sorted_model = Gtk.TreeModelSort(model=model)
773 sorted_model.set_sort_column_id(1, Gtk.SortType.ASCENDING)
774
775 return sorted_model
776
777 def change_label_in_frame(self, frame, string):
778 """Changes the label in the given frame to 'string Information'"""
779 label = frame.get_label_widget()
780 label.set_markup("<big>" + string + " " + "Information" + "</big>")
781
782 def show_info_in_box(self, object_info, property_names, box):
783 """Appends several boxes vertically to the box. The appended boxes will
784 all contain two labels, together forming something like this:
785 '<b>property_name:</b> object_info'. It will also append a separator
786 on top of each one of these boxes.
787
788 It is important to notice that the first element of object_info
789 is ignored. This is because of how the models in this class contain
790 information. Thus, there'll be as many of this small boxes as
791 len(property_names) minus one, read next paragraph.
792 """
793
794 for index, prop_name in enumerate(property_names, start=1):
795 if index != 1:
796 # do not append to the first prop_name
797 separator = Gtk.Separator.new(orientation=Gtk.Orientation.HORIZONTAL)
798 box.pack_start(separator, False, True, 0)
799
800 prop_box = Gtk.Box()
801 prop_value = object_info[index]
802
803 prop_label = Gtk.Label()
804 prop_label.set_markup("<b> %s </b>" % (prop_name))
805 prop_label.set_selectable(True)
806
807 value_label = Gtk.Label(prop_value)
808 value_label.set_selectable(True)
809 prop_box.pack_start(prop_label, False, False, 0)
810 prop_box.pack_start(value_label, False, False, 0)
811 box.pack_start(prop_box, True, True, 0)
812
732813 box.show_all()
733814
734 def reset_info(self, widget):
735 """Removes a widget from self.specific_info. Used to clear all
736 the information before displaying new"""
737 self.specific_info.remove(widget)
738
739 def reset_vuln_info(self, widget):
740 """Removes a widget from self.specific_vuln_info. Used to clear
741 all the information before displaying new"""
742 self.specific_vuln_info.remove(widget)
743
744 def on_click_ok(self, button):
815 def get_object(self, selected_object, object_type):
816 """Take a selection as selected_object and an object_type
817 and return the actual object, not the model's selection.
818 """
819 object_id = selected_object[0]
820 if object_type == 'Interface':
821 # an interface is a direct child of a host
822 object_ = self.host.getInterface(object_id)
823 elif object_type == 'Service':
824 # a service is a grand-child of a host, so we should look
825 # for its parent interface and ask her about the child
826 parent_interface_iter = selected_object.get_parent()
827 parent_interface_id = parent_interface_iter[0]
828 parent_interface = self.host.getInterface(parent_interface_id)
829 object_ = parent_interface.getService(object_id)
830
831 return object_
832
833 def get_properties_names(self, object_type):
834 """Return a list with the property names for objects of type
835 Interface, Service, Vulnerability and VulnerabilityWeb (passed as a
836 string).
837 """
838 if object_type == "Host":
839 property_names = ["Name: ", "OS: ", "Owned: ",
840 "Vulnerabilities: "]
841
842 if object_type == "Interface":
843 property_names = ["Name: ", "Description: ", "MAC: ",
844 "IPv4 Mask: ", "IPv4 Gateway: ", "IPv4 DNS: ",
845 "IPv4 Address: ", "IPv6 Prefix: ",
846 "IPv6 Gateway", "IPv6 DNS: ",
847 "IPv6 Address: "]
848
849 elif object_type == "Service":
850 property_names = ["Name: ", "Description: ", "Protocol: ",
851 "Status: ", "Port: ", "Version: ", "Is Owned?: "]
852
853 elif object_type == "Vulnerability":
854 property_names = ["Name: ", "Description: ", "Data: ",
855 "Severity: ", "Refs: "]
856
857 elif object_type == "VulnerabilityWeb":
858 property_names = ["Name: ", "Description: ", "Data: ",
859 "Severity: ", "Refs: ", "Path: ",
860 "Website: ", "Request: ", "Response: ",
861 "Method: ", "Pname: ", "Params: ",
862 "Query: ", "Category: "]
863 return property_names
864
865 def clear(self, box):
866 """Remove all the widgets from box."""
867
868 def remove(widget, box):
869 """Removes widget from box"""
870 box.remove(widget)
871
872 box.foreach(remove, box)
873
874 def on_click_ok(self, button=None):
745875 self.destroy()
746876
747877
760890 self.set_transient_for(parent)
761891 self.set_size_request(600, 400)
762892 self.set_modal(True)
763 self.connect("key_press_event", on_scape_destroy)
893 self.connect("key_press_event", key_reactions)
764894 self.conflicts = conflicts
765895 self.conflict_n = 0
766896 self.current_conflict = self.conflicts[self.conflict_n]
8931023 n. If first conflict, self.view will be none. If user is past the first
8941024 conflict, self.view will not be none"""
8951025
1026 @scrollable()
1027 def make_scrollable(view):
1028 return view
1029
8961030 if self.view is None:
8971031
8981032 renderer = Gtk.CellRendererText()
9241058 self.second_view.append_column(prop2_column)
9251059 self.second_view.append_column(obj2_column)
9261060
927 scrolled_view = Gtk.ScrolledWindow(None, None)
928 second_scrolled_view = Gtk.ScrolledWindow(None, None)
929 scrolled_view.add(self.view)
930 second_scrolled_view.add(self.second_view)
1061 scrolled_view = make_scrollable(self.view)
1062 second_scrolled_view = make_scrollable(self.second_view)
9311063
9321064 self.views_box.pack_start(scrolled_view, True, True, 5)
9331065 self.views_box.pack_start(second_scrolled_view, True, True, 5)
10931225 """Preconditions: the model has 5 string columns,
10941226 len(attr[0]) == len(attr[1]) == len(props),
10951227 type(attr[0][i]) == type(attr[1][i]) for every i
1096 attr is a list of two tuples. the first tuple holds info about obj1,
1097 the second about obj2.
1098 props is the list with names of such attributes
1228 attr is a list with two tuples. the first tuple holds info about obj1,
1229 the second about obj2, for example:
1230 [(name_obj1, ports_obj1), (name_obj2, porst_obj2)]
1231 props is the list with names of such attributes, for example:
1232 ["Name: ", "Ports: "]
10991233
11001234 Will return a model filled up with information as detailed in
11011235 self.create_conflicts_models.
11311265 # just use that color, screw highlights
11321266 return '#%02x%02x%02x' % (color1, color2, color3)
11331267
1134 i = 0
1135 for prop in props:
1136 first_raw_prop = attr[0][i]
1137 sec_raw_prop = attr[1][i]
1268 for index, prop in enumerate(props):
1269 # remember props is a list like [(obj1_prop1, obj1_prop2...),
1270 # (obj2_prop1, obj2, prop2...)]
1271 first_raw_prop = attr[0][index]
1272 sec_raw_prop = attr[1][index]
11381273 first_prop = self.cook(first_raw_prop)
11391274 sec_prop = self.cook(sec_raw_prop)
11401275
11411276 model.append([prop, first_prop, sec_prop,
11421277 decide_bg(),
11431278 decide_type(first_raw_prop)])
1144 i += 1
11451279
11461280 return model
11471281
12091343 self.set_transient_for(parent)
12101344 self.set_size_request(400, 200)
12111345 self.set_modal(True)
1212 self.connect("key_press_event", on_scape_destroy)
1213
1214 self.view = view
1346 self.connect("key_press_event", key_reactions)
12151347 self.destroy_notifications = callback
1348
1349 scrolled_list = self.create_view_box(view)
12161350
12171351 self.button = Gtk.Button()
12181352 self.button.set_label("OK")
1219 self.button.connect("clicked", self.on_click_OK)
1220
1221 scrolled_list = Gtk.ScrolledWindow.new(None, None)
1222 scrolled_list.set_min_content_width(200)
1223 scrolled_list.set_min_content_height(350)
1224 scrolled_list.add(self.view)
1353 self.button.connect("clicked", self.on_click_ok)
12251354
12261355 self.mainBox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
12271356 self.mainBox.pack_start(scrolled_list, True, True, 0)
12291358
12301359 self.add(self.mainBox)
12311360
1232 def on_click_OK(self, button):
1361 @scrollable(width=250, height=350)
1362 def create_view_box(self, view):
1363 return view
1364
1365 def on_click_ok(self, button=None):
12331366 self.destroy_notifications()
12341367 self.destroy()
12351368
13001433 textBuffer = Gtk.TextBuffer()
13011434 textBuffer.set_text(error)
13021435
1436 text_view_box = self.create_text_view_box(textBuffer)
1437
1438 content = self.get_content_area()
1439
1440 content.pack_start(text_view_box, True, True, 0)
1441 self.show_all()
1442
1443 @scrollable(width=200, height=200)
1444 def create_text_view_box(self, textBuffer):
13031445 textView = Gtk.TextView()
13041446 textView.set_editable(False)
13051447 textView.set_buffer(textBuffer)
1306
1307 box = self.get_content_area()
1308 scrolled_text = Gtk.ScrolledWindow.new(None, None)
1309 scrolled_text.set_min_content_height(200)
1310 scrolled_text.set_min_content_width(200)
1311 scrolled_text.add(textView)
1312
1313 box.pack_start(scrolled_text, True, True, 0)
1314 self.show_all()
1315
1316
1317 def on_scape_destroy(window, event):
1448 return textView
1449
1450
1451 def key_reactions(window, event):
13181452 """Silly function to destroy a window on escape key, to use
13191453 with all the dialogs that should be Gtk.Dialogs but are Gtk.Windows
13201454 or with windows that are too complex for gtk dialogs but should behave
13211455 as a dialog too"""
1322 if event.get_keycode()[1] == 9:
1456 key = Gdk.keyval_name(event.get_keyval()[1])
1457 if key == 'Escape':
13231458 window.destroy()
13241459 return True
1325 else:
1326 return False
1460 elif key == 'Return':
1461 window.on_click_ok()
1462 return True
77 '''
88 import gi
99 import os
10 import sys
1110
1211 gi.require_version('Gtk', '3.0')
1312 gi.require_version('Vte', '2.91')
1918 """Defines a simple terminal that will execute faraday-terminal with the
2019 corresponding host and port as specified by the CONF"""
2120 def __init__(self, CONF):
21 """Initialize terminal with infinite scrollback, no bell, connecting
22 all keys presses to copy_or_past, and starting faraday-terminal
23 """
2224 super(Vte.Terminal, self).__init__()
2325 self.set_scrollback_lines(-1)
2426 self.set_audible_bell(0)
5355 """Decides if the Ctrl+Shift is pressed, in which case returns True.
5456 If Ctrl+Shift+C or Ctrl+Shift+V are pressed, copies or pastes,
5557 acordingly. Return necesary so it doesn't perform other action,
56 like killing the process, on Ctrl+C.
58 like killing the process on Ctrl+C.
59
60 Note that it won't care about order: Shift+Ctrl+V will work just as
61 Ctrl+Shift+V.
5762 """
58
59 control_key = Gdk.ModifierType.CONTROL_MASK
60 shift_key = Gdk.ModifierType.SHIFT_MASK
63 control_key = 'control-mask'
64 shift_key = 'shift-mask'
65 last_pressed_key = Gdk.keyval_name(event.get_keyval()[1])
66 set_pressed_special_keys = set(event.state.value_nicks)
6167 if event.type == Gdk.EventType.KEY_PRESS:
62 if event.state == shift_key | control_key: #both shift and control
63 if event.keyval == 67: # that's the C key
68 if {control_key, shift_key} <= set_pressed_special_keys:
69 # '<=' means 'is a subset of' in sets
70 if last_pressed_key == 'C':
6471 self.copy_clipboard()
65 elif event.keyval == 86: # and that's the V key
72 elif last_pressed_key == 'V':
6673 self.paste_clipboard()
6774 return True
75
6876
6977 class Sidebar(Gtk.Notebook):
7078 """Defines the bigger sidebar in a notebook. One of its tabs will contain
8896 box.pack_start(self, True, True, 0)
8997 return box
9098
99
91100 class HostsSidebar(Gtk.Widget):
92101 """Defines the widget displayed when the user is in the "Hosts" tab of
93102 the Sidebar notebook. Will list all the host, and when clicking on one,
98107 almost nothing, the application will inmediatly call create_model
99108 with the last workspace and create_view with that model upon startup.
100109 """
101
102110 super(Gtk.Widget, self).__init__()
103111 self.open_dialog_callback = open_dialog_callback
104112 self.current_model = None
111119 host_id in the first column, the icon as a GdkPixbuf.Pixbuf()
112120 in the second column and a display_str with the host_name and the
113121 vulnerability count on the third column, like this:
114 | HOST_ID | HOST_OS_PIXBUF | DISPLAY_STR |
115 =================================================
116 | a923fd | LINUX_ICON | 192.168.1.2 (5) |
122 | HOST_ID | HOST_OS_PIXBUF | OS_STR | DISPLAY_STR | VULN_COUNT|
123 ======================================================================
124 | a923fd | PixBufIcon(linux)| linux | 192.168.1.2 (5) | 5 |
117125 """
118126 def compute_vuln_count(host):
119 """Returns the total vulnerability count for a given host"""
127 """Return the total vulnerability count for a given host"""
120128 vuln_count = 0
121129 vuln_count += len(host.getVulns())
122130 for interface in host.getAllInterfaces():
123131 vuln_count += len(interface.getVulns())
124132 for service in interface.getAllServices():
125133 vuln_count += len(service.getVulns())
126 return str(vuln_count)
134 return vuln_count
127135
128136 def decide_icon(os):
129 """Decides the correct Pixbuf icon for a OS. None if OS not
130 found or not recognized.
137 """Return the GdkPixbuf icon according to 'os' paramather string
138 and a str_id to that GdkPixbuf for easy comparison and ordering
139 of the view ('os' paramether string is complicated and has caps).
131140 """
132141 os = os.lower()
133142 if "linux" in os or "unix" in os:
134143 icon = GdkPixbuf.Pixbuf.new_from_file(self.linux_icon)
144 str_id = "linux"
135145 elif "windows" in os:
136 icon = GdkPixbuf.Pixbuf.new_from_file(self.windows_icon)
146 icon = GdkPixbuf.Pixbuf.new_from_file(self.windows_icon)
147 str_id = "windows"
137148 elif "mac" in os:
138 icon = GdkPixbuf.Pixbuf.new_from_file(self.mac_icon)
149 icon = GdkPixbuf.Pixbuf.new_from_file(self.mac_icon)
150 str_id = "mac"
139151 else:
140152 icon = None
141 return icon
142
143 hosts_model = Gtk.ListStore(str, GdkPixbuf.Pixbuf(), str)
153 str_id = "unknown"
154 return icon, str_id
155
156 def compare_os_strings(model, an_os, other_os, user_data):
157 """Compare an_os with other_os so the model knows how to sort them.
158 user_data is not used.
159 Forces 'unknown' OS to be always at the bottom of the model.
160 Return values:
161 1 means an_os should come after other_os
162 0 means they are the same
163 -1 means an_os should come before other_os
164 It helps to think about it like the relative position of an_os
165 in respect to other_os (-1 'left' in a list, 1 'right' in a list)
166 """
167 sort_column = 2
168 an_os = model.get_value(an_os, sort_column)
169 other_os = model.get_value(other_os, sort_column)
170 if an_os == "unknown":
171 order = 1
172 elif an_os < other_os or other_os == "unknown":
173 order = -1
174 elif an_os == other_os:
175 order = 0
176 else:
177 order = 1
178 return order
179
180 hosts_model = Gtk.ListStore(str, GdkPixbuf.Pixbuf(), str, str, int)
181
144182 for host in hosts:
145183 vuln_count = compute_vuln_count(host)
146 display_str = host.name + " (" + vuln_count + ")"
147 os = host.getOS()
148 hosts_model.append([host.id, decide_icon(os), display_str])
149 self.current_model = hosts_model
150 return hosts_model
184 os_icon, os_str = decide_icon(host.getOS())
185 display_str = host.name + " (" + str(vuln_count) + ")"
186 hosts_model.append([host.id, os_icon, os_str,
187 display_str, vuln_count])
188
189 # sort the model by default according to column 4 (num of vulns)
190 sorted_model = Gtk.TreeModelSort(model=hosts_model)
191 sorted_model.set_sort_column_id(4, Gtk.SortType.DESCENDING)
192
193 # set the sorting function of column 2
194 sorted_model.set_sort_func(2, compare_os_strings, None)
195
196 self.current_model = sorted_model
197
198 return self.current_model
151199
152200 def create_view(self, model):
153 """Creates a view displaying the third column of the given model as
154 a text, and using an icon representing its second column.
201 """Creates a view for the hosts model.
202 It will contain two columns, the first with the OS icon given in
203 the second column of the model. The second column of the view will
204 be the string contained in the fourth column of the model.
205 The first column of the view will be orderer according to the
206 second column of the model, and the second column of the view will
207 be ordered according to its fifth column.
155208 Will connect activation of a row with the on_click method
156209 """
157210
158 def display_str(col, cell, model, _iter, user_data):
159 cell.set_property('text', model.get_value(_iter, 2))
160
161 def set_icon(col, cell, model, _iter, user_data):
162 icon = model.get_value(_iter, 1)
163 if icon != "None":
164 cell.set_property('pixbuf',
165 GdkPixbuf.Pixbuf.new_from_file(icon))
166
167211 self.view = Gtk.TreeView(model)
168212 self.view.set_activate_on_single_click(True)
169213
170214 text_renderer = Gtk.CellRendererText()
171215 icon_renderer = Gtk.CellRendererPixbuf()
172216
173 column_hosts = Gtk.TreeViewColumn("Hosts", text_renderer, text=2)
217 column_hosts = Gtk.TreeViewColumn("Hosts", text_renderer, text=3)
218 column_hosts.set_sort_column_id(4)
219 column_hosts.set_sort_indicator(True)
220
174221 column_os = Gtk.TreeViewColumn("", icon_renderer, pixbuf=1)
222 column_os.set_sort_column_id(2)
223 column_os.set_sort_indicator(True)
175224
176225 self.view.append_column(column_os)
177226 self.view.append_column(column_hosts)
227
178228
179229 self.view.connect("row_activated", self.on_click)
180230
206256 scrolled_view.add(self.view)
207257 box.pack_start(scrolled_view, True, True, 0)
208258 return box
259
209260
210261 class WorkspaceSidebar(Gtk.Widget):
211262 """Defines the sidebar widget to be used by the AppWindow, passed as an
5656 def workspaceChanged(self, workspace, workspace_type):
5757 self._notifyWidgets(events.WorkspaceChangedCustomEvent(workspace,workspace_type))
5858
59 def CouchDBConnectionProblem(self, problem=None):
60 self._notifyWidgets(events.ShowExceptionConnectionRefusedCustomEvent(problem))
61
5962 def addHost(self, host):
6063 self._notifyWidgets(events.AddHostCustomEvent(host))
6164
7376
7477 def changeFromInstance(self, change):
7578 self._notifyWidgets(events.ChangeFromInstanceCustomEvent(change))
79
1515 CLEARHOSTS_ID, DIFFHOSTS_ID, SYNCFAILED_ID,
1616 CONFLICTS_ID, WORKSPACE_CHANGED, CONFLICT_UPDATE,
1717 RESOLVECONFLICTS_ID, UPDATEMODEL_ID, ADDHOST,
18 EDITHOST, DELHOST, CHANGEFROMINSTANCE)
18 EDITHOST, DELHOST, CHANGEFROMINSTANCE,
19 CONNECTION_REFUSED)
1920
2021
2122 class LogCustomEvent(qt.QCustomEvent):
112113 qt.QCustomEvent.__init__(self, e.type())
113114 self.change = e.change
114115
116 class ConnectionRefusedEvent(qt.QCustomEvent):
117 def __init__(self, e):
118 qt.QCustomEvent.__init__(self, e.type())
119
115120
116121 class QtCustomEvent(qt.QCustomEvent):
117122 events = {
131136 ADDHOST: AddHostCustomEvent,
132137 DELHOST: DeleteHostCustomEvent,
133138 EDITHOST: EditHostCustomEvent,
134 CHANGEFROMINSTANCE: ChangeFromInstanceCustomEvent
139 CHANGEFROMINSTANCE: ChangeFromInstanceCustomEvent,
140 CONNECTION_REFUSED: ConnectionRefusedEvent
135141 }
136142
137143 @staticmethod
2222
2323
2424 class PropertyItem(qt.QListViewItem):
25
26
25
26
2727 """Item for displaying a preferences-set in HostsBrowser."""
2828 def __init__(self, settings, number, parent):
2929 """_plugin_settings is the _plugin_settings class to work for
5959 qt.QListView.__init__(self, parent)
6060 self.setSelectionMode(qt.QListView.Extended)
6161
62
63
64
65
66
62
63
64
65
66
6767
6868 def selectWidget(self, widget):
6969 """Find the widget in the list and select it."""
7070
71
72
71
72
7373 iter = qt.QListViewItemIterator(self)
7474
7575 found = None
106106 self._model_controller = model_controller
107107
108108 self.modelUpdateTimer = qt.QTimer(self)
109
109
110110 self.__pendingModelObjectRedraws = []
111111
112112 self.reindex_flag_lock = Lock()
113113 self.reindex_flag = False
114114
115115 self.connect( self.modelUpdateTimer, qt.SIGNAL("timeout()"), self._modelObjectViewUpdater)
116
116
117117 self.modelUpdateTimer.start( 1000 , False)
118
118
119119
120120 self.setName(caption) if caption else self.setName("")
121121
124124
125125 self._host_items = {}
126126
127
127
128128 self._category_items = {}
129129
130
131
130
131
132132 self._category_tree = {}
133133
134134 self.contextpopups = {}
136136
137137 self.contextdispatchers = {}
138138
139
139
140140 self._filter = ""
141141 self.ix = None
142142
146146 split.setOrientation(qt.QSplitter.Vertical)
147147
148148 lv = self.listview = ModelObjectListView(split)
149
150
151
149
150
151
152152 lv.setRootIsDecorated(True)
153153
154
154
155155 self.connect( lv, qt.SIGNAL("selectionChanged()"), self._itemSelected )
156156 self.connect( lv, qt.SIGNAL("rightButtonPressed(QListViewItem *,const QPoint&,int)"), self._showContextMenu )
157
157
158158 lv.addColumn("Hosts")
159159 lv.setColumnWidthMode(0,qt.QListView.Maximum)
160
161
162
160
161
162
163163 lv.setTreeStepSize(20)
164164
165
166
167
168
165
166
167
168
169169 self.rootitem = None
170170
171
172
173
174
171
172
173
174
175175 self.details_table = EditionTable(split)
176176 hbox = qt.QHBox(self)
177177 self.object_label = qt.QLabel("", hbox)
181181
182182 self.prefchilds = []
183183
184
185
184
185
186186
187187 def load(self, workspace, workspace_type):
188188 self.rootitem = WorkspaceListViewItem(self.listview, workspace, workspace_type)
191191 def update(self, hosts):
192192 self.clearTree()
193193 self.redrawTree(hosts)
194
194
195195 def sizeHint(self):
196196 """Returns recommended size of dialog."""
197197 return qt.QSize(70, 200)
198198
199199 def resizeEvent (self, event ):
200
201
202
203
200
201
202
203
204204 self.listview.setColumnWidth(0,self.size().width()-7)
205
206
205
206
207207
208208 def clearTree(self):
209209 """
281281 viewall=True
282282 hosts=[]
283283
284
285
284
285
286286
287287 for k in self._host_items.keys():
288
288
289289 if (self._host_items[k].object.name in hosts) or viewall==True:
290290 self._host_items[k].setVisible(True)
291291 else:
293293
294294
295295 def _filterHost(self,hosts):
296
296
297297
298298 from whoosh.qparser import QueryParser
299299 with self.ix.searcher() as searcher:
300300 query = QueryParser("ip", self.ix.schema).parse(self._filter)
301301 results = searcher.search(query, limit=None)
302
303
304
302
303
304
305305 hostv={}
306306 for r in results:
307307 hostv[r['ip']]=1
415415 dialog.exec_loop()
416416
417417 def _item_save(self):
418
419
418
419
420420 if self._save_callback is not None:
421421 self._save_callback()
422422
427427 """
428428 this is called when a list view item is selected
429429 """
430
430
431431 i = self.listview.firstChild()
432432 self.items_selected=[]
433433 self.items_type={'Host': 0, 'Workspace': 0, 'Service':0,
447447
448448 self.itemselected = self.listview.currentItem()
449449
450
450
451451 self.details_table.clear()
452452 editor = self.itemselected.getEditor()
453453 editor.fillEditionTable(self.details_table)
515515
516516 def _delCategory(self, category, recursive=False):
517517 if category in self._category_tree:
518 if recursive:
518 if recursive:
519519 for id in self._category_tree:
520520 host_item = self._getHostListViewItem(id)
521521 if host_item is not None:
522522 self._delHostFromCategory(host_item.object, category)
523523 else:
524
525
524
525
526526 for id in self._category_tree:
527527 host_item = self._getHostListViewItem(id)
528528 if host_item is not None:
540540 """Pop up a context menu when an item is clicked on the list view."""
541541 ret = None
542542
543 if item is not None:
544
545
546
547
543 if item is not None:
544
545
546
547
548548 if self.items_type['Interface']:
549549 if (self.items_type['Category_General'] or self.items_type['Workspace']):
550550 popname="CategoryWorkspace_Interface"
564564 else:
565565 popname=item.type
566566 else:
567
567
568568 if item.type is "Category":
569569 popname=item.type + "_" + item.name
570570 else:
574574
575575 if ret in self.contextdispatchers:
576576 self.contextdispatchers[ret](item)
577
578
577
578
579579
580580 api.devlog("contextMenuEvent - item: %s - ret %s" % (self.name, ret))
581581
582
582
583583
584584 def _newHost(self, item):
585585 api.devlog("newHost")
588588
589589 def _newHostCallback(self, name, os):
590590 if name:
591
591
592592 guiapi.createAndAddHost(name, os=os)
593593
594594 def _delHost(self,item):
595595 api.devlog("delHost")
596 if item is not None and item.object is not None:
596 if item is not None and item.object is not None:
597597 dialog = MessageDialog(self,title="Host delete",callback=self._delSelectedCallback)
598598 dialog.exec_loop()
599599
614614
615615 def _delInterface(self,item):
616616 api.devlog("delInterface")
617 if item is not None and item.object is not None:
617 if item is not None and item.object is not None:
618618 dialog = MessageDialog(self,title="Interface delete",callback=self._delSelectedCallback)
619619 dialog.exec_loop()
620620
637637 guiapi.createAndAddServiceToInterface(host_id, interface_id , name, protocol=protocol, ports=ports)
638638
639639 def _delService(self,item):
640 if item is not None and item.object is not None:
640 if item is not None and item.object is not None:
641641 dialog = MessageDialog(self,title="Delete Item(s)",callback=self._delSelectedCallback)
642642 dialog.exec_loop()
643643
669669 parent_interface = self._getParentForType(i, "Interface").object
670670 parent_host = self._getParentForType(i, "Host").object
671671 guiapi.delServiceFromInterface(parent_host.getID(), parent_interface.getID(), _object.getID())
672
672
673673 self.listview.setCurrentItem(self.rootitem)
674674 self._itemSelected()
675675
688688
689689 def _delCategorymenu(self,item):
690690 api.devlog("delCategorymenu")
691 if item is not None:
691 if item is not None:
692692 dialog = MessageDialog(self,title="Category delete",callback=self._delCategoryCallback,item=item)
693693 dialog.exec_loop()
694694
734734 "save file dialog",
735735 "Choose a file to save the vulns" )
736736 from exporters.tofile import CSVVulnStatusReport
737 CSVVulnStatusReport(path = filename,
738 modelobjects = hosts).createCSVVulnStatusReport()
737 CSVVulnStatusReport(path = filename,
738 modelobjects = hosts).createCSVVulnStatusReport()
739739
740740 def _importVulnsCvs(self,item):
741741 filename = qt.QFileDialog.getOpenFileName(
744744 None,
745745 "open file dialog",
746746 "Choose a vulnerability file" );
747
747
748748 if os.path.isfile(filename):
749749 with open(filename) as f:
750750 data = f.read()
755755 if re.search("^#",l):
756756 api.devlog("ERROR FILE")
757757 continue
758
758
759759 d = l.split("|")
760760 if len(d) <8:
761761 api.log("Error vuln line: ("+l+")" )
775775 s_id = guiapi.createAndAddServiceToInterface(h_id,i_id,port,protocol,ports=[port])
776776 if type == "2":
777777 v_id = guiapi.createAndAddVulnWebToService(h_id,s_id, name, desc, [], severity, "/", "/")
778 else:
778 else:
779779 v_id = guiapi.createAndAddVulnToService(h_id,s_id, name, desc, [],severity)
780780
781781 api.devlog("type:" + type)
782
782
783783 def _isIPV4(self, ip):
784784 if len(ip.split(".")) == 4:
785785 return True
787787 return False
788788
789789 def _listNotes(self, item):
790 if item is not None and item.object is not None:
790 if item is not None and item.object is not None:
791791 dialog = NotesDialog(parent=self, model_object=item.object)
792792 dialog.exec_loop()
793793
794794 def _newNote(self, item):
795 if item is not None and item.object is not None:
795 if item is not None and item.object is not None:
796796 dialog = NewNoteDialog(self, callback=self._newNoteSelectedCallback)
797797 dialog.exec_loop()
798798
831831 None,
832832 "open file dialog",
833833 "Choose a password file" );
834
834
835835 if os.path.isfile(filename):
836836 with open(filename) as f:
837837 data = f.read()
842842 if re.search("^#",l):
843843 api.devlog("ERROR FILE")
844844 continue
845
845
846846 d = l.split(",")
847847 if len(d)<=1:
848848 d = l.split(":")
849
849
850850 api.devlog(d)
851851 if len(d) <=1:
852852 api.devlog("Error password line: ("+l+")" )
864864 d = WorkspacePropertiesDialog(self, "Workspace Properties", workspace=item.object)
865865 d.exec_loop()
866866
867 def _modelObjectViewUpdater(self):
867 def _modelObjectViewUpdater(self):
868868 if len(self.__pendingModelObjectRedraws):
869869 self.update(self.__pendingModelObjectRedraws.pop().hosts)
870870 self.__pendingModelObjectRedraws[:] = []
909909 Configures a context popup menu for each kind of item shown in the tree.
910910 This is done because different options may be needed for each item
911911 """
912
912
913913 popup = qt.QPopupMenu(self)
914
915
916
914
915
916
917917 popup.insertSeparator()
918918 popup.insertItem('Resolve Conflicts', 303)
919919 popup.insertItem('Save Vulns CSV', 402)
920920 popup.insertItem('Import Vulns CSV', 403)
921
922
921
922
923923 popup.insertSeparator()
924924 popup.insertItem('Add Host', 800)
925925
927927
928928 self.contextpopups["Category_General"] = self.contextpopups["Workspace"]
929929
930
930
931931 popup = qt.QPopupMenu(self)
932
933
934
932
933
934
935935
936936 self.contextpopups["Category_Applications"] = popup
937937
938
938
939939 popup = qt.QPopupMenu(self)
940940 popup.insertItem('Add Interfaces', 600)
941
942
941
942
943943
944944 self.contextpopups["Category_Interfaces"] = popup
945945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963963 popup = qt.QPopupMenu(self)
964964 popup.insertItem('Delete Host', 802)
965965 popup.insertSeparator()
974974 popup.insertItem('New Credential', 550)
975975 popup.insertItem('Show Credentials', 551)
976976 popup.insertItem('Import Creds', 561)
977
978
977
978
979979
980980 self.contextpopups["Host"] = popup
981981
982
982
983983 popup = qt.QPopupMenu(self)
984984 popup.insertItem('Delete Interface', 602)
985985 popup.insertSeparator()
990990 popup.insertSeparator()
991991 popup.insertItem('New note', 500)
992992 popup.insertItem('Show notes', 501)
993
994
993
994
995995
996996 self.contextpopups["Interface"] = popup
997997
998
998
999999 popup = qt.QPopupMenu(self)
10001000 popup.insertItem('Delete Service', 202)
10011001 popup.insertSeparator()
10081008 popup.insertItem('New Credential', 550)
10091009 popup.insertItem('Show Credentials', 551)
10101010 popup.insertItem('Import Creds', 561)
1011
1012
1011
1012
10131013
10141014 self.contextpopups["Service"] = popup
10151015
1016
1017
1018
1019
1020
1021
1022
1023
1016
1017
1018
1019
1020
1021
1022
1023
10241024 popup = qt.QPopupMenu(self)
10251025 popup.insertItem('Delete Items', 202)
10261026 popup.insertSeparator()
10331033
10341034 self.contextpopups["Service_Host"] = popup
10351035
1036
1037
1036
1037
10381038 popup = qt.QPopupMenu(self)
10391039 popup.insertItem('Add Service', 200)
10401040 popup.insertSeparator()
10461046 popup.insertSeparator()
10471047 popup.insertItem('New Credential', 550)
10481048 popup.insertItem('Import Creds', 561)
1049
1050
1049
1050
10511051
10521052 self.contextpopups["ServiceHost_Interface"] = popup
10531053
1054
1054
10551055 popup = qt.QPopupMenu(self)
1056
1057
1056
1057
10581058 popup.insertItem('Properties', 302)
10591059 popup.insertSeparator()
10601060 popup.insertItem('Add Host', 800)
10711071 popup.insertSeparator()
10721072 popup.insertItem('New Credential', 550)
10731073 popup.insertItem('Import Creds', 561)
1074
1075
1074
1075
10761076 self.contextpopups["CategoryWorkspace_Interface"] = popup
10771077
1078
1078
10791079 popup = qt.QPopupMenu(self)
1080
1081
1080
1081
10821082 popup.insertItem('Properties', 302)
10831083 popup.insertSeparator()
10841084 popup.insertItem('Add Host', 800)
10911091 popup.insertSeparator()
10921092 popup.insertItem('New Credential', 550)
10931093 popup.insertItem('Import Creds', 561)
1094
1095
1094
1095
10961096 self.contextpopups["CategoryWorkspace_ServiceHost"] = popup
10971097
10981098
1099
1100
1101
1102
1103
1104
1105
1106
1099
1100
1101
1102
1103
1104
1105
1106
11071107 def _setupContextDispatchers(self):
11081108 """
11091109 Configures a context dispatcher for each kind of item shown in the tree.
11161116 self.contextdispatchers[200] = self._newService
11171117 self.contextdispatchers[202] = self._delService
11181118
1119
1120
1119
1120
11211121 self.contextdispatchers[302] = self._showWorkspaceProperties
11221122 self.contextdispatchers[303] = self._resolveConflicts
11231123
532532 self.showConflictsDialog(event.local)
533533 elif event.type() == CHANGEFROMINSTANCE:
534534 self.newNotification(event.change)
535 elif event.type() == CONNECTION_REFUSED:
536 self.connectionRefused()
537
538 def connectionRefused(self):
539 self.showSimpleDialog("The connection to the database was lost. "
540 "Faraday will revert back to the Filesystem. "
541 "Fix your connection to CouchDB and reconnect "
542 "via the preferences dialog")
543
544 wm = self._main_app.getWorkspaceManager()
545 wm.closeWorkspace()
546 wm.resource()
547 wm.openWorkspace('untitled')
548
549 mwin = self._main_app.getMainWindow()
550 mwin.getWorkspaceTreeView().loadAllWorkspaces()
551 mwin.getWorkspaceTreeView().setDefaultWorkspace()
535552
536553 def update(self, event):
537554 if event.type() == EXCEPTION_ID:
1111 fi
1212
1313 update=0
14 #protection
15 sha_kali2_i686=d08b0562acc3da5a392509a1801d5569e1ace750d26d020b83ecc4c8eea4f191
16 sha_kali2_x86_64=f8ee223706bd306dbdba1bd9232f196878c598cb449d006e24edbcbe85f19f2a
17 sha_kali_i686=f071539d8d64ad9b30c7214daf5b890a94b0e6d68f13bdcc34c2453c99afe9c4
18 sha_kali_x86_64=02a050372fb30ede1454e1dd99d97e0fe0963ce2bd36c45efe90eec78df11d04
19 sha_ubuntu13_10_i686=8199904fb5fca8bc244c31b596c3ae0d441483bfbb2dc47f66186ceffbf3586e
20 sha_ubuntu13_10_x86_64=2b1af6f8d7463324f6df103455748e53cdb1edf6ee796056cdf2f701ccaef031
21 sha_ubuntu13_04_i686=d3632a393aa0bf869653afe252248de62e528c4e42ab49a0d16850ab89fda13e
22 sha_ubuntu13_04_x86_64=ea3010b8c3f81229a6b79c8d679005c1d482548223ebc448963d2d29aabe5692
2314
2415 #os detection
2516 arch=$(uname -m)
3930 os="$(uname -s) $(uname -r)"
4031 fi
4132
42 #Check if python2 is already installed
43 if ! which python2 > /dev/null; then
44 if ! which python2.7 > /dev/null; then
45 echo "[-] Please install Python2 or make sure it is in your path"
46 exit 1
47 fi
48 fi
33 echo "[+] Install $os $arch"
4934
50 echo "[+] Install $os $arch"
51 down=0
52 if [ "$os" = "Ubuntu 10.04.2 LTS" ]; then
53 version="ubuntu10-04.02$arch"
54 elif [[ "$os" =~ "Kali GNU/Linux 2."*|"Kali GNU/Linux Rolling".* ]]; then
55 version="kali2-$arch"
56 down=1
57 elif [[ "$os" =~ .*Kali.* ]]; then
58 version="kali-$arch"
59 down=1
60 elif [[ "$os" =~ "Ubuntu 12.04".* ]]; then
61 version="ubuntu12-$arch"
62 elif [ "$os" = "Ubuntu 13.10" ]; then
63 version="ubuntu13-10-$arch"
64 down=1
65 elif [ "$os" = "Ubuntu 13.04" ]; then
66 version="ubuntu13-04-$arch"
67 down=1
68 elif [[ "$os" =~ "Ubuntu 14.04".*|"Ubuntu 14.10".*|"Ubuntu Vivid Vervet (development branch)"|"Ubuntu 15".*|"Ubuntu 16".* ]]; then
69 version="ubuntu13-10-$arch"
70 down=1
71 # Install pip from github.
72 # Bug: https://bugs.launchpad.net/ubuntu/+source/python-pip/+bug/1306991
73 wget https://bootstrap.pypa.io/get-pip.py
74 python get-pip.py
75 elif [[ "$os" =~ "Mint 17".* ]]; then
76 version="ubuntu13-10-$arch"
77 down=1
78 # Install pip from github.
79 # Bug: https://bugs.launchpad.net/ubuntu/+source/python-pip/+bug/1306991
80 wget https://raw.github.com/pypa/pip/master/contrib/get-pip.py
81 python get-pip.py
82 elif [[ "$os" =~ "Debian 7".*|"Debian 8".*|"stretch/sid".* ]]; then
83 version="ubuntu13-10-$arch"
84 down=1
85 # Install pip from github.
86 # Bug: https://bugs.launchpad.net/ubuntu/+source/python-pip/+bug/1306991
87 wget https://bootstrap.pypa.io/get-pip.py
88 python get-pip.py
35 if [[ "$os" =~ "Debian 8".*|"stretch/sid".* ]]; then
8936
9037 #Check if user agree with change to experimental
9138 read -r -p "We need change your debian to experimental - sid branch (If you are not). You agree?[Y/n] " input
10148 echo "deb http://ftp.debian.org/debian experimental main" >> /etc/apt/sources.list
10249 echo "deb http://ftp.debian.org/debian sid main" >> /etc/apt/sources.list
10350 apt-get update
104
105 if [[ "$os" =~ "Debian 7".* ]]; then
106 apt-get -t experimental -y install libc6-dev
107 fi
108 else
109 echo "[-] Could not find a install for $os ($arch $kernel)"
110 exit
111 fi
112
113 if [ "$down" -eq 1 ]; then
114
115 if [ -e lib-$version.tgz ]; then
116 echo "[+] QT Libs already downloaded"
117 else
118 echo "[+] Download QT Libs"
119 wget "https://www.faradaysec.com/down/faraday/lib-$version.tgz" -O lib-$version.tgz
120 fi
121
122 shav="sha_${version//-/_}"
123 echo `sha256sum lib-$version.tgz`
124 if [ -e lib-$version.tgz ]; then
125 if [ "`echo ${!shav}`" = "`sha256sum lib-$version.tgz | awk -F\" \" \{'print $1'\}`" ]; then
126 echo "[+] SHA256 ok"
127 tar -xvzf lib-$version.tgz
128 mv lib-$version/ external_libs
129 else
130 rm lib-$version.tgz
131 echo "[-] SHA256 file corrupt, deleted run again ./$0"
132 exit
133 fi
134 else
135 echo "[-] Download error"
136 exit
137 fi
138 else
139 apt-get -y install python-qt3
51 update=1
14052 fi
14153
14254 if [ "$update" -eq 0 ]; then
14456 update=1
14557 fi
14658
147 apt-get --ignore-missing -y install ipython python-pip python-dev libpq-dev couchdb
59 apt-get --ignore-missing -y install ipython python-setuptools python-pip python-dev libpq-dev libffi-dev couchdb gir1.2-gtk-3.0 gir1.2-vte-2.91 python-gobject zsh curl
14860
149 #Check if python-setuptools not exists.
150 python -c "import setuptools" > /dev/null 2>&1
151
152 if [ "$?" -eq 1 ]; then
153 apt-get install python-setuptools
154 fi
155
156 #Delete debian experimental from sources.
157 if [[ "$os" =~ "Debian 7".*|"Debian 8".*|"stretch/sid".* ]]; then
158 sed -i 's/deb http:\/\/ftp.debian.org\/debian experimental main//' /etc/apt/sources.list
159 sed -i 's/deb http:\/\/ftp.debian.org\/debian sid main//' /etc/apt/sources.list
160 apt-get update
161 fi
162
163 pip install -r requirements.txt
61 pip2 install -r requirements.txt
16462
16563 echo "You can now run Faraday, enjoy!"
3838 self.active_workspace = None
3939
4040 def getWorkspacesNames(self):
41 """Returns the names of the workspaces as a list of strings"""
4142 return self.dbManager.getAllDbNames()
4243
4344 def createWorkspace(self, name, desc, dbtype=DBTYPE.FS):
8182 "For example: "
8283 "<couch_uri>http://john:[email protected]:5984</couch_uri>"))
8384 except Exception as e:
84 raise WorkspaceException(str(e))
85 return notification_center.CouchDBConnectionProblem(e)
86 #raise WorkspaceException(str(e))
8587 self.mappersManager.createMappers(dbConnector)
8688 workspace = self.mappersManager.getMapper(
8789 Workspace.__name__).find(name)
88 from config.configuration import getInstanceConfiguration
99 from model.common import ModelObject, ModelObjectNote, ModelObjectVuln, ModelObjectVulnWeb, ModelObjectCred, ModelComposite, ModelLeaf
1010 from model.common import Metadata
11 from utils.common import *
11 from utils.common import *
1212 from utils.decorators import updateLocalMetadata
1313
1414 import model.api as api
2727 The host has some attributes that are filled by the pen test tools run by
2828 the user
2929 """
30
30
3131 class_signature = "Host"
3232
3333 def __init__(self, name, os = "Unknown", default_gateway=None, dic=None, parent_id=None):
5050 if default_gateway is None else default_gateway
5151
5252 def _updatePublicAttributes(self):
53
53
5454 self.publicattrs['Operating System'] = 'getOS'
5555 self.publicattrsrefs['Operating System'] = '_operating_system'
5656
5858 """ Accept method for visitor in the host leaf"""
5959 for ints in self.getAllInterfaces():
6060 ints.accept(visitor)
61 visitor.visit(self)
61 visitor.visit(self)
6262
6363 def getCategories(self):
6464 return self.categories
6565
6666 def getCurrentCategory(self):
67
67
6868 cat = CONF.getDefaultCategory()
6969 try:
7070 cat = self.getCategories()[0]
7272 pass
7373 return cat
7474
75 def updateID(self):
75 def updateID(self):
7676 self._id = get_hash([self._name])
7777 self._prependParentId()
7878
79 def setOS(self, newOS):
79 def setOS(self, newOS):
8080 self._operating_system = newOS
8181
8282 def getOS(self):
8383 return self._operating_system
84
84
8585 operating_system = property(getOS, setOS)
8686
8787 def setName(self, newName):
88
88
8989 self._name = newName
9090
9191 def getName(self):
9292 return self._name
93
93
9494 name = property(getName, setName)
9595
9696 def getDefaultGateway(self):
9898
9999 def setDefaultGateway(self, default_gateway):
100100 self._default_gateway = default_gateway
101
101
102102
103103 #@save
104104 @updateLocalMetadata
118118 def getAllInterfaces(self, mode = 0):
119119 return self.getChildsByType(Interface.__name__)
120120
121 def getInterface(self, value):
122 """
123 value can be mac or ip address
124 if value is found it returns the interface objets
125 it returns None otherwise
126 """
127 return self.childs.get(value, None)
128
121 def getInterface(self, ID):
122 """Return the interface of id ID, None if ID wasn't an interface or
123 wasn't found among the children.
124 """
125 interface = self.findChild(ID)
126 return interface if interface.class_signature == "Interface" else None
129127
130128 def getService(self, name):
131129 """
146144
147145 @updateLocalMetadata
148146 def delApplication(self, appID): # Deprecated
149
147
150148 app = self.getApplication(appID)
151149 if app is not None:
152150 for srv in app.getAllServices():
153151 srv.delApplication(appID)
154
152
155153 return self._delValue("_applications", appID)
156154
157155 def addApplicationFull(self, app): # Deprecated # Deprecated
177175 if self._name == other_host.getName():
178176 return True
179177 else:
180
178
181179 ip_addr_this = self.getIPv4Addresses()
182180 ip_addr_other = other_host.getIPv4Addresses()
183
184
185
186
187
188
189
190
191
192
181
182
183
184
185
186
187
188
189
190
193191 for addr in ip_addr_this:
194192 if addr in ip_addr_other and IPy.IP(addr).iptype() == "PUBLIC":
195193 return True
196
194
197195 return False
198196
199 def __ne__(self, other_host):
197 def __ne__(self, other_host):
200198 return not self == other_host
201199
202200 def getIPv4Addresses(self):
219217 """
220218 An interface in a host
221219 """
222
220
223221 class_signature = "Interface"
224222
225223 def __init__(self, name = "", mac = "00:00:00:00:00:00",
231229
232230 ModelComposite.__init__(self, parent_id)
233231
234
232
235233 self._name = name
236234 self.mac = mac
237235 self.ipv4 = {
240238 "gateway" : ipv4_gateway,
241239 "DNS" : ipv4_dns
242240 }
243
241
244242 self.ipv6 = {
245243 "address" : ipv6_address,
246244 "prefix" : ipv6_prefix,
248246 "DNS" : ipv6_dns
249247 }
250248
251
249
252250 self._services = {}
253251
254
252
255253 self.network_segment = network_segment
256254
257
255
258256 self._hostnames=[]
259257 if hostname_resolution is not None:
260258 if isinstance(hostname_resolution, (str,unicode)):
267265 self.amount_ports_filtered = 0
268266
269267 def _updatePublicAttributes(self):
270
268
271269 self.publicattrs['MAC Address'] = 'mac'
272270 self.publicattrs['IPV4 Settings'] = 'ipv4'
273271 self.publicattrs['IPV6 Settings'] = 'ipv6'
296294 def accept(self, visitor):
297295 for servs in self.getAllServices():
298296 servs.accept(visitor)
299 visitor.visit(self)
300
301
297 visitor.visit(self)
298
299
302300 def tieBreakable(self, property_key):
303301 if property_key in ["_hostnames"]:
304302 return True
310308 return list(set(prop1))
311309 return None
312310
313 def updateID(self):
311 def updateID(self):
314312 self._id = get_hash([self.network_segment, self.ipv4["address"], self.ipv6["address"]])
315313 self._prependParentId()
316314
317315 def setName(self, name):
318316 self._name = name
319
317
320318 def getName(self):
321319 return self._name
322
323
320
321
324322
325323 def setMAC(self, mac):
326324 self.mac = mac
327
325
328326 def getMAC(self):
329327 return self.mac
330
328
331329 def setNetworkSegment(self, network_segment):
332330 self.network_segment = network_segment
333
331
334332 def getNetworkSegment(self):
335 return self.network_segment
336
333 return self.network_segment
334
337335 def setIPv4(self, ipv4):
338336 self.ipv4["address"] = ipv4.get("address", None)
339337 self.ipv4["mask"] = ipv4.get("mask", None)
340338 self.ipv4["gateway"] = ipv4.get("gateway", None)
341339 self.ipv4["DNS"] = ipv4.get("DNS", None)
342
340
343341 def getIPv4(self):
344342 return self.ipv4
345343
354352
355353 def getIPv4DNS(self):
356354 return self.ipv4["DNS"]
357
355
358356 def setIPv6(self, ipv6):
359357 self.ipv6["address"] = ipv6.get("address", None)
360358 self.ipv6["prefix"] = ipv6.get("prefix", None)
361359 self.ipv6["gateway"] = ipv6.get("gateway", None)
362360 self.ipv6["DNS"] = ipv6.get("DNS", None)
363
361
364362 def getIPv6(self):
365363 return self.ipv6
366364
375373
376374 def getIPv6DNS(self):
377375 return self.ipv6["DNS"]
378
376
379377 def setPortsOpened(self, ports_opened):
380378 self.amount_ports_opened = ports_opened
381
379
382380 def getPortsOpened(self):
383 return self.amount_ports_opened
384
381 return self.amount_ports_opened
382
385383 def setPortsClosed(self, ports_closed):
386384 self.amount_ports_closed = ports_closed
387
385
388386 def getPortsClosed(self):
389 return self.amount_ports_closed
390
387 return self.amount_ports_closed
388
391389 def setPortsFiltered(self, ports_filtered):
392390 self.amount_ports_filtered = ports_filtered
393
391
394392 def getPortsFiltered(self):
395393 return self.amount_ports_filtered
396394
397395 @updateLocalMetadata
398396 def addService(self, newService, update=False, setparent=True): # Deprecated
399 res = self._addValue("_services", newService, setparent=setparent, update=update)
397 res = self._addValue("_services", newService, setparent=setparent, update=update)
400398 if res: newService.addInterface(self)
401399 return res
402400
409407 def getAllServices(self, mode = 0):
410408 return self.getChildsByType(Service.__name__)
411409
412 def getService(self, name):
413 """
414 if name is found it returnsnetwork_segment the service object
415 it returns None otherwise
416 """
417 return self._getValueByID("_services", name)
410 def getService(self, ID):
411 """Get a Service from an ID. Return the service object if found,
412 None if ID wasn't a service or wasn't found among the children.
413 """
414 service = self.findChild(ID)
415 return service if service.class_signature == "Service" else None
418416
419417 def setServices(self, services):
420418 self._addChildsDict(services)
429427
430428 def getHostnames(self):
431429 return self._hostnames
432
430
433431 def setHostnames(self, hostnames):
434432 self._hostnames = hostnames
435433
469467 Commonly a service will have a name or description, a set of ports in which
470468 is listening and also a particular version
471469 """
472
470
473471 class_signature = "Service"
474472
475473 def __init__(self, name, protocol="TCP", ports=None, status="running",
488486 self._creds = {}
489487
490488 def _updatePublicAttributes(self):
491
489
492490 self.publicattrsrefs['Ports'] = '_ports'
493491 self.publicattrsrefs['Protocol'] = '_protocol'
494492 self.publicattrsrefs['Status'] = '_status'
502500
503501 def setName(self, name):
504502 self._name = name
505
503
506504 def getName(self):
507505 return self._name
508506
523521
524522 def getPorts(self):
525523 return self._ports
526
524
527525 def setPorts(self, ports):
528526 if ports is not None:
529527 if isinstance(ports, (str,unicode)):
547545 def getVersion(self):
548546 return self._version
549547
550 def updateID(self):
548 def updateID(self):
551549 self._id = get_hash([self._protocol, ":".join(str(self._ports))])
552550 self._prependParentId()
553551
554552 #@save
555553 @updateLocalMetadata
556 def updateAttributes(self, name=None, description=None, protocol=None, ports=None,
554 def updateAttributes(self, name=None, description=None, protocol=None, ports=None,
557555 status=None, version=None, owned=None):
558556 if name is not None:
559557 self.setName(name)
560558 if description is not None:
561559 self.setDescription(description)
562560 if protocol is not None:
563 self.setProtocol(protocol)
561 self.setProtocol(protocol)
564562 if ports is not None:
565563 self.setPorts(ports)
566564 if status is not None:
568566 if version is not None:
569567 self.setVersion(version)
570568 if owned is not None:
571 self.setOwned(owned)
569 self.setOwned(owned)
572570
573571 def _checkFullDelete(self):
574572 api.devlog("Doing service checkFullDelete")
584582 """
585583 return self._getAllValues("_interfaces", mode)
586584
587 def getInterface(self, value):
588 """
589 value can be a mac or ipv4 address
590 if value is found it returns the interface objets
591 it returns None otherwise
592 """
593 return self._getValueByID("_interfaces", value)
585 def getInterface(self, ID):
586 """Gets the interface with id ID. If ID isn't found or isn't an
587 interface, return None.
588 """
589 interface = self.findChild(ID)
590 return interface if interface.class_signature == "Interface" else None
594591
595592 def addApplication(self, newApp, update=False): # Deprecated
596593 res = self._addValue("_applications", newApp, update=update)
628625 The application can be related to more than one service
629626 Commonly this will have a name, description, version and status
630627 """
631
628
632629 class_signature = "HostApplication"
633630
634631 def __init__(self, name, status = "running", version = "unknonw"):
637634 self._name = name
638635 self._status = status
639636 self._version = version
640
637
641638 self._services = {}
642639
643 def _updatePublicAttributes(self):
640 def _updatePublicAttributes(self):
644641 self.publicattrs['Status'] = 'getStatus'
645642 self.publicattrs['Version'] = 'getVersion'
646643
647644 def setName(self, name):
648645 self._name = name
649
646
650647 def getName(self):
651 return self._name
652
648 return self._name
649
653650 def setStatus(self, status):
654651 self._status = status
655652
665662 def updateID(self):
666663 self._id = get_hash([self._name, self._version])
667664 self._prependParentId()
668
665
669666 @updateLocalMetadata
670667 def updateAttributes(self, name=None, description=None, status=None, version=None, owned=None):
671668 if name is not None:
704701 """
705702 return self._getAllValues("_services", mode)
706703
707 def getService(self, name):
704 def getService(self, ID):
708705 """
709706 if name is found it returns the service object
710707 it returns None otherwise
3636 }
3737
3838 def unserialize(self, mobj, doc):
39 mobj_type = mobj.class_signature
3940 self.children = self.findChildren(mobj.getID())
4041 mobj.setName(doc.get("name"))
4142 mobj.setOwned(doc.get("owned"))
4243 if doc.get("parent", None):
4344 mobj.setParent(self.mapper_manager.find(doc.get("parent")))
4445 mobj.setOwner(doc.get("owner"))
45 mobj.setDescription(doc.get("description"))
46 # NOTE: Vulnerability and VulnerabilityWeb, when modified from the web,
47 # have a 'desc' key, not a description key, which is already handled
48 # by their specific unserialize method
49 if mobj_type != 'Vulnerability' and mobj_type != 'VulnerabilityWeb':
50 mobj.setDescription(doc.get("description"))
4651 mobj.setMetadata( Metadata('').fromDict(mobj.getMetadata().__dict__))
4752 if self.children:
4853 self.setNotes(mobj)
265270 return doc
266271
267272 def unserialize(self, vuln_web, doc):
273 vuln_web.setDesc(doc.get("desc"))
268274 vuln_web.setWebsite(doc.get("website"))
269275 vuln_web.setPath(doc.get("path"))
270276 vuln_web.setRequest(doc.get("request"))
1010 import mockito
1111 import restkit
1212 import threading
13 import requests
14 import time
1315 from urlparse import urlparse
1416 import traceback
1517 from couchdbkit import Server, ChangesStream, Database
2123 #from persistence.change import change_factory
2224 from config.globals import CONST_BLACKDBS
2325 from config.configuration import getInstanceConfiguration
26
2427 CONF = getInstanceConfiguration()
2528
2629
131134
132135 def setChangesCallback(self, callback):
133136 self.changes_callback = callback
137
138 def setCouchExceptionCallback(self, callback):
139 self.couch_exception_callback = callback
134140
135141 def waitForDBChange(self):
136142 pass
234240 getLogger(self).warn(
235241 "You're not authorized to upload views to this database")
236242 self.seq_num = self.db.info()['update_seq']
243 test_couch_thread = threading.Thread(target=self.continuosly_check_connection)
244 test_couch_thread.daemon = True
245 test_couch_thread.start()
237246
238247 def getDocs(self):
239248 if len(self._docs.keys()) == 0:
290299 return res
291300
292301 def forceUpdate(self):
302 """It will try to update the information on the DB if it can.
303 The except clause is necesary to catch the case where we've lost
304 the connection to the DB.
305 """
306
293307 doc = self.getDocument(self.db.dbname)
294 return self.db.save_doc(doc, use_uuids=True, force_update=True)
308 try:
309 return self.db.save_doc(doc, use_uuids=True, force_update=True)
310 except:
311 return False
295312
296313 #@trap_timeout
297314 def getDocument(self, document_id):
345362 def setSeqNumber(self, seq_num):
346363 self.seq_num = seq_num
347364
365 def continuosly_check_connection(self):
366 """Intended to use on a separate thread. Call module-level
367 function testCouch every second to see if response to the server_uri
368 of the DB is still 200. Call the exception_callback if we can't access
369 the server three times in a row.
370 """
371 tolerance = 0
372 server_uri = self.db.server_uri
373 while True:
374 time.sleep(1)
375 test_was_successful = test_couch(server_uri)
376 if test_was_successful:
377 tolerance = 0
378 else:
379 tolerance += 1
380 if tolerance == 3:
381 self.couch_exception_callback()
382 return False # kill the thread if something went wrong
383
348384 #@trap_timeout
349385 def waitForDBChange(self, since=0):
386 """Listen to the stream of changes provided by CouchDbKit. Process
387 these changes accordingly. If there's an exception while listening
388 to the changes, return inmediatly."""
389
390 # XXX: the while True found here shouldn't be necessary because
391 # changesStream already keeps listening 'for ever'. In a few tests
392 # I ran, this hypothesis was confirmed, but with our current setup
393 # i'm afraid I may be missing something. In any case, it works
394 # as it is, but this definitevely needs revision.
395
350396 getLogger(self).debug(
351397 "Watching for changes")
352398 while True:
377423 except Exception as e:
378424 getLogger(self).info("Some exception happened while waiting for changes")
379425 getLogger(self).info(" The exception was: %s" % e)
426 return False # kill thread, it's failed... in reconnection
427 # another one will be created, don't worry
380428
381429 #@trap_timeout
382430 def _compactDatabase(self):
467515
468516
469517 class NoCouchDBError(Exception):
470 pass
518 def __init__(self):
519 Exception.__init__(self, "NoCouchDBError")
471520
472521
473522 class NoConectionServer(object):
518567 getLogger(self).warn("No route to couchdb server on: %s" % uri)
519568 getLogger(self).debug(traceback.format_exc())
520569
570
521571 #@trap_timeout
522572 def _create(self, name):
523573 db = self.__serv.create_db(name.lower())
530580 #@trap_timeout
531581 def _loadDbs(self):
532582 conditions = lambda x: not x.startswith("_") and x not in CONST_BLACKDBS
533 for dbname in filter(conditions, self.__serv.all_dbs()):
534 if dbname not in self.dbs.keys():
535 getLogger(self).debug(
536 "Asking for dbname[%s], registering for lazy initialization" % dbname)
537 self.dbs[dbname] = lambda x: self._loadDb(x)
583 try:
584 for dbname in filter(conditions, self.__serv.all_dbs()):
585 if dbname not in self.dbs.keys():
586 getLogger(self).debug(
587 "Asking for dbname[%s], registering for lazy initialization" % dbname)
588 self.dbs[dbname] = lambda x: self._loadDb(x)
589 except restkit.errors.RequestError as req_error:
590 getLogger(self).error("Couldn't load databases. "
591 "The connection to the CouchDB was probably lost. ")
538592
539593 def _loadDb(self, dbname):
540594 db = self.__serv.get_db(dbname)
542596 self.dbs[dbname] = CouchDbConnector(db, seq_num=seq)
543597 return self.dbs[dbname]
544598
599 def refreshDbs(self):
600 """Refresh databases using inherited method. On exception, asume
601 no databases are available.
602 """
603 try:
604 return AbstractPersistenceManager.refreshDbs()
605 except:
606 return []
545607
546608 #@trap_timeout
547609 def pushReports(self):
573635
574636 @staticmethod
575637 def testCouch(uri):
576 if uri is not None:
577 host, port = None, None
578 try:
579 import socket
580 url = urlparse(uri)
581 proto = url.scheme
582 host = url.hostname
583 port = url.port
584
585 port = port if port else socket.getservbyname(proto)
586 s = socket.socket()
587 s.settimeout(1)
588 s.connect((host, int(port)))
589 except:
590 return False
591 #getLogger(CouchdbManager).info("Connecting Couch to: %s:%s" % (host, port))
592 return True
638 """Redirect to the module-level function of the name, which
639 serves the same purpose and is used by other classes too."""
640 return test_couch(uri)
593641
594642 def testCouchUrl(self, uri):
595643 if uri is not None:
628676 self.__serv.replicate(workspace, dst, mutual = mutual, continuous = continuous, create_target = ct)
629677 if mutual:
630678 self.__serv.replicate(dst, src, continuous = continuous, **kwargs)
679
680
681 def test_couch(uri):
682 """Return True if we could access uri/_all_dbs, which should happen
683 if we have an Internet connection, Couch is up and we have the correct
684 permissions (response_code == 200)
685 """
686 try:
687 response_code = requests.get(uri + '/_all_dbs').status_code
688 return True if response_code == 200 else False
689 except requests.adapters.ConnectionError:
690 return False
0 '''
1 Faraday Penetration Test IDE
2 Copyright (C) 2016 Infobyte LLC (http://www.infobytesec.com/)
3 See the file 'doc/LICENSE' for the license information
4
5 '''
6
0 #!/usr/bin/env python
1 # -*- coding: utf-8 -*-
2
3 '''
4 Faraday Penetration Test IDE
5 Copyright (C) 2016 Infobyte LLC (http://www.infobytesec.com/)
6 See the file 'doc/LICENSE' for the license information
7
8 '''
9 from plugins import core
10 from model import api
11 import re
12 import os
13 import socket
14
15 __author__ = "Ulisses Albuquerque"
16 __copyright__ = "Copyright (c) 2016, Securus Global"
17 __credits__ = ["Ulisses Albuquerque"]
18 __license__ = ""
19 __version__ = "1.0.0"
20 __maintainer__ = "Ulisses Albuquerque"
21 __email__ = "[email protected]"
22 __status__ = "Development"
23
24
25 class CmdNetcatPlugin(core.PluginBase):
26 """
27 This plugin handles ping command.
28 Basically detects if user was able to connect to a device
29 """
30 def __init__(self):
31 core.PluginBase.__init__(self)
32 self.id = "netcat"
33 self.name = "Netcat"
34 self.plugin_version = "0.0.1"
35 self.version = "1.0.0"
36 self._command_regex = re.compile(r'^(?:.*\|)?\s*(?:nc|netcat|nc.openbsd|nc.traditional)\s+.*$')
37 self._completition = {
38 "": "[-bhklnrtuvCz] [-c shell] [-e filename] [-g gateway] [-G num] [-i secs] [-o file] [-p port] [-q secs] [-s addr] [-T tos] [-w secs]",
39 "-c": "shell",
40 "-e": "filename",
41 "-b": "allow broadcasts",
42 "-g": "gateway",
43 "-G": "num",
44 "-h": "this cruft",
45 "-i": "secs",
46 "-k": "set keepalive option on socket",
47 "-l": "listen mode, for inbound connects",
48 "-n": "numeric-only IP addresses, no DNS",
49 "-o": "file",
50 "-p": "port",
51 "-r": "randomize local and remote ports",
52 "-q": "secs",
53 "-s": "addr",
54 "-T": "tos",
55 "-t": "answer TELNET negotiation",
56 "-u": "UDP mode",
57 "-v": "verbose [use twice to be more verbose]",
58 "-w": "secs",
59 "-C": "Send CRLF as line-ending",
60 "-z": "zero-I/O mode [used for scanning]",
61 }
62
63 def resolveHost(self, host):
64 """
65 The use of gethostbyname/gethostbyaddr here is questionable, but it is
66 the easiest way to sort out the discrepancies between the output
67 formats of both versions of netcat
68 """
69 if re.search(r'^\d{1,3}(?:\.\d{1,3}){3}', host) is not None:
70 try:
71 result = socket.gethostbyaddr(host)
72 return (host, result[0])
73 except:
74 return (host, None)
75 else:
76 try:
77 result = socket.gethostbyname(host)
78 return (result, host)
79 except:
80 return (None, host)
81
82 def addEntry(self, attr_dict):
83 """
84 Because output differs between both versions of netcat, and because
85 the user might use the -n parameter which disables name resolution,
86 we need to check if the values we are getting are hostnames or IP
87 addresses
88 """
89 ip_address, hostname = self.resolveHost(attr_dict['host'])
90
91 # When service does not match anything in /etc/services, we get those
92 if attr_dict['service'] == '*' or attr_dict['service'] == '?' or attr_dict['service'] is None:
93 attr_dict['service'] = 'unknown'
94
95 if 'protocol' not in attr_dict:
96 attr_dict['protocol'] = 'tcp'
97
98 h_id = self.createAndAddHost(hostname)
99 i_id = self.createAndAddInterface(h_id, ip_address, ipv4_address = ip_address)
100 s_id = self.createAndAddServiceToInterface(h_id, i_id, attr_dict['service'],
101 protocol = attr_dict['protocol'], ports = [ int(attr_dict['port']) ])
102
103 def matchInOutput(self, regexp, output):
104 """
105 We take a split & filter approach to matching our regexps to the
106 command output
107 """
108 mapped_list = map(lambda s: re.search(regexp, s), re.split(r'(\r|\n)', output))
109 filtered_list = filter(lambda s: s is not None, mapped_list)
110
111 if len(filtered_list) > 0:
112 return filtered_list[0]
113 else:
114 return None
115
116 def parseOutputString(self, output, debug = False):
117 """
118 There are at least two variants of netcat, the OpenBSD version and the
119 'traditional' version. The verbose output differs between them, so we
120 will try to cover both cases.
121 """
122 print output
123 nc_bsd_rx = re.compile(r'^Connection\s+to\s+(?P<host>\S+)\s+(?P<port>\d+)\s+port\s+\[(?P<protocol>tcp|udp)/(?P<service>[^\]]+)\]\s+succeeded.*')
124 nc_sys_rx = re.compile(r'^(?P<host>\S+)\s+\[(?P<address>[0-9\.]+)\]\s+(?P<port>\d+)(?:\s+\((?P<service>[^)]+)\))?\s+open.*')
125
126 nc_bsd_match = self.matchInOutput(nc_bsd_rx, output)
127 if nc_bsd_match is not None:
128 self.addEntry(nc_bsd_match.groupdict())
129
130 nc_sys_match = self.matchInOutput(nc_sys_rx, output)
131 if nc_sys_match is not None:
132 self.addEntry(nc_sys_match.groupdict())
133
134 return True
135
136 def processCommandString(self, username, current_path, command_string):
137 """
138 We need to use '-v' because otherwise netcat does not provide any
139 output to indicate whether a connection has been successful; our
140 regexp can certainly be improved, because we might get '-v' combined
141 with other parameters, like in "nc -nv"
142 """
143 if re.search(r'(nc|netcat)[^\d|\|]*-v', command_string) is None:
144 return re.sub(r'(nc(?:\.traditional|\.openbsd)?|netcat)', r'\1 -v', command_string)
145
146 return command_string
147
148 def createPlugin():
149 return CmdNetcatPlugin()
0 couchdbkit==0.6.5
1 mockito==0.5.1
2 whoosh==2.5.5
3 argparse==1.1
4 IPy==0.75
5 restkit==4.2.2
6 requests==2.7.0
7 tornado==3.2
8 flask==0.10.1
9 colorama==0.3.2
0 couchdbkit
1 mockito
2 whoosh
3 argparse
4 IPy
5 restkit
6 requests
7 tornado
8 flask
9 colorama
10 twisted
11 sqlalchemy
1012 #extra
11 psycopg2==2.5.4
13 psycopg2
4949 BUFFER=" $new_cmd"
5050 fi
5151 FARADAY_OUTPUT=`mktemp tmp.XXXXXXXXXXXXXXXXXXXXXXXXXXXXX`
52 BUFFER="$BUFFER >&1 >> $FARADAY_OUTPUT"
52 BUFFER="$BUFFER 2>&1 | tee -a $FARADAY_OUTPUT"
5353 fi
5454 fi
5555 zle .accept-line "$@"