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()
     command = mongoInstance.findInDb("pollenisator", "commands",
                                      {"name": command_name}, False)
     if command["lvl"] == "network":
         newTool = Tool()
         newTool.initialize(command["name"], self.wave, self.scope, "", "",
                            "", "network")
         newTool.addInDb()
         return
     if command["lvl"] == "domain":
         if not Utils.isNetworkIp(self.scope):
             newTool = Tool()
             newTool.initialize(command["name"], self.wave, self.scope, "",
                                "", "", "domain")
             newTool.addInDb()
         return
     ips = self.getIpsFitting()
     for ip in ips:
         i = Ip(ip)
         i.addAllTool(command_name, self.wave, self.scope)
Exemple #2
0
 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 = {}
     ip, domain = parse_reverse_dig(file_opened.read())
     if ip is None:
         return None, None, None, None
     if domain is not None:
         # Add a domain as a scope in db
         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(list(ip_m.infos.get("hostname", [])) + [domain]))
         ip_m.updateInfos({"hostname": hostnames})
         ip_m.notes = "reversed dig give this domain : "+domain+"\n"+ip_m.notes
         notes += "Domain found :"+domain+"\n"
         targets["ip"] = {"ip": ip}
         ip_m.update()
     if notes == "":
         notes = "No domain found\n"
     return notes, tags, "ip", targets
Exemple #3
0
    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
Exemple #4
0
    def Parse(self, file_opened, **kwargs):
        """
        Parse a opened file to extract information
        Example file:
        10.0.0.1 - UNKNOWN - no connection - timeout
        10.0.0.2 - VULNERABLE - ?? - ????

        Args:
            file_opened: the open file
            kwargs: port("") and proto("") are valid
        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.
        """
        # 5. Parse the file has you want.
        # Here add a note to the tool's notes of each warnings issued by this testssl run.
        notes = ""
        tags = ["Neutral"]
        targets = {}
        for line in file_opened:
            # Auto Detect
            infos = line.split(" - ")
            if len(infos) < 3:
                return None, None, None, None
            if not Ip.isIp(infos[0]):
                return None, None, None, None
            if infos[1] not in ["UNKNOWN", "SAFE", "VULNERABLE"]:
                return None, None, None, None
            # Parse
            ip = line.split(" ")[0].strip()
            Ip().initialize(ip).addInDb()
            p_o = Port.fetchObject({"ip": ip, "port": kwargs.get(
                "port", None), "proto": kwargs.get("proto", None)})
            if p_o is not None:
                targets[str(p_o.getId())] = {"ip": ip, "port": kwargs.get(
                    "port", None), "proto": kwargs.get("proto", None)}
            if "VULNERABLE" in line:
                Defect().initialize(ip, kwargs.get("port", None), kwargs.get("proto", None), "Serveur vulnérable à BlueKeep",
                                    "Difficile", "Critique", "Critique", "N/A", ["Socle"], notes=notes, proofs=[]).addInDb()
                tags=["P0wned!"]
                if p_o is not None:
                    p_o.addTag("P0wned!")
                ip_o = Ip.fetchObject({"ip": ip})
                if ip_o is not None:
                    ip_o.addTag("P0wned!")
            elif "UNKNOWN" in line:
                tags = ["todo"]
            notes += line
        return notes, tags, "port", targets
