def addTag(self, newTag, overrideGroupe=True): """Add the given tag to this object. Args: newTag: a new tag as a string to be added to this model tags overrideGroupe: Default to True. If newTag is in a group with a tag already assigned to this object, it will replace this old tag. """ tags = self.getTags() if newTag not in tags: for group in self.getTagsGroups(): if newTag in group: i = 0 len_tags = len(tags) while i < len_tags: if tags[i] in group: if overrideGroupe: tags.remove(tags[i]) i -= 1 else: continue len_tags = len(tags) i += 1 tags.append(newTag) self.tags = tags mongoInstance = MongoCalendar.getInstance() mongoInstance.update(self.__class__.coll_name, {"_id": self.getId()}, {"$set": { "tags": tags }})
def stopTask(pentest, tool_iid, body): mongoInstance = MongoCalendar.getInstance() mongoInstance.connectToDb(pentest) stopableTool = ServerTool.fetchObject(pentest, {"_id": ObjectId(tool_iid)}) print("Trying to stop task " + str(stopableTool)) if stopableTool is None: return "Tool not found", 404 workers = mongoInstance.getWorkers({}) workerNames = [worker["name"] for worker in workers] forceReset = body["forceReset"] saveScannerip = stopableTool.scanner_ip if forceReset: stopableTool.markAsNotDone() update(pentest, tool_iid, ToolController(stopableTool).getData()) if saveScannerip == "": return "Empty worker field", 400 if saveScannerip == "localhost": return "Tools running in localhost cannot be stopped through API", 405 if saveScannerip not in workerNames: return "The worker running this tool is not running anymore", 404 from pollenisator.api import socketio, sockets socketio.emit('stopCommand', { 'pentest': pentest, "tool_iid": str(tool_iid) }, room=sockets[saveScannerip]) if not forceReset: stopableTool.markAsNotDone() update(pentest, tool_iid, ToolController(stopableTool).getData()) return "Success", 200
def delete(pentest, ip_iid): mongoInstance = MongoCalendar.getInstance() mongoInstance.connectToDb(pentest) ip_dic = mongoInstance.find("ips", {"_id": ObjectId(ip_iid)}, False) if ip_dic is None: return 0 tools = mongoInstance.find("tools", {"ip": ip_dic["ip"]}, True) for tool in tools: tool_delete(pentest, tool["_id"]) defects = mongoInstance.find( "defects", { "ip": ip_dic["ip"], "$or": [{ "port": { "$exists": False } }, { "port": None }] }, True) for defect in defects: defect_delete(pentest, defect["_id"]) ports = mongoInstance.find("ports", {"ip": ip_dic["ip"]}, True) for port in ports: port_delete(pentest, port["_id"]) res = mongoInstance.delete("ips", {"_id": ObjectId(ip_iid)}, False) if res is None: return 0 else: return res.deleted_count
def addAllTool(self, command_name): """ Add the appropriate tools (level check and wave's commands check) for this scope. Args: command_name: The command that we want to create all the tools for. """ mongoInstance = MongoCalendar.getInstance() mongoInstance.connectToDb(self.pentest) command = mongoInstance.findInDb(self.pentest, "commands", {"name": command_name}, False) if command["lvl"] == "network": newTool = ServerTool(self.pentest) newTool.initialize(command["name"], self.wave, self.scope, "", "", "", "network") newTool.addInDb() return if command["lvl"] == "domain": if not isNetworkIp(self.scope): newTool = ServerTool(self.pentest) newTool.initialize(command["name"], self.wave, self.scope, "", "", "", "domain") newTool.addInDb() return ips = self.getIpsFitting() for ip in ips: i = ServerIp(self.pentest, ip) i.addAllTool(command_name, self.wave, self.scope)
def autoScan(pentest, endoded_token): """ Search tools to launch within defined conditions and attempts to launch them this worker. Gives a visual feedback on stdout Args: pentest: The database to search tools in """ mongoInstance = MongoCalendar.getInstance() mongoInstance.connectToDb(pentest) check = True try: while check: launchableTools, waiting = findLaunchableTools(pentest) launchableTools.sort( key=lambda tup: (tup["timedout"], int(tup["priority"]))) #TODO CHECK SPACE for launchableTool in launchableTools: check = getAutoScanStatus(pentest) if not check: break res, statuscode = launchTask(pentest, launchableTool["tool"].getId(), { "checks": True, "plugin": "" }, worker_token=endoded_token) check = getAutoScanStatus(pentest) time.sleep(3) except (KeyboardInterrupt, SystemExit): print("stop autoscan : Kill received...") mongoInstance.delete("autoscan", {}, True) except Exception as e: print(str(e))
def addAllTool(self, command_name, wave_name, scope): """ Kind of recursive operation as it will call the same function in its children ports. Add the appropriate tools (level check and wave's commands check) for this ip. Also add for all registered ports the appropriate tools. Args: command_name: The command that we want to create all the tools for. wave_name: the wave name from where we want to load tools scope: a scope object allowing to launch this command. Opt """ # retrieve the command level mongoInstance = MongoCalendar.getInstance() mongoInstance.connectToDb(self.pentest) command = mongoInstance.findInDb(self.pentest, "commands", {"name": command_name}, False) if command["lvl"] == "ip": # finally add tool newTool = ServerTool(self.pentest) newTool.initialize(command_name, wave_name, "", self.ip, "", "", "ip") newTool.addInDb() return # Do the same thing for all children ports. ports = mongoInstance.find("ports", {"ip": self.ip}) for port in ports: p = ServerPort(self.pentest, port) p.addAllTool(command_name, wave_name, scope)
def createUser(body): username = body.get("username", "") name = body.get("name", "") surname = body.get("surname", "") email = body.get("email", "") pwd = body.get("pwd", "") if username == "": return "username is required", 400 elif pwd == "": return "pwd is required", 400 mongoInstance = MongoCalendar.getInstance() user = mongoInstance.findInDb("pollenisator", "users", {"username": username}, False) if user is not None: return "A user with this username already exists", 403 salt = bcrypt.gensalt() mongoInstance.insertInDb( "pollenisator", "users", { "username": username, "hash": bcrypt.hashpw(pwd.encode(), salt), "name": name, "surname": surname, "email": email, "scope": ["user"] }) return "Successully created user"
def delete(pentest, interval_iid): mongoInstance = MongoCalendar.getInstance() mongoInstance.connectToDb(pentest) interval_o = ServerInterval(pentest, mongoInstance.find("intervals", {"_id": ObjectId(interval_iid)}, False)) res = mongoInstance.delete("intervals", {"_id": ObjectId(interval_iid)}, False) parent_wave = mongoInstance.find("waves", {"wave": interval_o.wave}, False) if parent_wave is not None: mongoInstance.notify(pentest, "waves", parent_wave["_id"], "update", "") other_intervals = mongoInstance.find("waves", {"wave": interval_o.wave}) no_interval_in_time = True for other_interval in other_intervals: other_interval = ServerInterval(pentest, other_interval) if fitNowTime(other_interval.dated, other_interval.datef): no_interval_in_time = False break if no_interval_in_time: tools = mongoInstance.find("tools", {"wave": interval_o.wave}) for tool in tools: tool = ServerTool(pentest, tool) tool.setOutOfTime(pentest) if res is None: return 0 else: return res.deleted_count
def searchUsers(searchreq): mongoInstance = MongoCalendar.getInstance() user_records = mongoInstance.findInDb( "pollenisator", "users", {"username": { "$regex": f".*{searchreq}.*" }}) return [user_record["username"] for user_record in user_records]
def markAsRunning(self, workerName): """Set this tool status as running but keeps OOT or OOS. Sets the starting date to current time and ending date to "None" Args: workerName: the worker name that is running this tool """ self.dated = datetime.now().strftime('%d/%m/%Y %H:%M:%S') self.datef = "None" newStatus = ["running"] if "OOS" in self.status: newStatus.append("OOS") if "OOT" in self.status: newStatus.append("OOT") if "timedout" in self.status: newStatus.append("timedout") self.status = newStatus self.scanner_ip = workerName mongoInstance = MongoCalendar.getInstance() mongoInstance.updateInDb("pollenisator", "workers", {"name": workerName}, { "$push": { "running_tools": { "pentest": self.pentest, "iid": self.getId() } } }, notify=True)
def insert(pentest, body): mongoInstance = MongoCalendar.getInstance() mongoInstance.connectToDb(pentest) ip_o = ServerIp(pentest, body) base = ip_o.getDbKey() existing = mongoInstance.find("ips", base, False) if existing is not None: return {"res": False, "iid": existing["_id"]} if "_id" in body: del body["_id"] parent = ip_o.getParentId() ins_result = mongoInstance.insert("ips", body, parent) iid = ins_result.inserted_id if ip_o.in_scopes: waves = mongoInstance.find("waves", {}) for wave in waves: waveName = wave["wave"] commands = wave["wave_commands"] for commName in commands: # 2. finding the command only if lvl is port comm = mongoInstance.findInDb(pentest, "commands", { "name": commName, "lvl": "ip" }, False) if comm is not None: # 3. checking if the added port fit into the command's allowed service # 3.1 first, default the selected port as tcp if no protocole is defined. tool_o = ServerTool(pentest) tool_o.initialize(comm["name"], waveName, "", ip_o.ip, "", "", "ip") tool_o.addInDb() return {"res": True, "iid": iid}
def insert(pentest, body): mongoInstance = MongoCalendar.getInstance() mongoInstance.connectToDb(pentest) scope_o = ServerScope(pentest, body) # Checking unicity base = scope_o.getDbKey() existing = mongoInstance.find("scopes", base, False) if existing is not None: return {"res": False, "iid": existing["_id"]} if "_id" in body: del body["_id"] # Inserting scope parent = scope_o.getParentId() res_insert = mongoInstance.insert("scopes", base, parent) ret = res_insert.inserted_id scope_o._id = ret # adding the appropriate tools for this scope. wave = mongoInstance.find("waves", {"wave": scope_o.wave}, False) commands = wave["wave_commands"] for commName in commands: if commName.strip() != "": scope_o.addAllTool(commName) # Testing this scope against every ips ips = mongoInstance.find("ips", {}) for ip in ips: ip_o = ServerIp(pentest, ip) if scope_o._id not in ip_o.in_scopes: if ip_o.fitInScope(scope_o.scope): ip_o.addScopeFitting(pentest, scope_o.getId()) return {"res": True, "iid": ret}
def getTokenFor(username, pentest="", owner=False): mongoinstance = MongoCalendar.getInstance() user_record = mongoinstance.findInDb("pollenisator", "users", {"username":username}, False) if user_record is None: return "" mod = False try: scopes = set(decode_token(user_record.get("token","")).get("scope", [])) except: scopes = set() scopes = scopes.union(set(user_record.get("scope", []))) if pentest != "" and pentest not in scopes: scopes = set(user_record["scope"]) scopes.add(pentest) if owner: scopes.add("owner") scopes.add("pentester") mod = True if "user" not in scopes: scopes.add("user") mod = True if verifyToken(user_record.get("token", "")) and not mod: token = user_record.get("token", "") else: token = generateNewToken(user_record, list(scopes)) return token
def getIpsFitting(self): """Returns a list of ip mongo dict fitting this scope Returns: A list ip IP dictionnary from mongo db """ mongoInstance = MongoCalendar.getInstance() mongoInstance.connectToDb(self.pentest) ips = mongoInstance.find("ips", ) ips_fitting = [] isdomain = self.isDomain() for ip in ips: if isdomain: my_ip = performLookUp(self.scope) my_domain = self.scope ip_isdomain = not isIp(ip["ip"]) if ip_isdomain: if my_domain == ip["ip"]: ips_fitting.append(ip) if ServerScope.isSubDomain(my_domain, ip["ip"]): ips_fitting.append(ip) else: if my_ip == ip["ip"]: ips_fitting.append(ip) else: if ServerIp.checkIpScope(self.scope, ip["ip"]): ips_fitting.append(ip) return ips_fitting
def delete(pentest, port_iid): mongoInstance = MongoCalendar.getInstance() mongoInstance.connectToDb(pentest) port_o = ServerPort( pentest, mongoInstance.find("ports", {"_id": ObjectId(port_iid)}, False)) tools = mongoInstance.find("tools", { "port": port_o.port, "proto": port_o.proto, "ip": port_o.ip }, True) for tool in tools: tool_delete(pentest, tool["_id"]) defects = mongoInstance.find("defects", { "port": port_o.port, "proto": port_o.proto, "ip": port_o.ip }, True) for defect in defects: defect_delete(pentest, defect["_id"]) res = mongoInstance.delete("ports", {"_id": ObjectId(port_iid)}, False) if res is None: return 0 else: return res.deleted_count
def delete(pentest, scope_iid): mongoInstance = MongoCalendar.getInstance() mongoInstance.connectToDb(pentest) # deleting tool with scope lvl scope_o = ServerScope( pentest, mongoInstance.find("scopes", {"_id": ObjectId(scope_iid)}, False)) tools = mongoInstance.find( "tools", { "scope": scope_o.scope, "wave": scope_o.wave, "$or": [{ "lvl": "network" }, { "lvl": "domain" }] }) for tool in tools: tool_delete(pentest, tool["_id"]) # Deleting this scope against every ips ips = ServerIp.getIpsInScope(pentest, scope_iid) for ip in ips: ip.removeScopeFitting(pentest, scope_iid) res = mongoInstance.delete("scopes", {"_id": ObjectId(scope_iid)}, False) parent_wave = mongoInstance.find("waves", {"wave": scope_o.wave}, False) if parent_wave is None: return mongoInstance.notify(pentest, "waves", parent_wave["_id"], "update", "") # Finally delete the selected element if res is None: return 0 else: return res.deleted_count
def registerCommands(data): mongoInstance = MongoCalendar.getInstance() workerName = data.get("workerName") tools = data.get("tools") global sockets sockets[workerName] = request.sid command_names = tools mongoInstance.registerCommands(workerName, command_names)
def addAllTool(self, command_name, wave_name, scope, check=True): """ Add the appropriate tools (level check and wave's commands check) for this port. Args: command_name: The command that we want to create all the tools for. wave_name: name of the was to fetch allowed commands from scope: a scope matching this tool (should only be used by network level tools) check: A boolean to bypass checks. Force adding this command tool to this port if False. Default is True """ mongoInstance = MongoCalendar.getInstance() mongoInstance.connectToDb(self.pentest) if not check: newTool = ServerTool(self.pentest) newTool.initialize(command_name, wave_name, scope, self.ip, self.port, self.proto, "port") newTool.addInDb() return # retrieve wave's command wave = mongoInstance.find("waves", {"wave": wave_name}, False) commands = wave["wave_commands"] try: index = commands.index(command_name) # retrieve the command level command = mongoInstance.findInDb(self.pentest, "commands", {"name": commands[index]}, False) if command["lvl"] == "port": # 3. checking if the added port fit into the command's allowed service # 3.1 first, default the selected port as tcp if no protocole is defined. allowed_ports_services = command["ports"].split(",") for i, elem in enumerate(allowed_ports_services): if not (elem.strip().startswith("tcp/") or elem.strip().startswith("udp/")): allowed_ports_services[i] = "tcp/" + str(elem.strip()) for allowed in allowed_ports_services: protoRange = "udp" if allowed.startswith("udp/") else "tcp" maybeRange = str(allowed)[4:].split("-") startAllowedRange = -1 endAllowedRange = -1 if len(maybeRange) == 2: try: startAllowedRange = int(maybeRange[0]) endAllowedRange = int(maybeRange[1]) except ValueError: pass if (self.proto+"/"+self.port == allowed) or \ (self.proto+"/"+self.service == allowed) or \ (self.proto == protoRange and int(self.port) >= int(startAllowedRange) and int(self.port) <= int(endAllowedRange)): # finally add tool newTool = ServerTool(self.pentest) newTool.initialize(command_name, wave_name, scope, self.ip, self.port, self.proto, "port") newTool.addInDb() except ValueError: pass
def listUsers(): mongoInstance = MongoCalendar.getInstance() user_records = mongoInstance.aggregateFromDb("pollenisator", "users", [{ "$project": { "hash": 0, "token": 0 } }]) return [user_record for user_record in user_records]
def delete(pentest, command_group_iid): mongoInstance = MongoCalendar.getInstance() res = mongoInstance.deleteFromDb("pollenisator", "group_commands", {"_id": ObjectId(command_group_iid)}, False, True) if res is None: return 0 else: return res.deleted_count
def deleteUser(username): mongoInstance = MongoCalendar.getInstance() user = mongoInstance.findInDb("pollenisator", "users", {"username": username}, False) if user is not None: mongoInstance.deleteFromDb("pollenisator", "users", {"username": username}, False, False) return "User successfully deleted" else: return "User to delete not found", 404
def getParentId(self): """ Return the mongo ObjectId _id of the first parent of this object. For an interval it is the wave. Returns: Returns the parent wave's ObjectId _id". """ mongoInstance = MongoCalendar.getInstance() mongoInstance.connectToDb(self.pentest) return mongoInstance.find("waves", {"wave": self.wave}, False)["_id"]
def delete(pentest, tool_iid): mongoInstance = MongoCalendar.getInstance() mongoInstance.connectToDb(pentest) if not mongoInstance.isUserConnected(): return "Not connected", 503 res = mongoInstance.delete("tools", {"_id": ObjectId(tool_iid)}, False) if res is None: return 0 else: return res.deleted_count
def __init__(self, pentest="", *args, **kwargs): mongoInstance = MongoCalendar.getInstance() super().__init__(*args, **kwargs) if pentest != "": self.pentest = pentest elif mongoInstance.calendarName != "": self.pentest = mongoInstance.calendarName else: raise ValueError("An empty pentest name was given and the database is not set in mongo instance.") mongoInstance.connectToDb(self.pentest)
def checkTokenValidity(jwt_decoded): mongoInstance = MongoCalendar.getInstance() access_token = encode_token(jwt_decoded) user = mongoInstance.findInDb("pollenisator", "users", {"token":access_token}, False) if user is not None: exp_timestamp = jwt_decoded.get("exp", datetime.datetime.now().timestamp()) if datetime.datetime.now().timestamp() > exp_timestamp: return False return True return False
def insert(pentest, body): mongoInstance = MongoCalendar.getInstance() mongoInstance.connectToDb(pentest) if "_id" in body: del body["_id"] interval_o = ServerInterval(pentest, body) parent = interval_o.getParentId() ins_result = mongoInstance.insert("intervals", body, parent) interval_o.setToolsInTime() iid = ins_result.inserted_id return {"res":True, "iid":iid}
def getCommand(self): """ Get the tool associated command. Return: Returns the Mongo dict command fetched instance associated with this tool's name. """ mongoInstance = MongoCalendar.getInstance() commandTemplate = mongoInstance.findInDb(self.pentest, "commands", {"name": self.name}, False) return commandTemplate
def getCommandToExecute(self, command_o): """ Get the tool bash command to execute. Replace the command's text's variables with tool's informations. Return: Returns the bash command of this tool instance, a marker |outputDir| is still to be replaced. """ mongoInstance = MongoCalendar.getInstance() toolHasCommand = self.text if isinstance(command_o, str): command = command_o self.text = command lvl = self.lvl else: if toolHasCommand is not None and toolHasCommand.strip() != "": command = self.text lvl = self.lvl else: command = command_o.text lvl = command_o.lvl command = command.replace("|wave|", self.wave) if lvl == "network" or lvl == "domain": command = command.replace("|scope|", self.scope) if isNetworkIp(self.scope) == False: depths = self.scope.split(".") if len(depths) > 2: topdomain = ".".join(depths[1:]) else: topdomain = ".".join(depths) command = command.replace("|parent_domain|", topdomain) if lvl == "ip": command = command.replace("|ip|", self.ip) ip_db = mongoInstance.find("ips", {"ip": self.ip}, False) ip_infos = ip_db.get("infos", {}) for info in ip_infos: command = command.replace("|ip.infos." + str(info) + "|", command) if lvl == "port": command = command.replace("|ip|", self.ip) command = command.replace("|port|", self.port) command = command.replace("|port.proto|", self.proto) port_db = mongoInstance.find("ports", { "port": self.port, "proto": self.proto, "ip": self.ip }, False) command = command.replace("|port.service|", port_db["service"]) command = command.replace("|port.product|", port_db["product"]) port_infos = port_db.get("infos", {}) for info in port_infos: # print("replacing "+"|port.infos."+str(info)+"|"+ "by "+str(info)) command = command.replace("|port.infos." + str(info) + "|", str(port_infos[info])) return command
def insert(pentest, body): mongoInstance = MongoCalendar.getInstance() mongoInstance.connectToDb(pentest) port_o = ServerPort(pentest, body) base = port_o.getDbKey() existing = mongoInstance.find("ports", base, False) if existing is not None: return {"res": False, "iid": existing["_id"]} if "_id" in body: del body["_id"] parent = port_o.getParentId() ins_result = mongoInstance.insert("ports", body, parent) iid = ins_result.inserted_id # adding the appropriate tools for this port. # 1. fetching the wave's commands waves = mongoInstance.find("waves", {}) for wave in waves: waveName = wave["wave"] commands = wave["wave_commands"] for commName in commands: # 2. finding the command only if lvl is port comm = mongoInstance.findInDb(pentest, "commands", { "name": commName, "lvl": "port" }, False) if comm is not None: # 3. checking if the added port fit into the command's allowed service # 3.1 first, default the selected port as tcp if no protocole is defined. allowed_ports_services = comm["ports"].split(",") for i, elem in enumerate(allowed_ports_services): if not (elem.strip().startswith("tcp/") or elem.strip().startswith("udp/")): allowed_ports_services[i] = "tcp/" + str(elem.strip()) for allowed in allowed_ports_services: protoRange = "udp" if allowed.startswith("udp/") else "tcp" maybeRange = str(allowed)[4:].split("-") startAllowedRange = -1 endAllowedRange = -1 if len(maybeRange) == 2: try: startAllowedRange = int(maybeRange[0]) endAllowedRange = int(maybeRange[1]) except ValueError: pass if (port_o.proto+"/"+port_o.port == allowed) or \ (port_o.proto+"/"+port_o.service == allowed) or \ (port_o.proto == protoRange and int(port_o.port) >= int(startAllowedRange) and int(port_o.port) <= int(endAllowedRange)): # finally add tool newTool = ServerTool(pentest) newTool.initialize(comm["name"], waveName, "", port_o.ip, port_o.port, port_o.proto, "port") newTool.addInDb() return {"res": True, "iid": iid}
def insert(pentest, body): mongoInstance = MongoCalendar.getInstance() existing = mongoInstance.findInDb(body["indb"], "commands", {"name": body["name"]}, False) if existing is not None: return {"res": False, "iid": existing["_id"]} if "_id" in body: del body["_id"] ins_result = mongoInstance.insertInDb(body["indb"], "commands", body, '', True) iid = ins_result.inserted_id return {"res": True, "iid": iid}