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() mongoInstance = MongoCalendar.getInstance() existing = mongoInstance.find("scopes", base, False) if existing is not None: return 0, None # 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 parent = self.getParent() res_insert = mongoInstance.insert("scopes", base, parent) ret = res_insert.inserted_id self._id = ret # Adding appropriate tools for this scopes wave = mongoInstance.find("waves", {"wave": self.wave}, False) commands = wave["wave_commands"] for commName in commands: comm = mongoInstance.findInDb("pollenisator", "commands", { "name": commName, "lvl": "network" }, False) if comm is not None: newTool = Tool() newTool.initialize(comm["name"], self.wave, self.scope, "", "", "", "network") newTool.addInDb() else: comm = mongoInstance.findInDb("pollenisator", "commands", { "name": commName, "lvl": "domain" }, False) if comm is not None: newTool = Tool() newTool.initialize(comm["name"], self.wave, self.scope, "", "", "", "domain") newTool.addInDb() # Testing this scope against every ips ips = Ip.fetchObjects({}) for ip in ips: if self._id not in ip.in_scopes: if ip.fitInScope(self.scope): ip.addScopeFitting(self.getId()) ipToInsert = Ip() ipToInsert.initialize(self.scope) ipToInsert.addInDb() return 1, ret
def Parse(self, file_opened, **_kwargs): """ Parse a opened file to extract information Args: file_opened: the open file _kwargs: not used Returns: a tuple with 4 values (All set to None if Parsing wrong file): 0. notes: notes to be inserted in tool giving direct info to pentester 1. tags: a list of tags to be added to tool 2. lvl: the level of the command executed to assign to given targets 3. targets: a list of composed keys allowing retrieve/insert from/into database targerted objects. """ notes = "" tags = [] targets = {} result_socket = file_opened.read() domain, ip = parse_reverse_python(result_socket) if domain is None: return None, None, None, None Ip().initialize(domain).addInDb() ip_m = Ip().initialize(ip) res, iid = ip_m.addInDb() if not res: ip_m = Ip.fetchObject({"_id": iid}) hostnames = list(set(ip_m.infos.get("hostname", []) + [domain])) ip_m.updateInfos({"hostname": hostnames}) targets["ip"] = {"ip": ip} notes += "Domain found :" + domain + "\n" if notes == "": notes = "No domain found\n" return notes, tags, "ip", targets
def doInsert(self, values): """ Insert the Ip represented by this model in the database with the given values. Args: values: A dictionary crafted by MultipleIpView or IpView 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 IP try: multi = True except KeyError: multi = False if multi: # Get form values ret = [] total = 0 accepted = 0 for line in values["IPs"].split("\n"): if line != "": # Insert in database model = Ip().initialize(line) inserted, iid = model.addInDb() if inserted: ret.append(iid) accepted += 1 total += 1 return ret, total - accepted # nb errors = total - accepted
def Parse(self, file_opened, **_kwargs): """ Parse a opened file to extract information foe.test.fr. 801 IN A 18.19.20.21 blog.test.fr. 10800 IN CNAME 22.33.44.55 Args: file_opened: the open file _kwargs: not used Returns: a tuple with 4 values (All set to None if Parsing wrong file): 0. notes: notes to be inserted in tool giving direct info to pentester 1. tags: a list of tags to be added to tool 2. lvl: the level of the command executed to assign to given targets 3. targets: a list of composed keys allowing retrieve/insert from/into database targerted objects. """ notes = "" tags = [] countInserted = 0 for line in file_opened: domain, _record_type, ip = parse_crtsh_line(line) if domain is not None: # a domain has been found infosToAdd = {"hostname": ip} ip_m = Ip().initialize(domain, infos=infosToAdd) res, iid = ip_m.addInDb() # failed, domain is out of scope if not res: notes += domain + " exists but already added.\n" ip_m = Ip.fetchObject({"_id": iid}) infosToAdd = { "hostname": list(set([ip] + ip_m.infos.get("hostname", []))) } ip_m.updateInfos(infosToAdd) else: countInserted += 1 notes += domain + " inserted.\n" if notes.strip() == "": return None, None, None, None elif countInserted != 0: tags.append("todo") return notes, tags, "wave", {"wave": None}
def editScopeIPs(hostsInfos): """ Add all the ips and theirs ports found after parsing the file to the scope object in database. Args: hostsInfos: the dictionnary with ips as keys and a list of dictionnary containing ports informations as value. """ # Check if any ip has been found. if hostsInfos is not None: for infos in hostsInfos: tags = [] if infos.get("powned", False): tags.append("P0wned!") infosToAdd = {} OS = infos.get("OS", "") if OS != "": infosToAdd["OS"] = OS creds = infos.get("creds", "") if creds != "": infosToAdd["creds"] = creds powned = infos.get("powned", False) if powned: infosToAdd["powned"] = "True" ip_m = Ip().initialize(str(infos["ip"])) res, iid = ip_m.addInDb() if not res: ip_m = Ip.fetchObject({"_id": iid}) infosToAdd["hostname"] = list( set(ip_m.infos.get("hostname", []) + [infos["hostname"]])) ip_m.notes = "hostname:" + \ infos["hostname"] + "\n"+infos.get("OS", "") ip_m.tags = tags ip_m.update() port_m = Port().initialize(str(infos["ip"]), str(infos["port"]), "tcp", "netbios-ssn") res, iid = port_m.addInDb() if not res: port_m = Port.fetchObject({"_id": iid}) port_m.updateInfos(infosToAdd) port_m.tags = tags port_m.update()
def getIpPortsNmap(nmapFile): """ Read the given nmap .nmap file results and return a dictionnary with ips and a list of their open ports. Args: nmapFile: the path to the .nmap file generated by an nmap scan Returns: notes about inseted ip and ports """ notes = "" countOpen = 0 all_text = nmapFile.read().strip() lines = all_text.split("\n") if len(lines) <= 3: # print("Not enough lines to be nmap") return None if not lines[0].startswith("# Nmap"): # print("Not starting with # Nmap") return None if "scan initiated" not in lines[0]: # print("Not scan initiated on first line") return None if "# Nmap done at" not in lines[-1]: # print("Not # Nmap done at at the end : "+str(lines[-1])) return None ipCIDR_m = None ipDom_m = None for line in lines: # Search ip in file # match an ip ip = re.search( r"^Nmap scan report for (\S+)(?: \(((?:[0-9]{1,3}\.){3}[0-9]{1,3})\))?$", line) if ip is not None: # regex match lastIp = [ ip.group(1), ip.group(2) if ip.group(2) is not None else "" ] notes_ip = "ip:" + \ str(lastIp[1]) if lastIp[1] != "" and lastIp[1] is not None else "" ipCIDR_m = Ip().initialize(str(lastIp[0]), notes=notes_ip) if lastIp[1].strip() != "" and lastIp[1] is not None: ipDom_m = Ip().initialize(str(lastIp[1]), notes="domain:" + str(lastIp[0])) else: ipDom_m = None if " open " in line: if ipCIDR_m is None: # Probably a gnmap return None notes += line + "\n" # regex to find open ports in gnmap file port_search = re.search( r"^(\d+)\/(\S+)\s+open\s+(\S+)(?: +(.+))?$", line) if port_search is not None: port_number = str(port_search.group(1)) proto = str(port_search.group(2)) service = "unknown" if str( port_search.group(3)) == "" else str(port_search.group(3)) product = str(port_search.group(4)) # a port unique key is its protocole/number. countOpen += 1 validIps = [] if ipCIDR_m is not None: ipCIDR_m.addInDb() validIps.append(ipCIDR_m.ip) if ipDom_m is not None: res, iid = ipDom_m.addInDb() if not res: ipDom_m = Ip.fetchObject({"_id": iid}) ipDom_m.updateInfos({ "hostname": list( set( list(ipDom_m.infos.get("hostname", [])) + [str(ipCIDR_m.ip)])) }) validIps.append(ipDom_m.ip) for ipFound in validIps: if ip == "": continue port_o = Port().initialize(ipFound, port_number, proto, service, product) res_insert, iid = port_o.addInDb() if not res_insert: port_o = Port.fetchObject({"_id": iid}) port_o.service = service port_o.update() notes = str(countOpen) + " open ports found\n" + notes return notes
def smbmap_format(smbmap_output): """Parse raw smbmap file Args: smbmap_output: raw smbmap file content Returns: A tuple with values: 0. a string formated where each line are : fullpath permissions date 1. a list of interesting name file found 2. targets as described in Parse """ targets = {} regex_only_match_serv = re.compile( r"^\[\+\] IP: ([^:\s]+)(?::\d+)?\sName: \S+\s+$") # group 1 = SHARE NAME group 2 = PERMISSIONS regex_only_match_share_header = re.compile(r"^\t(\S+)\s+([A-Z , ]+)$") # group 1 = directory full path regex_only_match_dir = re.compile(r"^\t(\S+)$") # group 1 = d ou -, group 2 = permissions, group 3 = date, group 4 = filename regex_only_match_files = re.compile( r"^\s+([d-])([xrw-]{9})\s+([^\t]+)\t(.+)$") ret = "" interesting_files = {} interesting_name_list = [ "passwd", "password", "pwd", "mot_de_passe", "motdepasse", "auth", "creds", "confidentiel", "confidential", "backup", ".xml", ".conf", ".cfg", "unattended" ] current_serv = "" current_share = "" current_dir = "" ip_states = [] lines = smbmap_output.split("\n") for line in lines: result = regex_only_match_serv.match(line) if result is not None: ip = str(result.group(1)) current_serv = ip if ip not in ip_states: ip_o = Ip().initialize(ip) ip_o.addInDb() Port().initialize(ip, "445", "tcp", "samba").addInDb() targets[str(ip_o.getId())] = { "ip": ip, "port": "445", "proto": "tcp" } ip_states.append(ip) continue result = regex_only_match_share_header.match(line) if result is not None: share_name = str(result.group(1)) permissions = str(result.group(2)) current_share = share_name continue result = regex_only_match_dir.match(line) if result is not None: dir_path = str(result.group(1)) current_dir = dir_path continue result = regex_only_match_files.match(line) if result is not None: # isDirectory = (str(result.group(1)) == "d") permissions = str(result.group(2)) date = str(result.group(3)) file_name = str(result.group(4)) fullpath = "\\\\"+current_serv+"\\" + \ current_share+current_dir[1:]+file_name for interesting_names in interesting_name_list: if interesting_names.lower() in file_name.lower(): interesting_files[ "Shared " + interesting_names] = interesting_files.get( "Shared " + interesting_names, []) interesting_files["Shared " + interesting_names].append(fullpath + "\t" + permissions + "\t" + date) ret += fullpath + "\t" + permissions + "\t" + date + "\n" continue return ret, interesting_files, targets
def Parse(self, file_opened, **_kwargs): """ Parse a opened file to extract information Example: [ { "arguments": "./dnsrecon.py -r 10.0.0.0/24 -j /home/barre/test.json", "date": "2020-01-06 11:43:37.701513", "type": "ScanInfo" }, { "address": "10.0.0.1", "name": "_gateway", "type": "PTR" }, { "address": "10.0.0.77", "name": "barre-ThinkPad-E480", "type": "PTR" }, { "address": "10.0.0.77", "name": "barre-ThinkPad-E480.local", "type": "PTR" } ] Args: file_opened: the open file _kwargs: not used Returns: a tuple with 4 values (All set to None if Parsing wrong file): 0. notes: notes to be inserted in tool giving direct info to pentester 1. tags: a list of tags to be added to tool 2. lvl: the level of the command executed to assign to given targets 3. targets: a list of composed keys allowing retrieve/insert from/into database targerted objects. """ notes = "" tags = [] countInserted = 0 try: dnsrecon_content = json.loads(file_opened.read()) except json.decoder.JSONDecodeError: return None, None, None, None if len(dnsrecon_content) == 0: return None, None, None, None if not isinstance(dnsrecon_content[0], dict): return None, None, None, None if dnsrecon_content[0].get("type", "") != "ScanInfo": return None, None, None, None if dnsrecon_content[0].get("date", "") == "": return None, None, None, None for record in dnsrecon_content[1:]: ip = record["address"] name = record["name"] infosToAdd = {"hostname": name} ip_m = Ip().initialize(ip, infos=infosToAdd) res, iid = ip_m.addInDb() infosToAdd = {"ip": ip} ip_m = Ip().initialize(name, infos=infosToAdd) res, iid = ip_m.addInDb() # failed, domain is out of scope if not res: notes += name + " exists but already added.\n" ip_m = Ip.fetchObject({"_id": iid}) infosToAdd = {"ip": list(set([ip] + ip_m.infos.get("ip", [])))} ip_m.updateInfos(infosToAdd) else: countInserted += 1 notes += name + " inserted.\n" return notes, tags, "wave", {"wave": None}