Exemple #5
0
 def getNotDoneTools(cls, waveName):
     """Returns a set of tool mongo ID that are not done yet.
     """
     notDoneTools = set()
     mongoInstance = MongoCalendar.getInstance()
     tools = mongoInstance.find(
         "tools", {
             "wave": waveName,
             "ip": "",
             "scanner_ip": "None",
             "dated": "None",
             "datef": "None"
         })
     for tool in tools:
         notDoneTools.add(tool["_id"])
     scopes = Scope.fetchObjects({"wave": waveName})
     for scope in scopes:
         scopeId = scope.getId()
         ips = Ip.getIpsInScope(scopeId)
         for ip in ips:
             tools = mongoInstance.find(
                 "tools", {
                     "wave": waveName,
                     "ip": ip.ip,
                     "scanner_ip": "None",
                     "dated": "None",
                     "datef": "None"
                 })
             for tool in tools:
                 notDoneTools.add(tool["_id"])
     return notDoneTools
    def addInDb(self):
        """
        Add this scope in database.

        Returns: a tuple with :
                * bool for success
                * mongo ObjectId : already existing object if duplicate, create object id otherwise 
        """
        base = self.getDbKey()
        # Checking unicity
        mongoInstance = MongoCalendar.getInstance()
        existing = mongoInstance.find("scopes", base, False)
        if existing is not None:
            return False, existing["_id"]
        # Inserting scope
        parent = self.getParent()
        res_insert = mongoInstance.insert("scopes", base, parent)
        ret = res_insert.inserted_id
        self._id = ret
        # adding the appropriate tools for this scope.
        wave = mongoInstance.find("waves", {"wave": self.wave}, False)
        commands = wave["wave_commands"]
        for commName in commands:
            if commName.strip() != "":
                self.addAllTool(commName)
        # 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())
        return True, ret
 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()
     ips = mongoInstance.find("ips", )
     ips_fitting = []
     isdomain = self.isDomain()
     for ip in ips:
         if isdomain:
             my_ip = Utils.performLookUp(self.scope)
             my_domain = self.scope
             ip_isdomain = not Utils.isIp(ip["ip"])
             if ip_isdomain:
                 if my_domain == ip["ip"]:
                     ips_fitting.append(ip)
                 if Scope.isSubDomain(my_domain, ip["ip"]):
                     ips_fitting.append(ip)
             else:
                 if my_ip == ip["ip"]:
                     ips_fitting.append(ip)
         else:
             if Ip.checkIpScope(self.scope, ip["ip"]):
                 ips_fitting.append(ip)
     return ips_fitting
 def delete(self):
     """
     Delete the Scope represented by this model in database.
     Also delete the tools associated with this scope
     Also remove this scope from ips in_scopes attributes
     """
     # deleting tool with scope lvl
     tools = Tool.fetchObjects({
         "scope":
         self.scope,
         "wave":
         self.wave,
         "$or": [{
             "lvl": "network"
         }, {
             "lvl": "domain"
         }]
     })
     for tool in tools:
         tool.delete()
     # Deleting this scope against every ips
     ips = Ip.getIpsInScope(self._id)
     for ip in ips:
         ip.removeScopeFitting(self._id)
     mongoInstance = MongoCalendar.getInstance()
     mongoInstance.delete("scopes", {"_id": self._id})
     parent_wave = mongoInstance.find("waves", {"wave": self.wave}, False)
     if parent_wave is None:
         return
     mongoInstance.notify(mongoInstance.calendarName, "waves",
                          parent_wave["_id"], "update", "")
 def loadData(self):
     """
     Fetch data from database
     """
     self.ports = Port.fetchObjects({})
     self.ips = Ip.fetchObjects({})
     self.tools = Tool.fetchObjects({})
