def addInDb(self): """ Add this IP in database. Returns: a tuple with : * bool for success * mongo ObjectId : already existing object if duplicate, create object id otherwise """ # Checking unicity if self.ip.strip() == "": raise ValueError("Ip insertion error: Cannot insert empty ip") base = self.getDbKey() apiclient = APIClient.getInstance() # Add ip as it is unique base["notes"] = self.notes base["tags"] = self.tags base["in_scopes"] = self.in_scopes base["infos"] = self.infos resInsert, idInsert = apiclient.insert("ips", base) self._id = idInsert # adding the appropriate tools for this port. # 1. fetching the wave's commands return resInsert, self._id
def addUser(self): apiclient = APIClient.getInstance() if self.confirmpassword.get() != self.password.get(): tk.messagebox.showerror( "Add user failed", "The password does not match the confirmation") username = self.entryAddUser.get() passw = self.password.get() name = self.name.get() surname = self.surname.get() email = self.email.get() apiclient.registerUser(username, passw, name, surname, email) self.userTv.insert('', 'end', username, text=username, values=( "Change pass", '', name, surname, email, ))
def addDomainInDb(self, checkDomain=True): """ Add this scope domain in database. Args: checkDomain: boolean. If true (Default), checks that the domain IP is in scope Returns: a tuple with : * bool for success * mongo ObjectId : already existing object if duplicate, create object id otherwise """ # Checking unicity base = self.getDbKey() apiclient = APIClient.getInstance() # Check if domain's ip fit in one of the Scope of the wave if checkDomain: if not Scope.checkDomainFit(self.wave, self.scope): return -1, None # insert the domains in the scopes res_insert, iid = apiclient.insert("scopes", base) self._id = iid # Adding appropriate tools for this scopes return 1, iid
def addDCinDb(self, ip): apiclient = APIClient.getInstance() existing = apiclient.findInDb(apiclient.getCurrentPentest(), ActiveDirectory.collName, { "type": "computer", "ip": ip }, False) if existing is None: apiclient.insertInDb(apiclient.getCurrentPentest(), ActiveDirectory.collName, { "type": "computer", "domain": "", "isDC": True, "name": "", "ip": ip, "OS": "", "signing": True, "SMBv1": "", "users": [], "admins": [] }, notify=True) else: apiclient.updateInDb(apiclient.getCurrentPentest(), ActiveDirectory.collName, {"_id": ObjectId(existing["_id"])}, {"$set": { "isDC": True }}, notify=True) if not existing.get("isDC", False): if len(existing.get("users", [])) > 0: self.newComputerEvent("OnDCFirstUser", existing.get("users", [])[0], ip) if len(existing.get("admins", [])) > 0: self.newComputerEvent("OnDCFirstAdmin", existing.get("admins", [])[0], ip)
def _commonWindowForms(self, default={}): """Construct form parts identical between Modify and Insert forms Args: default: a dict of default values for inputs (sleep_between, priority, max_thread). Default to empty respectively "0", "0", "1" """ self.form.addFormHidden("owner", default.get("owner", "")) panel_bottom = self.form.addFormPanel(grid=True) row = 0 panel_bottom.addFormLabel("Binary path", row=row) panel_bottom.addFormStr("Bin path", r"", default.get("bin_path", ""), width=30, column=1, row=row) panel_bottom.addFormHelper( "The local binary path to use for this command.", column=2, row=row) row += 1 panel_bottom.addFormLabel("Plugin", row=row) panel_bottom.addFormCombo("Plugin", APIClient.getInstance().getPlugins(), default.get("plugin", "Default") ,width=30, column=1, row=row) panel_bottom.addFormHelper( "The plugin handling this command.", column=2, row=row) row += 1 panel_bottom.addFormLabel("Timeout (in secondes)", row=row) panel_bottom.addFormStr("Timeout", r"\d+", default.get("timeout", "300"), width=10, column=1, row=row) panel_bottom.addFormHelper( "The tool will cancel itself when this duration in second is reached to be run again later.", column=2, row=row) row += 1 panel_bottom.addFormLabel("Delay", row=row) panel_bottom.addFormStr("Delay", r"\d+", default.get("sleep_between", "0"), width=5, column=1, row=row) panel_bottom.addFormHelper( "Delay in-between two launch of this command (in seconds)", column=2, row=row) panel_bottom.addFormLabel("Priority", row=row) panel_bottom.addFormStr("Priority", r"\d+", default.get("priority", "0"), width=2, row=row, column=1) panel_bottom.addFormHelper( "Priority in queue (0 is HIGHEST)", row=row, column=2) panel_bottom.addFormLabel("Threads", row=row) panel_bottom.addFormStr("Threads", r"\d+", default.get("max_thread", "1"), width=2, row=row, column=1) panel_bottom.addFormHelper( "Number of authorized parallel running of this command on one worker.", row=row, column=2)
def notify(self, db, collection, iid, action, _parent): """ Callback for the observer implemented in mongo.py. Each time an object is inserted, updated or deleted the standard way, this function will be called. Args: collection: the collection that has been modified iid: the mongo ObjectId _id that was modified/inserted/deleted action: string "update" or "insert" or "delete". It was the action performed on the iid _parent: Not used. the mongo ObjectId of the parent. Only if action in an insert. Not used anymore """ apiclient = APIClient.getInstance() if not apiclient.getCurrentPentest() != "": return if apiclient.getCurrentPentest() != db: return if collection == ActiveDirectory.collName: self.handleActiveDirectoryNotif(iid, action) elif collection == "ports" and action != "delete": port_o = Port.fetchObject({"_id": ObjectId(iid)}) if int(port_o.port) == 445: self.loadInfoFromPort(port_o) if int(port_o.port) == 88: self.addDCinDb(port_o.ip)
def onOk(self, event=None): """ Called when the user clicked the validation button. Try a full connection with authentication to the host given. Side effects: - Open dialogs if the connection failed. Does not close this dialog. - If the connections succeeded : write the client.cfg file accordingly. """ # send the data to the parent config = self.getForm() apiclient = APIClient.getInstance() apiclient.reinitConnection() res = apiclient.tryConnection(config) self.rvalue = False if res: # pylint: disable=len-as-condition loginRes = apiclient.login(self.ent_login.get(), self.password.get()) if loginRes: self.rvalue = True self.app.destroy() else: tk.messagebox.showerror("Connection failure", "The login/password you entered does not exists") else: tk.messagebox.showerror("Connection failure", "The host is not responding. Check if server is alive or if you have a local proxy configured.")
def launchCallback(self, _event=None): """ Callback for the launch tool button. Will queue this tool to a worker. #TODO move to ToolController Will try to launch respecting limits first. If it does not work, it will asks the user to force launch. Args: _event: Automatically generated with a button Callback, not used. """ res = self.safeLaunchCallback() if not res: dialog = ChildDialogQuestion( self.appliViewFrame, "Safe queue failed", "This tool cannot be launched because no worker add space for its thread.\nDo you want to launch it anyway?" ) self.appliViewFrame.wait_window(dialog.app) answer = dialog.rvalue if answer == "Yes": apiclient = APIClient.getInstance() apiclient.sendLaunchTask(self.controller.model.getId(), False) if res: self.form.clear() for widget in self.appliViewFrame.winfo_children(): widget.destroy() self.openModifyWindow()
def savePentestSettings(self): apiclient = APIClient.getInstance() settings = apiclient.find("settings") existing_settings = {} for setting in settings: existing_settings[setting["key"]] = setting for k, v in self.db_settings.items(): if k in existing_settings: if k == "tags": for line_key, line_value in v.items(): tag, color = line_key, line_value if tag not in existing_settings["tags"]["value"]: apiclient.registerTag(tag, color, False) else: apiclient.updateTag(tag, color, False) for tag in existing_settings["tags"].get("value", {}): if tag not in v: apiclient.unregisterTag(tag, False) else: apiclient.updateInDb(apiclient.getCurrentPentest(), "settings", {"key": k}, {"$set": { "value": v }})
def displayData(self): """ Display loaded data in treeviews """ dialog = ChildDialogProgress( self.parent, "Loading dashboard ", "Refreshing dashboard. Please wait for a few seconds.", 200, "determinate") dialog.show(10) # Reset Ip treeview for children in self.treevw.get_children(): self.treevw.delete(children) dialog.update(1) listOfip = [] for ip in self.ips: servicesCount = len([x for x in Port.fetchObjects({"ip": ip.ip})]) listOfip.append((ip.ip, servicesCount)) dialog.update(2) listOfip.sort(key=lambda tup: tup[1], reverse=True) for i in range(len(listOfip)): self.treevw.insert('', 'end', i, text=listOfip[i][0], values=(listOfip[i][1])) dialog.update(3) # Reset Port treeview for children in self.treevwport.get_children(): self.treevwport.delete(children) dialog.update(4) portCounts = {} for port in self.ports: if port.port not in portCounts.keys(): portCounts[port.port] = 1 else: portCounts[port.port] += 1 dialog.update(5) port_id = 0 # Ordering dictionnary portCounts = { k: v for k, v in sorted( portCounts.items(), key=lambda item: item[1], reverse=True) } for portCount in portCounts: self.treevwport.insert('', 'end', port_id, text=str(portCount), values=(portCounts[portCount])) port_id += 1 dialog.update(6) # Tool part # Reset Tools treeview for children in self.treevwtools.get_children(): self.treevwtools.delete(children) dialog.update(7) listOfTools = [_ for _ in self.tools] listOfTools.sort(key=lambda x: x.status, reverse=True) result = APIClient.getInstance().aggregate("tools", [{ "$group": { "_id": { "name": "$name", "status": "$status", "wave": "$wave" }, "count": { "$sum": 1 } } }]) result = [_ for _ in result] tools_dashboard = {} for tool_result in result: tool_id = tool_result["_id"].get( "wave", "") + "::" + tool_result["_id"]["name"] tools_dashboard[tool_id] = tools_dashboard.get(tool_id, {}) tool_status = list(tool_result["_id"].get("status", "ready")) if not tool_status: tool_status = ["ready"] tools_dashboard[tool_id][tool_status[0]] = tool_result["count"] dialog.update(8) for tool_id in sorted(list(tools_dashboard.keys())): self.treevwtools.insert( '', 'end', None, text=str(tool_id), values=(tools_dashboard[tool_id].get("ready", 0), tools_dashboard[tool_id].get("running", 0), tools_dashboard[tool_id].get("done", 0), tools_dashboard[tool_id].get("error", 0) + tools_dashboard[tool_id].get("timedout", 0))) dialog.update(9) # Defect Part # reset defect TW for children in self.treevwDefaults.get_children(): self.treevwDefaults.delete(children) result = APIClient.getInstance().aggregate("defects", [{ "$group": { "_id": { "risk": "$risk", "type": "$type" }, "count": { "$sum": 1 } } }]) dialog.update(10) result = [_ for _ in result] result.sort(key=lambda x: x["count"], reverse=True) for defect in result: defectRisk = defect["_id"]["risk"] defectType = " ".join(defect["_id"]["type"]) defectCount = defect["count"] self.treevwDefaults.insert('', 'end', None, text=str(defectRisk), values=(defectType, defectCount)) dialog.destroy()
def open(self): apiclient = APIClient.getInstance() if apiclient.getCurrentPentest() is not None: self.refreshUI() return True
def openModifyWindow(self): """ Creates a tkinter form using Forms classes. This form aims to update or delete an existing Port """ modelData = self.controller.getData() top_panel = self.form.addFormPanel(grid=True) top_panel.addFormLabel("IP", row=0, column=0) top_panel.addFormStr("IP", '', modelData["ip"], None, column=1, row=0, state="readonly") top_panel.addFormLabel("Number", column=0, row=1) top_panel.addFormStr("Number", '', modelData["port"], None, column=1, row=1, state="readonly") top_panel.addFormLabel("Proto", row=2, column=0) top_panel.addFormStr("Proto", '', modelData["proto"], None, column=1, row=2, state="readonly") top_panel.addFormLabel("Service", row=3) top_panel.addFormStr("Service", r"", modelData["service"], column=1, row=3) if "http" in modelData["service"]: top_panel.addFormButton("Open in browser", self.openInBrowser, column=2, row=3) top_panel.addFormLabel("Product", row=4) top_panel.addFormStr("Product", r"", modelData["product"], width=40, row=4, column=1) top_panel = self.form.addFormPanel() top_panel.addFormLabel("Notes", side="top") top_panel.addFormText("Notes", r"", modelData["notes"], None, side="top", height=10) top_panel.addFormLabel("Infos", side="left") top_panel.addFormText("Infos", is_json, json.dumps(modelData["infos"], indent=4), side="left", fill="both", height=5) command_list = Command.fetchObjects( {"lvl": "port"}, APIClient.getInstance().getCurrentPentest()) command_names = ["None"] self.command_names_to_iid = {} for command_doc in command_list: command_names.append(command_doc.name) self.command_names_to_iid[command_doc.name] = str(command_doc._id) self.tool_panel = self.form.addFormPanel(grid=True) self.tool_panel.addFormLabel("Tool to add") self.tool_panel.addFormCombo("Tool to add", command_names, "None", column=1) self.tool_panel.addFormButton("Add tool", self._addTool, column=2) top_panel = self.form.addFormPanel(grid=True) top_panel.addFormButton("Add a security defect", self.addDefectCallback) self.form.addFormHidden("ip", modelData["ip"]) self.completeModifyWindow()
def loadData(self): """ Fetch data from database """ apiclient = APIClient.getInstance() self.auths = apiclient.find("auths")
def addToMyCommands(self): apiclient = APIClient.getInstance() apiclient.addCommandToMyCommands(self.getId())
def _load(self): """ Load the treeview with database information """ apiclient = APIClient.getInstance() dialog = ChildDialogProgress( self.appli, "Loading " + str(apiclient.getCurrentPentest()), "Opening " + str(apiclient.getCurrentPentest()) + ". Please wait for a few seconds.", 200, "determinate") step = 0 dialog.show(100) nbObjects = apiclient.count("waves", ) nbObjects += apiclient.count("scopes") nbObjects += apiclient.count("intervals") nbObjects += apiclient.count("scopes") nbObjects += apiclient.count("ips") nbObjects += apiclient.count("ports") nbObjects += apiclient.count("tools") nbObjects += apiclient.count("commands") onePercentNbObject = nbObjects // 100 if nbObjects > 100 else 1 nbObjectTreated = 0 self.delete(*self.get_children()) self._hidden = [] self._detached = [] self.waves_node = self.insert("", "end", str("waves"), text="Waves", image=WaveView.getClassIcon()) # Loading every category separatly is faster than recursivly. # This is due to cursor.next function calls in pymongo # Adding wave objects self.commands_node = self.insert("", "end", "commands", text="Commands", image=CommandView.getClassIcon()) self.group_command_node = self.insert( "", "end", "groupcommands", text="Command Groups", image=CommandGroupView.getClassIcon()) self.my_group_command_node = self.insert( self.group_command_node, "end", "mygroupcommands", text="My Command Groups", image=CommandGroupView.getClassIcon()) self.worker_group_command_node = self.insert( self.group_command_node, "end", "workergroupcommands", text="Worker Command Groups", image=CommandGroupView.getClassIcon()) self.my_commands_node = self.insert(self.commands_node, "end", "mycommands", text="My commands", image=CommandView.getClassIcon()) self.worker_commands_node = self.insert( self.commands_node, "end", "workercommands", text="Worker commands", image=CommandView.getClassIcon()) self.others_commands_node = self.insert( self.commands_node, "end", "otherscommands", text="Others commands", image=CommandView.getClassIcon()) commands = Command.fetchObjects({}, apiclient.getCurrentPentest()) for command in commands: command_vw = CommandView(self, self.appli.viewframe, self.appli, CommandController(command)) command_vw.addInTreeview() group_commands = CommandGroup.fetchObjects( {}, apiclient.getCurrentPentest()) for command_groupe_vw in group_commands: command_groupe_vw = CommandGroupView( self, self.appli.viewframe, self.appli, CommandGroupController(command_groupe_vw)) command_groupe_vw.addInTreeview() waves = Wave.fetchObjects({}) for wave in waves: wave_o = WaveController(wave) wave_vw = WaveView(self, self.appli.viewframe, self.appli, wave_o) wave_vw.addInTreeview(self.waves_node, False) nbObjectTreated += 1 if nbObjectTreated % onePercentNbObject == 0: step += 1 dialog.update(step) scopes = Scope.fetchObjects({}) for scope in scopes: scope_o = ScopeController(scope) scope_vw = ScopeView(self, self.appli.viewframe, self.appli, scope_o) scope_vw.addInTreeview(None, False) nbObjectTreated += 1 if nbObjectTreated % onePercentNbObject == 0: step += 1 dialog.update(step) intervals = Interval.fetchObjects({}) for interval in intervals: interval_o = IntervalController(interval) interval_vw = IntervalView(self, self.appli.viewframe, self.appli, interval_o) interval_vw.addInTreeview(None, False) nbObjectTreated += 1 if nbObjectTreated % onePercentNbObject == 0: step += 1 dialog.update(step) #Adding ip objects self.ips_node = self.insert("", "end", str("ips"), text="IPs", image=IpView.getClassIcon()) ips = Ip.fetchObjects({}) for ip in ips: ip_o = IpController(ip) ip_vw = IpView(self, self.appli.viewframe, self.appli, ip_o) ip_vw.addInTreeview(None, False) self.appli.statusbar.notify(ip_vw.controller.getTags()) nbObjectTreated += 1 if nbObjectTreated % onePercentNbObject == 0: step += 1 dialog.update(step) # Adding port objects ports = Port.fetchObjects({}) for port in ports: port_o = PortController(port) port_vw = PortView(self, self.appli.viewframe, self.appli, port_o) port_vw.addInTreeview(None, False) self.appli.statusbar.notify(port_vw.controller.getTags()) nbObjectTreated += 1 if nbObjectTreated % onePercentNbObject == 0: step += 1 dialog.update(step) # Adding defect objects defects = Defect.fetchObjects({"ip": {"$ne": ""}}) for defect in defects: defect_o = DefectController(defect) defect_vw = DefectView(self, self.appli.viewframe, self.appli, defect_o) defect_vw.addInTreeview(None) nbObjectTreated += 1 if nbObjectTreated % onePercentNbObject == 0: step += 1 dialog.update(step) # Adding tool objects tools = Tool.fetchObjects({}) for tool in tools: tool_o = ToolController(tool) tool_vw = ToolView(self, self.appli.viewframe, self.appli, tool_o) tool_vw.addInTreeview(None, False) self.appli.statusbar.notify(tool_vw.controller.getTags()) nbObjectTreated += 1 if nbObjectTreated % onePercentNbObject == 0: step += 1 dialog.update(step) self.sort(self.ips_node) self.appli.statusbar.update() dialog.destroy()
def notify(self, db, collection, iid, action, _parent): """ Callback for the observer implemented in mongo.py. Each time an object is inserted, updated or deleted the standard way, this function will be called. Args: collection: the collection that has been modified iid: the mongo ObjectId _id that was modified/inserted/deleted action: string "update" or "insert" or "delete". It was the action performed on the iid _parent: Not used. the mongo ObjectId of the parent. Only if action in an insert. Not used anymore """ apiclient = APIClient.getInstance() if not apiclient.getCurrentPentest() != "": return if db == "pollenisator": if collection == "settings": self.configureTags() return if apiclient.getCurrentPentest() != db: return # Delete if action == "delete": if collection == "defects": view = self.getViewFromId(str(iid)) if view is not None: self.appli.statusbar.notify([], view.controller.getTags()) try: self.delete(ObjectId(iid)) except tk.TclError: pass # item was not inserted in the treeview # Insert if action == "insert": view = None res = apiclient.find(collection, {"_id": ObjectId(iid)}, False) if collection == "tools": view = ToolView(self, self.appli.viewframe, self.appli, ToolController(Tool(res))) elif collection == "waves": view = WaveView(self, self.appli.viewframe, self.appli, WaveController(Wave(res))) elif collection == "scopes": view = ScopeView(self, self.appli.viewframe, self.appli, ScopeController(Scope(res))) elif collection == "ports": view = PortView(self, self.appli.viewframe, self.appli, PortController(Port(res))) elif collection == "ips": view = IpView(self, self.appli.viewframe, self.appli, IpController(Ip(res))) elif collection == "intervals": view = IntervalView(self, self.appli.viewframe, self.appli, IntervalController(Interval(res))) elif collection == "defects": view = DefectView(self, self.appli.viewframe, self.appli, DefectController(Defect(res))) elif collection == "commands": view = CommandView(self, self.appli.viewframe, self.appli, CommandController(Command(res))) elif collection == "group_commands": view = CommandGroupView( self, self.appli.viewframe, self.appli, CommandGroupController(CommandGroup(res))) try: if view is not None: view.addInTreeview() view.insertReceived() self.appli.statusbar.notify(view.controller.getTags()) except tk.TclError: pass if action == "update": try: view = self.getViewFromId(str(iid)) if view is not None: item = self.item(str(iid)) oldTags = item["tags"] view.controller.actualize() self.appli.statusbar.notify(view.controller.getTags(), oldTags) self.item(str(iid), text=str(view.controller.getModelRepr()), image=view.getIcon()) except tk.TclError: if view is not None: view.addInTreeview() if str(self.appli.openedViewFrameId) == str(iid): for widget in self.appli.viewframe.winfo_children(): widget.destroy() view.openModifyWindow() if view is not None: view.updateReceived() self.appli.statusbar.update()
def addComputerinDb(self, port_o): apiclient = APIClient.getInstance() existing = apiclient.findInDb(apiclient.getCurrentPentest(), ActiveDirectory.collName, { "type": "computer", "ip": port_o.ip }, False) existingUsers = [] newUsers = [] existingAdmins = [] newAdmins = [] isDC = False if existing is None: newUsers = ActiveDirectory.normalize_users( port_o.infos.get("users", [])) newAdmins = ActiveDirectory.normalize_users( port_o.infos.get("admins", [])) apiclient.insertInDb( apiclient.getCurrentPentest(), ActiveDirectory.collName, { "type": "computer", "domain": port_o.infos.get("domain", ""), "isDC": isDC, "name": port_o.infos.get("machine_name", ""), "ip": port_o.ip, "OS": port_o.infos.get("OS", ""), "signing": port_o.infos.get("signing", ""), "secrets": port_o.infos.get("secrets", ""), "ntds": port_o.infos.get("ntds", ""), "SMBv1": port_o.infos.get("SMBv1", ""), "users": newUsers, "admins": newAdmins }, notify=True) else: isDC = existing.get("isDC", False) existingUsers = set( map(tuple, ActiveDirectory.normalize_users(existing.get("users", [])))) newUsers = list( existingUsers.union( map( tuple, ActiveDirectory.normalize_users( port_o.infos.get("users", []))))) existingAdmins = set( map( tuple, ActiveDirectory.normalize_users(existing.get("admins", [])))) newAdmins = list( existingAdmins.union( map( tuple, ActiveDirectory.normalize_users( port_o.infos.get("admins", []))))) apiclient.updateInDb( apiclient.getCurrentPentest(), ActiveDirectory.collName, {"_id": ObjectId(existing["_id"])}, { "$set": { "name": port_o.infos.get("machine_name", ""), "domain": port_o.infos.get("domain", ""), "isDC": isDC, "OS": port_o.infos.get("OS", ""), "signing": port_o.infos.get("signing", ""), "secrets": port_o.infos.get("secrets", ""), "ntds": port_o.infos.get("ntds", ""), "SMBv1": port_o.infos.get("SMBv1", ""), "users": newUsers, "admins": newAdmins } }) self.checkEvents(port_o, existingUsers, newUsers, existingAdmins, newAdmins, isDC)
def addSelectedToMyCommands(self, event=None): apiclient = APIClient.getInstance() for selected in self.appliTw.selection(): apiclient.addCommandToMyCommands(selected)
def openModifyWindow(self): """ Creates a tkinter form using Forms classes. This form aims to update or delete an existing Tool """ modelData = self.controller.getData() top_panel = self.form.addFormPanel(grid=True) top_panel.addFormLabel("Name", modelData["name"]) dates_panel = self.form.addFormPanel(grid=True) dates_panel.addFormLabel("Start date") dates_panel.addFormDate("Start date", self.mainApp, modelData["dated"], column=1) dates_panel.addFormLabel("End date", row=1) dates_panel.addFormDate("End date", self.mainApp, modelData["datef"], row=1, column=1) dates_panel.addFormLabel("Scanner", row=2) dates_panel.addFormStr("Scanner", r"", modelData["scanner_ip"], row=2, column=1) dates_panel.addFormLabel("Command executed", row=3) dates_panel.addFormStr("Command executed", "", modelData.get("infos", {}).get("cmdline", ""), row=3, column=1, state="disabled") notes = modelData.get("notes", "") top_panel = self.form.addFormPanel() top_panel.addFormLabel("Notes", side="top") top_panel.addFormText("Notes", r"", notes, None, side="top", height=15) actions_panel = self.form.addFormPanel() apiclient = APIClient.getInstance() hasWorkers = len( apiclient.getWorkers({"pentest": apiclient.getCurrentPentest()})) #Ready is legacy, OOS and/or OOT should be used if ("ready" in self.controller.getStatus() or "error" in self.controller.getStatus() or "timedout" in self.controller.getStatus()) or len( self.controller.getStatus()) == 0: if apiclient.getUser() in modelData["name"]: actions_panel.addFormButton("Local launch", self.localLaunchCallback, side="right") elif hasWorkers and "Worker" in modelData["name"]: actions_panel.addFormButton("Run on worker", self.launchCallback, side="right") else: actions_panel.addFormLabel("Info", "Tool is ready", side="right") elif "OOS" in self.controller.getStatus( ) or "OOT" in self.controller.getStatus(): actions_panel.addFormButton("Local launch", self.localLaunchCallback, side="right") if hasWorkers: actions_panel.addFormButton("Run on worker", self.launchCallback, side="right") else: actions_panel.addFormLabel("Info", "Tool is ready but no worker found", side="right") elif "running" in self.controller.getStatus(): actions_panel.addFormButton("Stop", self.stopCallback, side="right") elif "done" in self.controller.getStatus(): actions_panel.addFormButton("Download result file", self.downloadResultFile, side="right") try: mod = Utils.loadPlugin( self.controller.model.getCommand()["plugin"]) pluginActions = mod.getActions(self.controller.model) except KeyError: # Happens when parsed an existing file.: pluginActions = None except Exception: pluginActions = None if pluginActions is not None: for pluginAction in pluginActions: actions_panel.addFormButton(pluginAction, pluginActions[pluginAction], side="right") actions_panel.addFormButton("Reset", self.resetCallback, side="right") defect_panel = self.form.addFormPanel(grid=True) defect_panel.addFormButton("Create defect", self.createDefectCallback) defect_panel.addFormButton("Show associated command", self.showAssociatedCommand, column=1) self.completeModifyWindow()
def executeCommand(apiclient, toolId, local=True, allowAnyCommand=False): """ remote task Execute the tool with the given toolId on the given calendar name. Then execute the plugin corresponding. Any unhandled exception will result in a task-failed event in the class. Args: apiclient: the apiclient instance. toolId: the mongo Object id corresponding to the tool to execute. local: boolean, set the execution in a local context Raises: Terminated: if the task gets terminated OSError: if the output directory cannot be created (not if it already exists) Exception: if an exception unhandled occurs during the bash command execution. Exception: if a plugin considered a failure. """ # Connect to given calendar APIClient.setInstance(apiclient) toolModel = Tool.fetchObject({"_id": ObjectId(toolId)}) command_dict = toolModel.getCommand() if command_dict is None and toolModel.text != "": command_dict = {"plugin": toolModel.plugin_used, "timeout": 0} msg = "" success, comm, fileext = apiclient.getCommandLine(toolId) if not success: print(str(comm)) toolModel.setStatus(["error"]) return False, str(comm) outputRelDir = toolModel.getOutputDir(apiclient.getCurrentPentest()) abs_path = os.path.dirname(os.path.abspath(__file__)) toolFileName = toolModel.name+"_" + \ str(time.time()) # ext already added in command outputDir = os.path.join(abs_path, "./results", outputRelDir) # Create the output directory try: os.makedirs(outputDir) except OSError as exc: if exc.errno == errno.EEXIST and os.path.isdir(outputDir): pass else: print(str(exc)) toolModel.setStatus(["error"]) return False, str(exc) outputDir = os.path.join(outputDir, toolFileName) comm = comm.replace("|outputDir|", outputDir) toolModel.updateInfos({"cmdline": comm}) # Get tool's wave time limit searching the wave intervals if toolModel.wave == "Custom commands" or local: timeLimit = None else: timeLimit = getWaveTimeLimit(toolModel.wave) # adjust timeLimit if the command has a lower timeout if command_dict is not None and timeLimit is not None: timeLimit = min( datetime.now() + timedelta(0, int(command_dict.get("timeout", 0))), timeLimit) ## try: print(('TASK STARTED:' + toolModel.name)) print("Will timeout at " + str(timeLimit)) # Execute the command with a timeout returncode, stdout = Utils.execute(comm, timeLimit, True) if returncode == -1: toolModel.setStatus(["timedout"]) return False, "timedout" except Exception as e: print(str(e)) toolModel.setStatus(["error"]) return False, str(e) # Execute found plugin if there is one outputfile = outputDir + fileext plugin = "auto-detect" if command_dict["plugin"] == "" else command_dict[ "plugin"] msg = apiclient.importToolResult(toolId, plugin, outputfile) if msg != "Success": #toolModel.markAsNotDone() print(str(msg)) toolModel.setStatus(["error"]) return False, str(msg) # Delay if command_dict is not None: if float(command_dict.get("sleep_between", 0)) > 0.0: msg += " (will sleep for " + \ str(float(command_dict.get("sleep_between", 0)))+")" print(msg) time.sleep(float(command_dict.get("sleep_between", 0))) return True, outputfile
def pollex(): """Send a command to execute for pollenisator-gui running instance """ verbose = False if sys.argv[1] == "-v": verbose = True execCmd = shlex.join(sys.argv[2:]) else: execCmd = shlex.join(sys.argv[1:]) bin_name = shlex.split(execCmd)[0] if bin_name in [ "echo", "print", "vim", "vi", "tmux", "nano", "code", "cd", "pwd", "cat" ]: return cmdName = os.path.splitext(os.path.basename(execCmd.split(" ")[0]))[0] apiclient = APIClient.getInstance() apiclient.tryConnection() cmdName += "::" + str(time.time()).replace(" ", "-") commands = Command.fetchObjects({"bin_path": {'$regex': bin_name}}) choices = set() if commands is not None: for command in commands: choices.add(command.plugin) if len(choices) == 0: plugin = "Default" elif len(choices) == 1: plugin = choices.pop() else: choice = -1 while choice == -1: print("Choose plugin:") for i, choice in enumerate(choices): print(f"{i+1}. {choice}") try: choice_str = input() choice = int(choice_str) except ValueError as e: print("You must type a valid number") if choice > len(choices) or choice < 1: choice = -1 print("You must type a number between 1 and " + str(len(choices))) plugin = list(choices)[choice - 1] print("INFO : Executing plugin " + str(plugin)) success, comm, fileext = apiclient.getDesiredOutputForPlugin( execCmd, plugin) if not success: print("ERROR : An error as occured : " + str(comm)) return with tempfile.TemporaryDirectory() as tmpdirname: outputFilePath = os.path.join(tmpdirname, cmdName) comm = comm.replace("|outputDir|", outputFilePath) if (verbose): print("Executing command : " + str(comm)) returncode, stdout = Utils.execute(comm, None, True) #if stdout.strip() != "": # print(stdout.strip()) if not os.path.exists(outputFilePath): if os.path.exists(outputFilePath + fileext): outputFilePath += fileext else: print( f"ERROR : Expected file was not generated {outputFilePath}" ) return print(f"INFO : Uploading results {outputFilePath}") msg = apiclient.importExistingResultFile( outputFilePath, plugin, os.environ.get("POLLENISATOR_DEFAULT_TARGET", ""), comm) print(msg)
def stop(self): """Stop an automatic scan. Will try to stop running tools.""" apiclient = APIClient.getInstance() apiclient.sendStopAutoScan()
def initUI(self, parent): """Create widgets and initialize them Args: parent: the parent tkinter widget container.""" if self.workerTv is not None: self.refreshUI() return apiclient = APIClient.getInstance() self.parent = parent self.parent.configure(onfiledrop=self.dropFile) ### WORKER TREEVIEW : Which worker knows which commands lblworker = ttk.Label(self.parent, text="Workers:") lblworker.pack(side=tk.TOP, padx=10, pady=5, fill=tk.X) self.workerTv = ttk.Treeview(self.parent) self.workerTv['columns'] = ('workers') self.workerTv.heading("#0", text='Workers', anchor=tk.W) self.workerTv.column("#0", anchor=tk.W) self.workerTv.pack(side=tk.TOP, padx=10, pady=10, fill=tk.X) self.workerTv.bind("<Double-Button-1>", self.OnWorkerDoubleClick) self.workerTv.bind("<Delete>", self.OnWorkerDelete) btn_pane = ttk.Frame(self.parent) self.btn_setInclusion = ttk.Button( btn_pane, text="Include/exclude selected worker", command=self.setWorkerInclusion) self.btn_setInclusion.pack(padx=5, side=tk.RIGHT) self.docker_image = tk.PhotoImage(file=Utils.getIcon("baleine.png")) self.docker_download_image = tk.PhotoImage( file=Utils.getIcon("baleine_download.png")) self.btn_ServerWorker = ttk.Button(btn_pane, command=self.runWorkerOnServer, text="Start remote worker") self.btn_ServerWorker.pack(padx=5, side=tk.RIGHT) if git_available: self.btn_docker_worker = ttk.Button( btn_pane, command=self.launchDockerWorker, image=self.docker_image, style="Toolbutton") self.btn_docker_worker.pack(padx=5, side=tk.RIGHT) self.btn_docker_worker = ttk.Button( btn_pane, command=self.installDockerWorker, image=self.docker_download_image, style="Toolbutton") self.btn_docker_worker.pack(padx=5, side=tk.RIGHT) self.btn_ServerWorker = ttk.Button(btn_pane, command=self.registerAsWorker, text="Register as worker") self.btn_ServerWorker.pack(padx=5, side=tk.RIGHT) btn_pane.pack(side=tk.TOP, padx=10, pady=5) workers = apiclient.getWorkers() total_registered_commands = 0 registeredCommands = set() for worker in workers: workername = worker["name"] try: if apiclient.getCurrentPentest() == worker.get("pentest", ""): worker_node = self.workerTv.insert('', 'end', workername, text=workername, image=self.ok_icon) else: worker_node = self.workerTv.insert('', 'end', workername, text=workername, image=self.nok_icon) except tk.TclError: pass #### TREEVIEW SCANS : overview of ongoing auto scan#### lblscan = ttk.Label(self.parent, text="Scan overview:") lblscan.pack(side=tk.TOP, padx=10, pady=5, fill=tk.X) self.scanTv = ttk.Treeview(self.parent) self.scanTv['columns'] = ('Started at') self.scanTv.heading("#0", text='Scans', anchor=tk.W) self.scanTv.column("#0", anchor=tk.W) self.scanTv.pack(side=tk.TOP, padx=10, pady=10, fill=tk.X) self.scanTv.bind("<Double-Button-1>", self.OnDoubleClick) running_scans = Tool.fetchObjects({"status": "running"}) for running_scan in running_scans: self.scanTv.insert('', 'end', running_scan.getId(), text=running_scan.name, values=(running_scan.dated), image=self.running_icon) #### BUTTONS FOR AUTO SCANNING #### if apiclient.getAutoScanStatus(): self.btn_autoscan = ttk.Button(self.parent, text="Stop Scanning", command=self.stopAutoscan) self.btn_autoscan.pack() else: self.btn_autoscan = ttk.Button(self.parent, text="Start Scanning", command=self.startAutoscan) self.btn_autoscan.pack() btn_parse_scans = ttk.Button(self.parent, text="Parse existing files", command=self.parseFiles) btn_parse_scans.pack(side="top", pady=10) info = ttk.Label(self.parent, text="You can also drop your files / folder here") info.pack()
def OnUserDelete(self, event): apiclient = APIClient.getInstance() username = self.userTv.selection()[0] apiclient.deleteUser(username) self.userTv.delete(username)
def onTreeviewSelect(self, event=None): """Called when a line is selected on the treeview Open the selected object view on the view frame. Args: _event: not used but mandatory """ selection = self.selection() if len(selection) == 1: item = super().onTreeviewSelect(event) if isinstance(item, str): apiclient = APIClient.getInstance() self.saveState(apiclient.getCurrentPentest()) if str(item) == "waves": objView = WaveView(self, self.appli.viewframe, self.appli, WaveController(Wave())) objView.openInsertWindow() elif str(item) == "mycommands": user = apiclient.getUser() objView = CommandView( self, self.appli.viewframe, self.appli, CommandController( Command({ "indb": apiclient.getCurrentPentest(), "owner": user }))) objView.openInsertWindow() elif str(item) == "workercommands": user = "******" objView = CommandView( self, self.appli.viewframe, self.appli, CommandController( Command({ "indb": apiclient.getCurrentPentest(), "owner": user }))) objView.openInsertWindow() elif str(item) == "mygroupcommands": objView = CommandGroupView( self, self.appli.viewframe, self.appli, CommandGroupController( CommandGroup({ "indb": apiclient.getCurrentPentest(), "owner": apiclient.getUser() }))) objView.openInsertWindow() elif str(item) == "workergroupcommands": objView = CommandGroupView( self, self.appli.viewframe, self.appli, CommandGroupController( CommandGroup({ "indb": apiclient.getCurrentPentest(), "owner": "Worker" }))) objView.openInsertWindow() elif str(item) == "ips": objView = MultipleIpView(self, self.appli.viewframe, self.appli, IpController(Ip())) objView.openInsertWindow() elif "intervals" in str(item): wave = Wave.fetchObject({ "_id": ObjectId(IntervalView.treeviewListIdToDb(item)) }) objView = IntervalView( self, self.appli.viewframe, self.appli, IntervalController(Interval().initialize(wave.wave))) objView.openInsertWindow() elif "scopes" in str(item): wave = Wave.fetchObject( {"_id": ObjectId(ScopeView.treeviewListIdToDb(item))}) objView = MultipleScopeView( self, self.appli.viewframe, self.appli, ScopeController(Scope().initialize(wave.wave))) objView.openInsertWindow() else: self.openModifyWindowOf(item) elif len(selection) > 1: # Multi select: multiView = MultiSelectionView(self, self.appli.viewframe, self.appli) for widget in self.appli.viewframe.winfo_children(): widget.destroy() multiView.form.clear() multiView.openModifyWindow()
def addWorkerCommandsToWave(self): apiclient = APIClient.getInstance() apiclient.addWorkerCommandsToWave(self.getId())
def getDefectTable(cls): """Return the table of global defects sorted by their index field Returns: A list of Defect """ return APIClient.getInstance().getDefectTable()
def delete(self): """ Delete the tool represented by this model in database. """ apiclient = APIClient.getInstance() apiclient.delete("tools", ObjectId(self._id))
def isMyCommand(self): user = APIClient.getInstance().getUser() return user == self.owner
def removeSelectedFromMyCommands(self, event=None): apiclient = APIClient.getInstance() for selected in self.appliTw.selection(): apiclient.removeCommandFromMyCommands(selected)