def userCommand(self, command_option, user): if user is None: selection_users = self.tvUsers.selection() if len(selection_users) >= 1: item = self.tvUsers.item(selection_users[0]) user = (item["values"][1], item["text"], item["values"][0]) else: user = None searching = [r"ask_text:([^:\|]+)", "computers_as_file"] for keyword in searching: s = re.search(r"\|" + keyword + r"\|", command_option) if s is not None: if keyword == "computers_as_file": filepath = self.exportAllComputersAsFile() command_option = command_option.replace( s.group(0), filepath) elif "|ask_text:" in s.group(0): what = s.group(1) dialog = ChildDialogAskText(self.tkApp, what) self.tkApp.wait_window(dialog.app) fp = tempfile.mkdtemp() filepath = os.path.join(fp, what + ".txt") with open(filepath, "w") as f: f.write(dialog.rvalue) command_option = command_option.replace( s.group(0), filepath) command_option = command_option.replace("|domain|", user[0]) command_option = command_option.replace("|username|", user[1]) command_option = command_option.replace("|password|", user[2]) Utils.executeInExternalTerm(command_option)
def openPathForUser(self): selection = self.treevw.selection() if selection: folder = os.path.join(self.getScriptsDir(), selection[0]) else: folder = self.getScriptsDir() Utils.openPathForUser(folder)
def downloadResultFile(self, _event=None): """Callback for tool click #TODO move to ToolController Download the tool result file and asks the user if he or she wants to open it. If OK, tries to open it Args: _event: not used """ apiclient = APIClient.getInstance() dialog = ChildDialogInfo(self.appliViewFrame, "Download Started", "Downloading...") dialog.show() abs_path = os.path.dirname(os.path.abspath(__file__)) outputDir = os.path.join(abs_path, "../../results") path = self.controller.getOutputDir(apiclient.getCurrentPentest()) path = apiclient.getResult(self.controller.getDbId(), os.path.join(outputDir, path)) dialog.destroy() if path is not None: if os.path.isfile(path): dialog = ChildDialogQuestion( self.appliViewFrame, "Download completed", "The file has been downloaded.\n Would you like to open it?", answers=["Open", "Cancel"]) self.appliViewFrame.wait_window(dialog.app) if dialog.rvalue == "Open": Utils.openPathForUser(path) return else: return path = None if path is None: tkinter.messagebox.showerror( "Download failed", "the file does not exist on sftp server")
def shareCommand(self, command_option): selected = self.tvShares.selection()[0] parent_iid = self.tvShares.parent(selected) if not parent_iid: # file in share return ip = self.tvShares.item(parent_iid)["text"] item_values = self.tvShares.item(selected)["values"] domain = item_values[-2] if item_values[-2] != "" else None user = item_values[-1] share_name = item_values[0] apiclient = APIClient.getInstance() apiclient.getCurrentPentest() user_o = apiclient.findInDb(apiclient.getCurrentPentest(), ActiveDirectory.collName, { "type": "user", "domain": domain, "username": user }, False) if user_o is None: tk.messagebox.showerror( "user not found", "User " + str(domain) + "\\" + str(user) + " was not found") return user = "" if user is None else user domain = "" if domain is None else domain command_option = command_option.replace("|username|", user) command_option = command_option.replace("|domain|", domain) command_option = command_option.replace("|password|", user_o["password"]) command_option = command_option.replace( "|share|", share_name.replace("\\\\", "\\")) command_option = command_option.replace("|ip|", ip) Utils.executeInExternalTerm(command_option)
def openMultiInsertWindow(self, addButtons=True): """ Creates a tkinter form using Forms classes. This form aims to insert many Defects Args: addButtons: boolean value indicating that insertion buttons should be visible. Default to True """ settings = self.mainApp.settings settings.reloadSettings() results, msg = APIClient.searchDefect("") default_values = {} if results is not None: for result in results: if result is not None: default_values[result["title"]] = result["risk"] self.browse_top_treevw = self.form.addFormTreevw( "Defects", ("Title", "Risk"), default_values, side="top", fill="both", width=400, height=8, status="readonly", binds={ "<Double-Button-1>": self.doubleClickDefectView, "<Delete>": self.deleteDefectTemplate }) self.buttonUpImage = ImageTk.PhotoImage( Image.open(Utils.getIconDir() + 'up-arrow.png')) self.buttonDownImage = ImageTk.PhotoImage( Image.open(Utils.getIconDir() + 'down-arrow.png')) # use self.buttonPhoto buttonPan = self.form.addFormPanel(side="top", anchor="center", fill="none") btn_down = buttonPan.addFormButton("V", self.moveDownMultiTreeview, side="left", anchor="center", image=self.buttonDownImage) btn_down = buttonPan.addFormButton("Î", self.moveUpMultiTreeview, side="right", anchor="center", image=self.buttonUpImage) default_values = {} self.browse_down_treevw = self.form.addFormTreevw("Defects", ("Title", "Risk"), default_values, side="bottom", fill="both", width=400, height=8, status="readonly") if addButtons: self.completeInsertWindow() else: self.showForm()
def __init__(self, parent): """ parent: the tkinter parent view to use for this window construction. """ self.parent = parent self.app = tk.Toplevel(parent) self.app.title("Scripts Manager") self.app.resizable(True, True) self.rvalue = None appFrame = ttk.Frame(self.app) #PANED PART self.paned = tk.PanedWindow(appFrame, height=300) #RIGHT PANE : TAble self.viewframe = ttk.Frame(self.paned) self.file_tree = CheckboxTreeview(self.viewframe) self.file_tree['columns'] = ('name', 'category') self.file_tree.heading('#0', text='Name') self.file_tree.column("#0", stretch=tk.YES, minwidth=300, width=300) self.file_tree.heading('#1', text='Category') self.file_tree.column("#1", stretch=tk.YES, minwidth=300, width=300) self.file_tree.pack(fill=tk.BOTH, expand=True) btn_pane = ttk.Frame(self.viewframe) self.execute_icone = tk.PhotoImage(file = Utils.getIcon("execute.png")) btn_execute = ttk.Button(btn_pane, text="Execute", image=self.execute_icone, command=self.executedSelectedScripts, tooltip="Execute all selected scripts", style="Toolbutton") btn_execute.pack(side=tk.RIGHT, padx=3, pady=5) self.open_folder_icone = tk.PhotoImage(file = Utils.getIcon("folder.png")) btn_openPathForUser = ttk.Button(btn_pane, text="Execute", image=self.open_folder_icone, command=self.openPathForUser, tooltip="Open scripts folder", style="Toolbutton") btn_openPathForUser.pack(side=tk.RIGHT, padx=3, pady=5) btn_pane.pack(fill=tk.X, side=tk.BOTTOM, anchor=tk.E) #LEFT PANE : Treeview self.frameTw = ttk.Frame(self.paned) self.treevw = ttk.Treeview(self.frameTw) self.treevw.pack() scbVSel = ttk.Scrollbar(self.frameTw, orient=tk.VERTICAL, command=self.treevw.yview) self.treevw.configure(yscrollcommand=scbVSel.set) self.treevw.grid(row=0, column=0, sticky=tk.NSEW) scbVSel.grid(row=0, column=1, sticky=tk.NS) self.treevw.grid(row=0, column=0, sticky=tk.NSEW) scbVSel.grid(row=0, column=1, sticky=tk.NS) self.paned.add(self.frameTw) self.paned.add(self.viewframe) self.paned.pack(fill=tk.BOTH, expand=1) self.frameTw.rowconfigure(0, weight=1) # Weight 1 sur un layout grid, sans ça le composant ne changera pas de taille en cas de resize self.frameTw.columnconfigure(0, weight=1) # Weight 1 sur un layout grid, sans ça le composant ne changera pas de taille en cas de resize appFrame.pack(fill=tk.BOTH, ipady=10, ipadx=10, expand=True) self.treevw.bind("<<TreeviewSelect>>", self.onTreeviewSelect) try: self.app.wait_visibility() self.app.focus_force() self.app.lift() except tk.TclError: pass self.refreshUI()
def openTerminal(cls, default_target=""): if cls.settings.isTrapCommand(): comm = "bash --rcfile " + os.path.join( Utils.getMainDir(), "setupTerminalForPentest.sh") else: comm = "bash" env = { "POLLENISATOR_DEFAULT_TARGET": default_target, } res = Utils.executeInExternalTerm(comm, with_bash=False, env=env)
def doInsert(self, values): """ Insert the Scope represented by this model in the database with the given values. Args: values: A dictionary crafted by MultipleScopeView or ScopeView containg all form fields values needed. Returns: { '_id': The mongo ObjectId _id of the inserted command document. 'nbErrors': The number of objects that has not been inserted in database due to errors. } """ # Only multi insert exists at the moment for Scope # Get form values wave = values["wave"] ret = [] total = 0 accepted = 0 insert_setting = values["Settings"] split_range_setting = values.get("Split", False) for line in values["Scopes"].split("\n"): if line.strip() != "": # Insert in database scopeToAdd = line.strip() if Utils.isIp(scopeToAdd): scopeToAdd += "/32" if Utils.isNetworkIp(scopeToAdd): if split_range_setting: network_ips = Utils.splitRange(scopeToAdd) if len(network_ips) == 0: model = Scope().initialize(wave, scopeToAdd, "") inserted_res, iid = model.addInDb() else: for network_ip in network_ips: model = Scope().initialize( wave, str(network_ip), "") inserted_res, iid = model.addInDb() if inserted_res: accepted += 1 ret.append(iid) total += 1 else: model = Scope().initialize(wave, scopeToAdd, "") inserted_res, iid = model.addInDb() else: model = Scope().initialize(wave, scopeToAdd, "") inserted_res, iid = model.addDomainInDb(insert_setting) if inserted_res == 1: accepted += 1 ret.append(iid) total += 1 return ret, total - accepted # nb errors = total - accepted
def add_path_listbox(self, event): data = Utils.drop_file_event_parser(event) for d in data: if os.path.isfile(d) and "file" in self.modes: self.listbox.insert("end", d) elif os.path.isdir(d) and "directory" in self.modes: self.listbox.insert("end", d)
def __init__(self, parent, settings): self.proc = None self.s = None self.__class__.settings = settings self.img = ImageTk.PhotoImage(Image.open(Utils.getIcon("help.png"))) manager = Manager() self.exiting = manager.Value('i', 0)
def openModifyWindow(self, addButtons=True): """ Creates a tkinter form using Forms classes. This form aims to update or delete an existing Defect Args: addButtons: boolean value indicating that insertion buttons should be visible. Default to True """ modelData = self.controller.getData() topPanel = self.form.addFormPanel(grid=True) topPanel.addFormSearchBar("Search Remark", APIClient.searchRemark, topPanel, row=0, column=1, autofocus=False) self.imgTypeForm = topPanel.addFormImage( Utils.getIconDir() + RemarkView.getIconName(modelData["type"]), row=1) self.comboTypeForm = topPanel.addFormCombo( "Type", ["Positive", "Neutral", "Negative"], column=1, row=1, default=modelData["type"], binds={"<<ComboboxSelected>>": self.updateImage}) topPanel.addFormStr("Title", r".+", modelData["title"], width=50, row=1, column=2) if addButtons: self.completeModifyWindow() else: self.showForm()
def __init__(self, parent, settings): """ Constructor """ self.dashboardFrame = None self.parent = None self.treevw = None self.style = None self.ips = None self.ports = None self.tools = None iconPath = Utils.getIconDir() self.icons = {} self.icons["tool"] = ImageTk.PhotoImage( Image.open(iconPath + "tool.png")) self.icons["cross"] = ImageTk.PhotoImage( Image.open(iconPath + "cross.png")) self.icons["running"] = ImageTk.PhotoImage( Image.open(iconPath + "running.png")) self.icons["done"] = ImageTk.PhotoImage( Image.open(iconPath + "done_tool.png")) self.icons["error"] = ImageTk.PhotoImage( Image.open(iconPath + "error_tool.png")) self.icons["ready"] = ImageTk.PhotoImage( Image.open(iconPath + "waiting.png")) self.icons["Not ready"] = ImageTk.PhotoImage( Image.open(iconPath + "cross.png"))
def updateImage(self, _event=None): """Callback when ease or impact is modified. Calculate new resulting risk value Args _event: mandatory but not used """ typeof = self.comboTypeForm.getValue() self.imgTypeForm.setImage(Utils.getIconDir() + RemarkView.getIconName(typeof))
def __init__(self, default_path=""): """ Open a child dialog of a tkinter application to ask details about existing files parsing. Args: default_path: a default path to be added """ self.app = tkinterDnD.Tk() Utils.setStyle(self.app) self.app.title("Upload result file") self.rvalue = None self.default = default_path appFrame = ttk.Frame(self.app) apiclient = APIClient.getInstance() self.form = FormPanel() self.form.addFormLabel("Import one file or choose a directory", "", side=tk.TOP) self.form.addFormFile("File", ".+", self.default, width=50, side=tk.TOP, mode="file|directory") self.form.addFormLabel("Plugins", side=tk.TOP) self.form.addFormCombo("Plugin", ["auto-detect"] + apiclient.getPlugins(), "auto-detect", side=tk.TOP) self.form.addFormButton("Parse", self.onOk, side=tk.RIGHT) self.form.constructView(appFrame) appFrame.pack(ipadx=10, ipady=10) try: self.app.wait_visibility() self.app.focus_force() self.app.grab_set() self.app.lift() except tk.TclError: pass self.app.mainloop() self.app.destroy()
def isLaunchableNow(self): """Returns True if the tool matches criteria to be launched (current time matches one of interval object assigned to this wave) Returns: bool """ intervals = Interval.fetchObjects({"wave": self.wave}) for intervalModel in intervals: if Utils.fitNowTime(intervalModel.dated, intervalModel.datef): return True return False
def checkDomainFit(cls, waveName, domain): """ Check if a found domain belongs to one of the scope of the given wave. Args: waveName: The wave id (name) you want to search for a validating scope domain: The found domain. Returns: boolean """ # Checking settings for domain check. settings = Settings() # get the domain ip so we can search for it in ipv4 range scopes. domainIp = Utils.performLookUp(domain) apiclient = APIClient.getInstance() scopesOfWave = apiclient.find("scopes", {"wave": waveName}) for scopeOfWave in scopesOfWave: scopeIsANetworkIp = Utils.isNetworkIp(scopeOfWave["scope"]) if scopeIsANetworkIp: if settings.db_settings.get("include_domains_with_ip_in_scope", False): if Ip.checkIpScope(scopeOfWave["scope"], domainIp): return True else: # If scope is domain # check if we include subdomains if settings.db_settings.get("include_all_domains", False): return True else: splitted_domain = domain.split(".") # Assuring to check only if there is a domain before the tld (.com, .fr ... ) topDomainExists = len(splitted_domain) > 2 if topDomainExists: if settings.db_settings.get("include_domains_with_topdomain_in_scope", False): if splitted_domain[1:] == scopeOfWave["scope"].split("."): return True if settings.db_settings.get("include_domains_with_ip_in_scope", False): inRangeDomainIp = Utils.performLookUp( scopeOfWave["scope"]) if str(inRangeDomainIp) == str(domainIp): return True return False
def __init__(self, parent, info="Choose a file", default_path=""): """ Open a child dialog of a tkinter application to ask details about existing files parsing. Args: default_path: a default path to be added """ self.app = tkinterDnD.Tk() Utils.setStyle(self.app) self.app.title(info) self.rvalue = None self.default = default_path appFrame = ttk.Frame(self.app) self.form = FormPanel() self.form.addFormLabel("Choose one file", info, side=tk.TOP) self.fileForm = self.form.addFormFile("File", ".+", '', width=50, side=tk.TOP, mode="file") self.button = self.form.addFormButton("Cancel", self.onError, side=tk.RIGHT) self.form.addFormButton("OK", self.onOk, side=tk.RIGHT) self.form.constructView(appFrame) appFrame.pack(ipadx=10, ipady=10) try: self.app.wait_visibility() self.app.focus_force() self.app.grab_set() self.app.lift() except tk.TclError: pass self.app.mainloop() self.app.destroy()
def getIcon(cls, typeOfRemark): """ Load the object icon in cache if it is not yet done, and returns it Return: Returns the icon representing this object. """ cache = cls.cached_icons.get(typeOfRemark, None) if cache is None: from PIL import Image, ImageTk path = Utils.getIconDir() + cls.getIconName(typeOfRemark) cls.cached_icons[typeOfRemark] = ImageTk.PhotoImage( Image.open(path)) return cls.cached_icons[typeOfRemark] return cache
def getWaveTimeLimit(waveName): """ Return the latest time limit in which this tool fits. The tool should timeout after that limit Returns: Return the latest time limit in which this tool fits. """ intervals = Interval.fetchObjects({"wave": waveName}) furthestTimeLimit = datetime.now() for intervalModel in intervals: if Utils.fitNowTime(intervalModel.dated, intervalModel.datef): endingDate = intervalModel.getEndingDate() if endingDate is not None: if endingDate > furthestTimeLimit: furthestTimeLimit = endingDate return furthestTimeLimit
def refreshUI(self): for widget in self.treevw.winfo_children(): widget.destroy() script_dir = self.getScriptsDir() if self.__class__.folder_icon is None: self.__class__.folder_icon = ImageTk.PhotoImage(Image.open(Utils.getIcon("folder.png"))) parent = self.treevw.insert("", "end", " ", text="Scripts", image=self.__class__.folder_icon, open=True) self.treevw.focus(parent) self.treevw.selection_set(parent) for root, subFolders, files in os.walk(script_dir): root_name = root.replace(script_dir, "") for folder in subFolders: if folder.startswith("__") or folder.endswith("__"): continue folder_iid = os.path.join(root_name, folder) parent_node = parent if root_name == "" else root_name self.treevw.insert(parent_node, "end", folder_iid, text=folder, image=self.__class__.folder_icon) self.openScriptFolderView()
def viewProof(self, _event, obj): """Callback when view proof is clicked. Download and display the file Args _event: mandatory but not used obj: the clicked index proof """ proof_local_path = self.controller.getProof(obj) if proof_local_path is not None: if os.path.isfile(proof_local_path): res = Utils.openPathForUser(proof_local_path) if not res: tk.messagebox.showerror("Could not open", "Failed to open this file.") proof_local_path = None return if proof_local_path is None: tk.messagebox.showerror("Download failed", "the file does not exist on sftp server")
def dropFile(self, event): # This function is called, when stuff is dropped into a widget data = Utils.drop_file_event_parser(event) self.parseFiles(data)
def start_docker(dialog, force_reinstall): worker_subdir = os.path.join(Utils.getMainDir(), "PollenisatorWorker") if os.path.isdir(worker_subdir) and force_reinstall: shutil.rmtree(worker_subdir) if not os.path.isdir(worker_subdir): git.Git(Utils.getMainDir()).clone( "https://github.com/fbarre96/PollenisatorWorker.git") shutil.copyfile( os.path.join(Utils.getConfigFolder(), "client.cfg"), os.path.join(Utils.getMainDir(), "PollenisatorWorker/config/client.cfg")) dialog.update( 1, msg= "Building worker docker could take a while (1~10 minutes depending on internet connection speed)..." ) try: client = docker.from_env() clientAPI = docker.APIClient() except Exception as e: dialog.destroy() tk.messagebox.showerror("Unable to launch docker", e) return image = client.images.list("pollenisatorworker") if len(image) > 0 and force_reinstall: force_reinstall = tk.messagebox.askyesno( "Force reinstall", "A pollenisator worker image has been found. Are you sure you want to rebuild it ?" ) if len(image) == 0 or force_reinstall: try: log_generator = clientAPI.build(path=os.path.join( Utils.getMainDir(), "PollenisatorWorker/"), rm=True, tag="pollenisatorworker", nocache=force_reinstall) change_max = None for byte_log in log_generator: updated_dialog = False log_line = byte_log.decode("utf-8").strip() if log_line.startswith("{\"stream\":\""): log_line = log_line[len("{\"stream\":\""):-4] matches = re.search(r"Step (\d+)/(\d+)", log_line) if matches is not None: if change_max is None: change_max = int(matches.group(2)) dialog.progressbar["maximum"] = change_max dialog.update(int(matches.group(1)), log=log_line + "\n") updated_dialog = True except docker.errors.BuildError as e: dialog.destroy() tk.messagebox.showerror("Build docker error", "Building error:\n" + str(e)) return image = client.images.list("pollenisatorworker") if len(image) == 0: tk.messagebox.showerror( "Building docker failed", "The docker build command failed, try to install manually...") return dialog.update(2, msg="Starting worker docker ...") clientCfg = Utils.loadClientConfig() if clientCfg["host"] == "localhost" or clientCfg["host"] == "127.0.0.1": network_mode = "host" else: network_mode = None container = client.containers.run( image=image[0], network_mode=network_mode, volumes={ os.path.join(Utils.getMainDir(), "PollenisatorWorker"): { 'bind': '/home/Pollenisator', 'mode': 'rw' } }, detach=True) dialog.update(3, msg="Checking if worker is running") print(container.id) if container.logs() != b"": print(container.logs()) dialog.destroy()
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 initUI(self, parent): """ Initialize window and widgets. """ if self.parent is not None: # Already initialized self.reset() self.fillWithFixes() return self.parent = parent ###Fixes TABLE ### self.rowHeight = 20 self.style = ttk.Style() self.style.configure('Report.Treeview', rowheight=self.rowHeight) # FIXES TREEVW fixesLabelFrame = ttk.LabelFrame(parent, text="Fixes table") self.paned = tk.PanedWindow(fixesLabelFrame, orient=tk.VERTICAL, height=400) self.frameTw = ttk.Frame(self.paned) self.treevw = ttk.Treeview(self.frameTw, style='Report.Treeview', height=0) self.treevw['columns'] = ('execution', 'gain') self.treevw.heading("#0", text='Title', anchor=tk.W) self.treevw.column("#0", anchor=tk.W, width=150) self.treevw.heading('execution', text='Execution') self.treevw.column('execution', anchor='center', width=40) self.treevw.heading('gain', text='Gain') self.treevw.column('gain', anchor='center', width=40) self.treevw.bind("<Double-Button-1>", self.OnDoubleClick) self.treevw.bind("<Delete>", self.deleteSelectedItem) self.treevw.bind("<Alt-Down>", self.bDown) self.treevw.bind("<Alt-Up>", self.bUp) self.treevw.bind("<ButtonPress-1>", self.dragStart) self.treevw.bind("<ButtonRelease-1>", self.dragRelease, add='+') self.treevw.bind("<B1-Motion>", self.dragMove, add='+') self.treevw.grid(row=0, column=0, sticky=tk.NSEW) scbVSel = ttk.Scrollbar(self.frameTw, orient=tk.VERTICAL, command=self.treevw.yview) self.treevw.configure(yscrollcommand=scbVSel.set) scbVSel.grid(row=0, column=1, sticky=tk.NS) self.frameTw.pack(side=tk.TOP, fill=tk.BOTH, padx=5, pady=10) self.frameTw.columnconfigure(0, weight=1) self.frameTw.rowconfigure(0, weight=1) ### OFFICE EXPORT FRAME ### belowFrame = ttk.Frame(self.paned) frameBtn = ttk.Frame(belowFrame) self.buttonUpImage = ImageTk.PhotoImage( Image.open(Utils.getIconDir() + 'up-arrow.png')) self.buttonDownImage = ImageTk.PhotoImage( Image.open(Utils.getIconDir() + 'down-arrow.png')) # use self.buttonPhoto btn_down = ttk.Button(frameBtn, image=self.buttonDownImage, command=self.bDown) btn_down.pack(side="left", anchor="center") btn_up = ttk.Button(frameBtn, image=self.buttonUpImage, command=self.bUp) btn_up.pack(side="left", anchor="center") btn_delFix = ttk.Button(frameBtn, text="Remove selection", command=self.deleteSelectedItem) btn_delFix.pack(side=tk.RIGHT, padx=5) btn_addFix = ttk.Button(frameBtn, text="Add a fix", command=self.addFixCallback) btn_addFix.pack(side=tk.RIGHT, padx=5) frameBtn.pack(side=tk.TOP, pady=5) belowFrame.pack(side=tk.TOP, fill=tk.BOTH) self.paned.add(self.frameTw) self.paned.add(belowFrame) self.paned.pack(fill=tk.BOTH, expand=1) fixesLabelFrame.pack(side=tk.TOP, fill=tk.BOTH, pady=10) self.fillWithFixes()
def getScriptsDir(self): return os.path.join(Utils.getMainDir(), "scripts/")
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 computerCommand(self, command_option, ips=None, user=None): if ips is None: ips = [] selection = self.tvComputers.selection() for selected in selection: item = self.tvComputers.item(selected) ip = item["text"] ips.append(ip) if user is None: selection_users = self.tvUsers.selection() if len(selection_users) >= 1: item = self.tvUsers.item(selection_users[0]) user = (item["values"][1], item["text"], item["values"][0]) else: user = None for ip in ips: searching = [ "wordlist", r"ask_text:([^:\|]+)", "users_as_file", "ip" ] for keyword in searching: s = re.search(r"\|" + keyword + r"\|", command_option) if s is not None: if keyword == "wordlist": dialog = ChildDialogAskFile(self.tkApp, f"Choose a wordlist file") command_option = command_option.replace( s.group(0), dialog.rvalue) elif keyword == "ip": command_option = command_option.replace(s.group(0), ip) elif keyword == "users_as_file": filepath = self.exportAllUsersAsFile() command_option = command_option.replace( s.group(0), filepath) elif "|ask_text:" in s.group(0): what = s.group(1) dialog = ChildDialogAskText(self.tkApp, what) self.tkApp.wait_window(dialog.app) fp = tempfile.mkdtemp() filepath = os.path.join(fp, what + ".txt") with open(filepath, "w") as f: f.write(dialog.rvalue) command_option = command_option.replace( s.group(0), filepath) user_searching = { "domain": None, "username": None, "password": None } if any( map( lambda user_keyword: f"|{user_keyword}|" in command_option, user_searching)): if user is not None and len(user) == 3: command_option = command_option.replace( "|domain|", user[0]) command_option = command_option.replace( "|username|", user[1]) command_option = command_option.replace( "|password|", user[2]) else: for user_keyword in user_searching: if f"|{user_keyword}|" in command_option: dialog = ChildDialogAskText(self.parent, "Enter " + str(user_keyword), multiline=False) self.parent.wait_window(dialog.app) if dialog.rvalue is None: return command_option = command_option.replace( f"|{user_keyword}|", dialog.rvalue) Utils.executeInExternalTerm(command_option)
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 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()