Exemple #10
0
 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.
     """
     targets = {}
     notes = file_opened.read()
     regex_ip = r"Nmap scan report for (\S+)"
     ip_group = re.search(regex_ip, notes)
     if ip_group is None:
         return None, None, None, None
     # Auto Detect:
     if "smb-vuln-ms17-010:" not in notes:
         return None, None, None, None
     # Parsing
     ip = ip_group.group(1).strip()
     Ip().initialize(ip).addInDb()
     port_re = r"(\d+)\/(\S+)\s+open\s+microsoft-ds"
     res_search = re.search(port_re, notes)
     res_insert = None
     if res_search is None:
         port = None
         proto = None
     else:
         port = res_search.group(1)
         proto = res_search.group(2)
         p_o = Port()
         p_o.initialize(ip, port, proto, "microsoft-ds")
         res_insert = p_o.addInDb()
         targets[str(p_o.getId())] = {
             "ip": ip,
             "port": port,
             "proto": proto
         }
     if "VULNERABLE" in notes:
         d_o = Defect()
         d_o.initialize(ip,
                        port,
                        proto,
                        "Serveur vulnérable à EternalBlue",
                        "Difficile",
                        "Critique",
                        "Critique",
                        "N/A", ["Socle"],
                        notes=notes,
                        proofs=[])
         d_o.addInDb()
         tags = ["P0wned!"]
         if res_insert is not None:
             p_o.addTag("P0wned!")
     return notes, tags, "port", targets
Exemple #11
0
    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
Exemple #12
0
 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 = ["todo"]
     marker = "- scanning for subdomain..."
     markerFound = False
     countFound = 0
     for line in file_opened:
         if marker == line.strip():
             markerFound = True
         if not markerFound:
             continue
         ip, domain, alias = parse_knockpy_line(line)
         if ip is not None and domain is not None:
             # a domain has been found
             res, iid = Ip().initialize(domain).addInDb()
             if res:
                 Ip().initialize(ip).addInDb()
                 notes += line + "\n"
                 countFound += 1
             # failed, domain is out of scope
             else:
                 notes += domain + " exists but already added.\n"
             ip_m = Ip.fetchObject({"_id": iid})
             if alias:
                 ip_m.updateInfos({"alias": ip})
     if notes.strip() == "":
         return None, None, None, None
     return notes, tags, "wave", {"wave": None}
 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):
             mongoInstance = MongoCalendar.getInstance()
             self.saveState(mongoInstance.calendarName)
             if str(item) == "waves":
                 objView = WaveView(self, self.appli.viewframe, self.appli,
                                    WaveController(Wave()))
                 objView.openInsertWindow()
             elif str(item) == "commands":
                 objView = CommandView(
                     self, self.appli.viewframe, self.appli,
                     CommandController(
                         Command({"indb": mongoInstance.calendarName})))
                 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()
Exemple #14
0
    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)
        mongoInstance = MongoCalendar.getInstance()
        scopesOfWave = mongoInstance.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
Exemple #15
0
 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.
     """
     tags = ["todo"]
     data = file_opened.read()
     notes = ""
     if data.strip() == "":
         return None, None, None, None
     else:
         hosts = parse_dirsearch_file(data)
         if not hosts.keys():
             return None, None, None, None
         targets = {}
         for host in hosts:
             Ip().initialize(host).addInDb()
             for port in hosts[host]:
                 port_o = Port()
                 port_o.initialize(host, port, "tcp",
                                   hosts[host][port]["service"])
                 res, iid = port_o.addInDb()
                 if not res:
                     port_o = Port.fetchObject({"_id": iid})
                 targets[str(port_o.getId())] = {
                     "ip": host, "port": port, "proto": "tcp"}
                 hosts[host][port]["paths"].sort(key=lambda x: int(x[0]))
                 results = "\n".join(hosts[host][port]["paths"])
                 notes += results
                 newInfos = {}
                 for statuscode in hosts[host][port]:
                     if isinstance(statuscode, int):
                         if hosts[host][port].get(statuscode, []):
                             newInfos["Dirsearch_"+str(statuscode)
                                      ] = hosts[host][port][statuscode]
                 newInfos["SSL"] = "True" if hosts[host][port]["service"] == "https" else "False"
                 port_o.updateInfos(newInfos)
     return notes, tags, "port", targets
Exemple #16
0
 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 = ["todo"]
     countInserted = 0
     markerSublister = "# Coded By Ahmed Aboul-Ela - @aboul3la"
     markerFound = False
     for line in file_opened:
         if markerSublister in line:
             markerFound = True
         if not markerFound:
             continue
         if line.startswith("\x1b[92m"):
             line = line[len("\x1b[92m"):]
         if line.endswith("\x1b[0m"):
             line = line[:-1 * len("\x1b[0m")]
         domainGroup = re.search(
             r"((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9])",
             line.strip())
         if domainGroup is not None:
             # a domain has been found
             domain = domainGroup.group(1)
             inserted, _ = Ip().initialize(domain).addInDb()
             # failed, domain is out of wave, still noting thi
             if not inserted:
                 notes += domain + " exists but already added.\n"
             else:
                 countInserted += 1
                 notes += domain + " inserted.\n"
     if notes.strip() == "":
         return None, None, None, None
     if not markerFound:
         return None, None, None, None
     return notes, tags, "wave", {"wave": None}
Exemple #17
0
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()
Exemple #18
0
    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 = file_opened.read()
        targets = {}
        tags = []
        if "| http-methods:" not in notes:
            return None, None, None, None
        host, port, proto, service, risky_methods, supported_methods = parse(
            notes)
        if host == "":
            return None, None, None, None
        Ip().initialize(host).addInDb()
        p_o = Port().initialize(host, port, proto, service)
        res, iid = p_o.addInDb()
        if not res:
            p_o = Port.fetchObject({"_id": iid})

        p_o.updateInfos({"Methods": ", ".join(supported_methods)})
        targets[str(p_o.getId())] = {"ip": host, "port": port, "proto": proto}
        if "TRACE" in risky_methods:
            Defect().initialize(host, port, proto, "Méthode TRACE activée", "Difficile", "Important", "Important",
                                 "N/A", ["Socle"], notes="TRACE detected", proofs=[]).addInDb()
            risky_methods.remove("TRACE")
        if len(risky_methods) > 0:
            notes = "RISKY HTTP METHODS ALLOWED : " + " ".join(risky_methods)
            tags = []
            tags.append("Interesting")
        return notes, tags, "port", targets
Exemple #19
0
 def addInTreeview(self, parentNode=None, addChildren=True):
     """Add this view in treeview. Also stores infos in application treeview.
     Args:
         parentNode: if None, will calculate the parent. If setted, forces the node to be inserted inside given parentNode.
         _addChildren: not used here
     """
     if parentNode is None:
         parentNode = self.getParent()
     ip_node = None
     try:
         if isinstance(parentNode, ObjectId):
             ip_parent_o = Ip.fetchObject({"_id": parentNode})
             if ip_parent_o is not None:
                 parent_view = IpView(self.appliTw,
                                      self.appliViewFrame, self.mainApp,
                                      IpController(ip_parent_o))
                 parent_view.addInTreeview(None, False)
         ip_node = self.appliTw.insert(parentNode,
                                       "end",
                                       str(self.controller.getDbId()),
                                       text=str(
                                           self.controller.getModelRepr()),
                                       tags=self.controller.getTags(),
                                       image=self.getClassIcon())
     except TclError:
         pass
     self.appliTw.views[str(self.controller.getDbId())] = {"view": self}
     if addChildren and ip_node is not None:
         self._insertChildrenDefects()
         self._insertChildrenTools()
         self._insertChildrenPorts(ip_node)
     # self.appliTw.sort(parentNode)
     if "hidden" in self.controller.getTags():
         self.hide()
     modelData = self.controller.getData()
     if not modelData["in_scopes"]:
         self.controller.addTag("OOS")
Exemple #20
0
 def loadSummary(self):
     """Reload information about IP and Port and reload the view.
     """
     mongoInstance = MongoCalendar.getInstance()
     nonEmptyIps = list(
         mongoInstance.aggregate("ports", [{
             "$group": {
                 "_id": "$ip"
             }
         }, {
             "$count": "total"
         }]))
     if not nonEmptyIps:
         return
     nonEmptyIps = nonEmptyIps[0]
     step = 0
     dialog = ChildDialogProgress(
         self.parent, "Loading summary ",
         "Refreshing summary. Please wait for a few seconds.", 200,
         "determinate")
     dialog.show(nonEmptyIps["total"])
     nonEmptyIps = mongoInstance.aggregate("ports", [{
         "$group": {
             "_id": "$ip"
         }
     }])
     for ipCIDR in nonEmptyIps:
         step += 1
         ip = Ip.fetchObject({"ip": ipCIDR["_id"]})
         if ip.in_scopes:
             dialog.update(step)
             self.insertIp(ip.ip)
     self.frameTw.update_idletasks()
     self.parent.update_idletasks()
     smart_grid(self.frameTw, self.root, *list(self.treeviews.values()))
     dialog.destroy()
Exemple #21
0
 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.
     """
     tags = ["todo"]
     targets = {}
     notes = file_opened.read()
     if notes == "":
         return None, None, None, None
     if not notes.startswith("- Nikto v"):
         return None, None, None, None
     host, port, service, infos = parse_nikto_plain_text(notes)
     if host:
         if port:
             Ip().initialize(host).addInDb()
             p_o = Port().initialize(host, port, "tcp", service)
             res, iid = p_o.addInDb()
             if not res:
                 p_o = Port.fetchObject({"_id": iid})
             p_o.updateInfos({
                 "Nikto":
                 infos,
                 "SSL":
                 "True" if service == "https" else "False"
             })
             targets[str(iid)] = {"ip": host, "port": port, "proto": "tcp"}
     return notes, tags, "port", targets
Exemple #22
0
    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}
Exemple #23
0
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
Exemple #24
0
 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 = []
     content = file_opened.read()
     targets = {}
     try:
         notes_json = json.loads(content)
     except json.decoder.JSONDecodeError:
         return None, None, None, None
     oneScanIsValid = False
     for scan in notes_json:
         try:
             if scan.get('ssh_scan_version', None) is None:
                 continue
             ips = [scan["hostname"], scan["ip"]]
             port = str(scan["port"])
             for ip in ips:
                 if ip.strip() == "":
                     continue
                 Ip().initialize(ip).addInDb()
                 port_o = Port().initialize(ip, port, "tcp", "ssh")
                 res, iid = port_o.addInDb()
                 if not res:
                     port_o = Port.fetchObject({"_id": iid})
                 notes = "\n".join(scan["compliance"].get(
                     "recommendations", []))
                 targets[str(port_o.getId())] = {
                     "ip": ip,
                     "port": port,
                     "proto": "tcp"
                 }
                 oneScanIsValid = True
                 if "nopassword" in scan["auth_methods"]:
                     tags = ["P0wned!"]
                 # Will not exit if port was not ssh
                 is_ok = scan["compliance"]["compliant"]
                 if str(is_ok) == "False":
                     port_o.updateInfos({"compliant": "False"})
                     port_o.updateInfos(
                         {"auth_methods": scan["auth_methods"]})
                     Defect().initialize(
                         ip,
                         port,
                         "tcp",
                         "Défauts d’implémentation de la configuration SSH",
                         "Très difficile",
                         "Majeur",
                         "Important",
                         "N/A", ["Socle"],
                         notes=notes,
                         proofs=[]).addInDb()
         except KeyError:
             continue
     if not oneScanIsValid:
         return None, None, None, None
     return notes, tags, "port", targets
Exemple #25
0
 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.
     """
     tags = ["todo"]
     targets = {}
     notes = file_opened.read()
     if notes == "":
         return None, None, None, None
     try:
         data = json.loads(notes)
     except json.decoder.JSONDecodeError:
         return None, None, None, None
     regex_host = r"https?://([^\/]+)"
     oneValidWhatweb = False
     for website in data:
         keys = website.keys()
         expected_keys = [
             'target', 'http_status', 'request_config', 'plugins'
         ]
         all_keys = True
         for expected in expected_keys:
             if expected not in keys:
                 all_keys = False
                 break
         if not all_keys:
             continue
         host_port_groups = re.search(regex_host, website["target"])
         if host_port_groups is None:
             continue
         host_port = host_port_groups.group(1)
         service = "https" if "https://" in website["target"] else "http"
         if len(host_port.split(":")) == 2:
             port = host_port.split(":")[1]
             host = host_port.split(":")[0]
         else:
             host = host_port
             port = "443" if "https://" in website["target"] else "80"
         Ip().initialize(host).addInDb()
         p_o = Port().initialize(host, port, "tcp", service)
         inserted, iid = p_o.addInDb()
         if not inserted:
             p_o = Port.fetchObject({"_id": iid})
         infosToAdd = {"URL": website["target"]}
         for plugin in website.get("plugins", {}):
             item = website["plugins"][plugin].get("string")
             if isinstance(item, list):
                 if item:
                     infosToAdd[plugin] = item
             else:
                 item = str(item)
                 if item != "":
                     infosToAdd[plugin] = item
         p_o.updateInfos(infosToAdd)
         targets[str(p_o.getId())] = {
             "ip": host,
             "port": port,
             "proto": "tcp"
         }
         oneValidWhatweb = True
     if not oneValidWhatweb:
         return None, None, None, None
     return notes, tags, "port", targets
Exemple #26
0
def parseWarnings(file_opened):
    """
    Parse the result of a testssl json output file
        Args:
            file_opened:  the opened file reference

        Returns:
            Returns a tuple with (None values if not matching a testssl output):
                - a list of string for each testssl NOT ok, WARN, or MEDIUM warnings
                - a dict of targeted objects with database id as key and a unique key as a mongo search pipeline ({})
    """
    targets = {}
    missconfiguredHosts = {}
    firstLine = True
    for line in file_opened:
        if firstLine:
            if line.strip() != '"id", "fqdn/ip", "port", "severity", "finding", "cve", "cwe"' and \
                    line.strip() != '"id","fqdn/ip","port","severity","finding","cve","cwe"':
                return None, None
            firstLine = False
            continue
        # Search ip in file
        warn = re.search(
            r"^\"[^\"]*\", ?\"([^\"]*)\", ?\"([^\"]*)\", ?\"(OK|INFO|NOT ok|WARN|LOW|MEDIUM|HIGH|CRITICAL)\", ?\"[^\"]*\", ?\"[^\"]*\", ?\"[^\"]*\"$",
            line)
        if warn is not None:
            ip = warn.group(1)
            domain = None
            port = warn.group(2)
            notes = warn.group(3)
            if "/" in ip:
                domain = ip.split("/")[0]
                ip = "/".join(ip.split("/")[1:])
                Ip().initialize(domain).addInDb()
                Port().initialize(domain, port, "tcp", "ssl").addInDb()
            Ip().initialize(ip).addInDb()
            Port().initialize(ip, port, "tcp", "ssl").addInDb()
            if notes not in ["OK", "INFO"]:
                missconfiguredHosts[ip] = missconfiguredHosts.get(ip, {})
                missconfiguredHosts[ip][port] = missconfiguredHosts[ip].get(
                    port, [])
                missconfiguredHosts[ip][port].append(notes + " : " + line)
                if domain is not None:
                    missconfiguredHosts[domain] = missconfiguredHosts.get(
                        domain, {})
                    missconfiguredHosts[domain][port] = missconfiguredHosts[
                        domain].get(port, [])
                    missconfiguredHosts[domain][port].append(notes + " : " +
                                                             line)
    for ip in missconfiguredHosts.keys():
        for port in missconfiguredHosts[ip].keys():
            p_o = Port.fetchObject({"ip": ip, "port": port, "proto": "tcp"})
            targets[str(p_o.getId())] = {
                "ip": ip,
                "port": port,
                "proto": "tcp"
            }
            missconfiguredHosts[ip][port].sort()
            notes = "\n".join(missconfiguredHosts[ip][port])
            res, _ = Defect().initialize(ip,
                                         port,
                                         "tcp",
                                         "Défauts d'implémentation du SSL/TLS",
                                         "Très difficile",
                                         "Majeur",
                                         "Important",
                                         "N/A", ["Socle"],
                                         notes=notes,
                                         proofs=[]).addInDb()
            if not res:
                p_o.updateInfos({"compliant": "False"})
                defect_o = Defect.fetchObject({
                    "ip": ip,
                    "title": "Défauts d'implémentation du SSL/TLS",
                    "port": port,
                    "proto": "tcp"
                })
                defect_o.notes += notes
                defect_o.update()
    if firstLine:
        return None, None
    return str(len(missconfiguredHosts.keys())
               ) + " misconfigured hosts found. Defects created.", targets
    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
        """
        mongoInstance = MongoCalendar.getInstance()
        if not mongoInstance.hasACalendarOpen():
            return
        if mongoInstance.calendarName != db:
            return
        # Delete
        if action == "delete":
            if collection == "defects":
                view = self.getViewFromId(str(iid))
                if view is not None:
                    view.beforeDelete()
                    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 = mongoInstance.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)))
            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:
                    oldTags = self.item(str(iid))["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 _load(self):
     """
     Load the treeview with database information
     """
     mongoInstance = MongoCalendar.getInstance()
     dialog = ChildDialogProgress(self.appli, "Loading "+str(
         mongoInstance.calendarName), "Opening "+str(mongoInstance.calendarName) + ". Please wait for a few seconds.", 200, "determinate")
     step = 0
     dialog.show(100)
     nbObjects = mongoInstance.find("waves").count()
     nbObjects += mongoInstance.find("scopes").count()
     nbObjects += mongoInstance.find("intervals").count()
     nbObjects += mongoInstance.find("scopes").count()
     nbObjects += mongoInstance.find("ips").count()
     nbObjects += mongoInstance.find("ports").count()
     nbObjects += mongoInstance.find("tools").count()
     onePercentNbObject = nbObjects//100 if nbObjects > 100 else 1
     nbObjectTreated = 0
     for child in self.get_children():
         self.delete(child)
     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
     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()
Exemple #29
0
    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}
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