def test_sanitise_input(self):
        """
        Test sanitiseInput(self, cmd)
        """
        safe = SpiderFootHelpers.sanitiseInput("example-string")
        self.assertIsInstance(safe, bool)
        self.assertTrue(safe)

        safe = SpiderFootHelpers.sanitiseInput("example-string\n")
        self.assertIsInstance(safe, bool)
        self.assertFalse(safe)

        safe = SpiderFootHelpers.sanitiseInput("example string")
        self.assertIsInstance(safe, bool)
        self.assertFalse(safe)

        safe = SpiderFootHelpers.sanitiseInput("-example-string")
        self.assertIsInstance(safe, bool)
        self.assertFalse(safe)

        safe = SpiderFootHelpers.sanitiseInput("..example-string")
        self.assertIsInstance(safe, bool)
        self.assertFalse(safe)

        safe = SpiderFootHelpers.sanitiseInput("12")
        self.assertIsInstance(safe, bool)
        self.assertFalse(safe)
Example #2
0
    def handleEvent(self, event):
        eventName = event.eventType
        srcModuleName = event.module
        eventData = event.data

        self.debug(f"Received event, {eventName}, from {srcModuleName}")

        if self.errorState:
            return

        if srcModuleName == "sfp_tool_onesixtyone":
            self.debug("Skipping event from myself.")
            return

        if not self.opts['onesixtyone_path']:
            self.error("You enabled sfp_tool_onesixtyone but did not set a path to the tool!")
            self.errorState = True
            return

        exe = self.opts['onesixtyone_path']
        if self.opts['onesixtyone_path'].endswith('/'):
            exe = f"{exe}onesixtyone"

        if not os.path.isfile(exe):
            self.error(f"File does not exist: {exe}")
            self.errorState = True
            return

        if not SpiderFootHelpers.sanitiseInput(eventData, extra=['/']):
            self.debug("Invalid input, skipping.")
            return

        targets = []
        try:
            if eventName == "NETBLOCK_OWNER" and self.opts['netblockscan']:
                net = IPNetwork(eventData)
                if net.prefixlen < self.opts['netblockscanmax']:
                    self.debug(f"Skipping scanning of {eventData}, too big.")
                    return
                for addr in net.iter_hosts():
                    targets.append(str(addr))
        except BaseException as e:
            self.error(f"Strange netblock identified, unable to parse: {eventData} ({e})")
            return

        # Don't look up stuff twice, check IP == IP here
        if eventData in self.results:
            self.debug(f"Skipping {eventData} as already scanned.")
            return
        else:
            # Might be a subnet within a subnet or IP within a subnet
            for addr in self.results:
                if IPNetwork(eventData) in IPNetwork(addr):
                    self.debug(f"Skipping {eventData} as already within a scanned range.")
                    return

        self.results[eventData] = True

        # If we weren't passed a netblock, this will be empty
        if not targets:
            targets.append(eventData)

        for target in targets:
            args = [
                exe,
                "-c",
                self.communitiesFile,
                target
            ]
            try:
                p = Popen(args, stdout=PIPE, stderr=PIPE)
                out, stderr = p.communicate(input=None)
                stdout = out.decode(sys.stdin.encoding)
            except Exception as e:
                self.error(f"Unable to run onesixtyone: {e}")
                continue

            if p.returncode != 0:
                self.error(f"Unable to read onesixtyone output\nstderr: {stderr}\nstdout: {stdout}")
                continue

            if not stdout:
                self.debug(f"onesixtyone returned no output for {target}")
                continue

            for result in stdout.split("\n"):
                srcevent = event

                if target not in result:
                    continue

                if target != eventData:
                    srcevent = SpiderFootEvent("IP_ADDRESS", target, self.__name__, event)
                    self.notifyListeners(srcevent)

                e = SpiderFootEvent('UDP_PORT_OPEN', f"{target}:161", self.__name__, srcevent)
                self.notifyListeners(e)

                e = SpiderFootEvent("UDP_PORT_OPEN_INFO", result, self.__name__, e)
                self.notifyListeners(e)
    def handleEvent(self, event):
        eventName = event.eventType
        srcModuleName = event.module
        eventData = event.data

        self.debug(f"Received event, {eventName}, from {srcModuleName}")

        if self.errorState:
            return

        if eventData in self.results:
            self.debug(f"Skipping {eventData} as already scanned.")
            return

        self.results[eventData] = True

        if not self.opts['wafw00f_path']:
            self.error(
                "You enabled sfp_tool_wafw00f but did not set a path to the tool!"
            )
            self.errorState = True
            return

        exe = self.opts['wafw00f_path']
        if self.opts['wafw00f_path'].endswith('/'):
            exe = exe + 'wafw00f'

        if not os.path.isfile(exe):
            self.error(f"File does not exist: {exe}")
            self.errorState = True
            return

        url = eventData

        if not SpiderFootHelpers.sanitiseInput(url):
            self.error("Invalid input, refusing to run.")
            return

        args = [self.opts['python_path'], exe, '-a', '-o-', '-f', 'json', url]
        try:
            p = Popen(args, stdout=PIPE, stderr=PIPE)
            stdout, stderr = p.communicate(input=None)
        except Exception as e:
            self.error(f"Unable to run wafw00f: {e}")
            return

        if p.returncode != 0:
            self.error(
                f"Unable to read wafw00f output\nstderr: {stderr}\nstdout: {stdout}"
            )
            return

        if not stdout:
            self.debug(f"wafw00f returned no output for {eventData}")
            return

        try:
            result_json = json.loads(stdout)
        except Exception as e:
            self.error(
                f"Could not parse wafw00f output as JSON: {e}\nstdout: {stdout}"
            )
            return

        if not result_json:
            self.debug(f"wafw00f returned no output for {eventData}")
            return

        evt = SpiderFootEvent('RAW_RIR_DATA', json.dumps(result_json),
                              self.__name__, event)
        self.notifyListeners(evt)

        for waf in result_json:
            if not waf:
                continue

            firewall = waf.get('firewall')
            if not firewall:
                continue
            if firewall == 'Generic':
                continue

            manufacturer = waf.get('manufacturer')
            if not manufacturer:
                continue

            software = ' '.join(filter(None, [manufacturer, firewall]))

            if software:
                evt = SpiderFootEvent('WEBSERVER_TECHNOLOGY', software,
                                      self.__name__, event)
                self.notifyListeners(evt)
    def handleEvent(self, event):
        eventName = event.eventType
        srcModuleName = event.module
        eventData = event.data

        self.debug(f"Received event, {eventName}, from {srcModuleName}")

        if self.errorState:
            return

        if eventData in self.results:
            self.debug(f"Skipping {eventData} as already scanned.")
            return

        self.results[eventData] = True

        if not self.opts['cmseekpath']:
            self.error("You enabled sfp_tool_cmseek but did not set a path to the tool!")
            self.errorState = True
            return

        # Normalize path
        if self.opts['cmseekpath'].endswith('cmseek.py'):
            exe = self.opts['cmseekpath']
            resultpath = self.opts['cmseekpath'].split("cmseek.py")[0] + "/Result"
        elif self.opts['cmseekpath'].endswith('/'):
            exe = self.opts['cmseekpath'] + "cmseek.py"
            resultpath = self.opts['cmseekpath'] + "Result"
        else:
            exe = self.opts['cmseekpath'] + "/cmseek.py"
            resultpath = self.opts['cmseekpath'] + "/Result"

        # If tool is not found, abort
        if not os.path.isfile(exe):
            self.error(f"File does not exist: {exe}")
            self.errorState = True
            return

        # Sanitize domain name.
        if not SpiderFootHelpers.sanitiseInput(eventData):
            self.error("Invalid input, refusing to run.")
            return

        args = [
            self.opts['pythonpath'],
            exe,
            '--follow-redirect',
            '--batch',
            '-u',
            eventData
        ]
        try:
            p = Popen(args, stdout=PIPE, stderr=PIPE)
            stdout, stderr = p.communicate(input=None)
        except Exception as e:
            self.error(f"Unable to run CMSeeK: {e}")
            return

        if p.returncode != 0:
            self.error(f"Unable to read CMSeeK output\nstderr: {stderr}\nstdout: {stdout}")
            return

        if b"CMS Detection failed" in stdout:
            self.debug(f"Could not detect the CMS for {eventData}")
            return

        log_path = f"{resultpath}/{eventData}/cms.json"
        if not os.path.isfile(log_path):
            self.error(f"File does not exist: {log_path}")
            return

        try:
            f = io.open(log_path, encoding='utf-8')
            j = json.loads(f.read())
        except Exception as e:
            self.error(f"Could not parse CMSeeK output file {log_path} as JSON: {e}")
            return

        cms_name = j.get('cms_name')

        if not cms_name:
            return

        cms_version = j.get('cms_version')

        software = ' '.join(filter(None, [cms_name, cms_version]))

        if not software:
            return

        evt = SpiderFootEvent("WEBSERVER_TECHNOLOGY", software, self.__name__, event)
        self.notifyListeners(evt)
Example #5
0
    def handleEvent(self, event):
        eventName = event.eventType
        srcModuleName = event.module
        eventData = event.data

        self.debug(f"Received event, {eventName}, from {srcModuleName}")

        if self.errorState:
            return

        if srcModuleName == "sfp_tool_nuclei":
            return

        if not self.opts['nuclei_path'] or not self.opts['template_path']:
            self.error(
                "You enabled sfp_tool_nuclei but did not set a path to the tool and/or templates!"
            )
            self.errorState = True
            return

        exe = self.opts['nuclei_path']
        if self.opts['nuclei_path'].endswith('/'):
            exe = f"{exe}nuclei"

        if not os.path.isfile(exe):
            self.error(f"File does not exist: {exe}")
            self.errorState = True
            return

        if not SpiderFootHelpers.sanitiseInput(eventData, extra=['/']):
            self.debug("Invalid input, skipping.")
            return

        # Don't look up stuff twice
        if eventData in self.results:
            self.debug(f"Skipping {eventData} as already scanned.")
            return

        if eventName != "INTERNET_NAME":
            # Might be a subnet within a subnet or IP within a subnet
            for addr in self.results:
                try:
                    if IPNetwork(eventData) in IPNetwork(addr):
                        self.debug(
                            f"Skipping {eventData} as already within a scanned range."
                        )
                        return
                except BaseException:
                    # self.results will also contain hostnames
                    continue

        self.results[eventData] = True

        timeout = 240
        try:
            target = eventData
            if eventName == "NETBLOCK_OWNER" and self.opts['netblockscan']:
                target = ""
                net = IPNetwork(eventData)
                if net.prefixlen < self.opts['netblockscanmax']:
                    self.debug(f"Skipping scanning of {eventData}, too big.")
                    return

                # Nuclei doesn't support targeting subnets directly,
                # so for now work around that by listing each IP.
                for addr in IPNetwork(eventData).iter_hosts():
                    target += str(addr) + "\n"
                    timeout += 240
        except BaseException as e:
            self.error(
                f"Strange netblock identified, unable to parse: {eventData} ({e})"
            )
            return

        try:
            args = [
                exe,
                "-silent",
                "-json",
                "-concurrency",
                "100",
                "-retries",
                "1",
                "-t",
                self.opts["template_path"],
                "-no-interactsh",
                "-etags",
                "dos",
                "fuzz",
                "misc",
            ]
            p = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE)
            try:
                stdout, stderr = p.communicate(input=target.encode(
                    sys.stdin.encoding),
                                               timeout=timeout)
                if p.returncode == 0:
                    content = stdout.decode(sys.stdout.encoding)
                else:
                    self.error("Unable to read Nuclei content.")
                    self.debug(f"Error running Nuclei: {stderr}, {stdout}")
                    return
            except TimeoutExpired:
                p.kill()
                stdout, stderr = p.communicate()
                self.debug("Timed out waiting for Nuclei to finish")
                return
        except BaseException as e:
            self.error(f"Unable to run Nuclei: {e}")
            return

        if not content:
            return

        try:
            for line in content.split("\n"):
                if not line:
                    continue

                data = json.loads(line)
                srcevent = event
                host = data['matched-at'].split(":")[0]
                if host != eventData:
                    if self.sf.validIP(host):
                        srctype = "IP_ADDRESS"
                    else:
                        srctype = "INTERNET_NAME"
                    srcevent = SpiderFootEvent(srctype, host, self.__name__,
                                               event)
                    self.notifyListeners(srcevent)

                matches = re.findall(r"CVE-\d{4}-\d{4,7}", line)
                if matches:
                    for cve in matches:
                        etype, cvetext = self.sf.cveInfo(cve)
                        e = SpiderFootEvent(etype, cvetext, self.__name__,
                                            srcevent)
                        self.notifyListeners(e)
                else:
                    if "matcher-name" in data:
                        etype = "VULNERABILITY_GENERAL"
                        if data['info']['severity'] == "info":
                            etype = "WEBSERVER_TECHNOLOGY"

                        datatext = f"Template: {data['info']['name']}({data['template-id']})\n"
                        datatext += f"Matcher: {data['matcher-name']}\n"
                        datatext += f"Matched at: {data['matched-at']}\n"
                        if data['info'].get('reference'):
                            datatext += f"Reference: <SFURL>{data['info']['reference'][0]}</SFURL>"

                        evt = SpiderFootEvent(
                            etype,
                            datatext,
                            self.__name__,
                            srcevent,
                        )
                        self.notifyListeners(evt)
        except (KeyError, ValueError) as e:
            self.error(f"Couldn't parse the JSON output of Nuclei: {e}")
            self.error(f"Nuclei content: {content}")
            return
    def handleEvent(self, event):
        eventName = event.eventType
        srcModuleName = event.module
        eventData = event.data

        self.debug(f"Received event, {eventName}, from {srcModuleName}")

        if self.errorState:
            return

        if eventData in self.results:
            self.debug(f"Skipping {eventData} as already scanned.")
            return

        self.results[eventData] = True

        if not self.opts['snallygaster_path']:
            self.error(
                "You enabled sfp_tool_snallygaster but did not set a path to the tool!"
            )
            self.errorState = True
            return

        exe = self.opts["snallygaster_path"]
        if self.opts["snallygaster_path"].endswith("/"):
            exe = f"{exe}snallygaster"

        if not os.path.isfile(exe):
            self.error(f"File does not exist: {exe}")
            self.errorState = True
            return

        if not SpiderFootHelpers.sanitiseInput(eventData):
            self.error("Invalid input, refusing to run.")
            return

        args = [exe, '--nowww', '-j', eventData]
        try:
            p = Popen(args, stdout=PIPE, stderr=PIPE)
            out, stderr = p.communicate(input=None)
            stdout = out.decode(sys.stdin.encoding)
        except Exception as e:
            self.error(f"Unable to run snallygaster: {e}")
            return

        if p.returncode != 0:
            self.error(
                f"Unable to read onesixtyone output\nstderr: {stderr}\nstdout: {stdout}"
            )
            return

        if not stdout:
            self.debug(f"snallygaster returned no output for {eventData}")
            return

        try:
            result_json = json.loads(stdout)
        except Exception as e:
            self.error(
                f"Could not parse snallygaster output as JSON: {e}\nstderr: {stderr}\nstdout: {stdout}"
            )
            return

        if not result_json:
            self.debug(f"snallygaster returned no output for {eventData}")
            return

        for res in result_json:
            if "cause" not in res:
                continue

            text = f"Cause: {res['cause']}\nURL: {res['url']}"
            if res["misc"]:
                text += f"\nAdditional Info: {res['misc']}"
            evt = SpiderFootEvent(
                "VULNERABILITY_GENERAL",
                text,
                self.__name__,
                event,
            )
            self.notifyListeners(evt)
Example #7
0
    def handleEvent(self, event):
        eventName = event.eventType
        srcModuleName = event.module
        eventData = event.data

        self.debug(f"Received event, {eventName}, from {srcModuleName}")

        if self.errorState:
            return

        if not self.opts['wappalyzer_path']:
            self.error(
                "You enabled sfp_tool_wappalyzer but did not set a path to the tool!"
            )
            self.errorState = True
            return

        exe = self.opts['wappalyzer_path']
        if self.opts['wappalyzer_path'].endswith('/'):
            exe = f"{exe}cli.js"

        if not os.path.isfile(exe):
            self.error(f"File does not exist: {exe}")
            self.errorState = True
            return

        if not SpiderFootHelpers.sanitiseInput(eventData):
            self.debug("Invalid input, skipping.")
            return

        # Don't look up stuff twice
        if eventData in self.results:
            self.debug(f"Skipping {eventData} as already scanned.")
            return
        self.results[eventData] = True

        try:
            args = [self.opts["node_path"], exe, f"https://{eventData}"]
            p = Popen(args, stdout=PIPE, stderr=PIPE)
            try:
                stdout, stderr = p.communicate(input=None, timeout=60)
                if p.returncode == 0:
                    content = stdout.decode(sys.stdin.encoding)
                else:
                    self.error("Unable to read Wappalyzer content.")
                    self.error(f"Error running Wappalyzer: {stderr}, {stdout}")
                    return
            except TimeoutExpired:
                p.kill()
                stdout, stderr = p.communicate()
                self.debug("Timed out waiting for Wappalyzer to finish")
                return
        except BaseException as e:
            self.error(f"Unable to run Wappalyzer: {e}")
            return

        try:
            data = json.loads(content)
            for item in data["technologies"]:
                for cat in item["categories"]:
                    if cat["name"] == "Operating systems":
                        evt = SpiderFootEvent(
                            "OPERATING_SYSTEM",
                            item["name"],
                            self.__name__,
                            event,
                        )
                    elif cat["name"] == "Web servers":
                        evt = SpiderFootEvent(
                            "WEBSERVER_TECHNOLOGY",
                            item["name"],
                            self.__name__,
                            event,
                        )
                    else:
                        evt = SpiderFootEvent(
                            "SOFTWARE_USED",
                            item["name"],
                            self.__name__,
                            event,
                        )
                    self.notifyListeners(evt)
        except (KeyError, ValueError) as e:
            self.error(f"Couldn't parse the JSON output of Wappalyzer: {e}")
            self.error(f"Wappalyzer content: {content}")
            return
Example #8
0
    def handleEvent(self, event):
        eventName = event.eventType
        srcModuleName = event.module
        eventData = event.data

        self.debug(f"Received event, {eventName}, from {srcModuleName}")

        if self.errorState:
            return

        if srcModuleName == "sfp_tool_testsslsh":
            self.debug("Skipping event from myself.")
            return

        if not self.opts['testsslsh_path']:
            self.error(
                "You enabled sfp_tool_testsslsh but did not set a path to the tool!"
            )
            self.errorState = True
            return

        exe = self.opts['testsslsh_path']
        if self.opts['testsslsh_path'].endswith('/'):
            exe = f"{exe}testssl.sh"

        if not os.path.isfile(exe):
            self.error(f"File does not exist: {exe}")
            self.errorState = True
            return

        if not SpiderFootHelpers.sanitiseInput(eventData, extra=['/']):
            self.debug("Invalid input, skipping.")
            return

        targets = list()
        try:
            if eventName == "NETBLOCK_OWNER" and self.opts['netblockscan']:
                net = IPNetwork(eventData)
                if net.prefixlen < self.opts['netblockscanmax']:
                    self.debug("Skipping scanning of " + eventData +
                               ", too big.")
                    return
                for addr in net.iter_hosts():
                    targets.append(str(addr))
        except BaseException as e:
            self.error(
                f"Strange netblock identified, unable to parse: {eventData} ({e})"
            )
            return

        # Don't look up stuff twice, check IP == IP here
        if eventData in self.results:
            self.debug(f"Skipping {eventData} as already scanned.")
            return
        else:
            if eventName != "INTERNET_NAME":
                # Might be a subnet within a subnet or IP within a subnet
                for addr in self.results:
                    try:
                        if IPNetwork(eventData) in IPNetwork(addr):
                            self.debug(
                                f"Skipping {eventData} as already within a scanned range."
                            )
                            return
                    except BaseException:
                        # self.results will also contain hostnames
                        continue

        self.results[eventData] = True

        # If we weren't passed a netblock, this will be empty
        if not targets:
            targets.append(eventData)

        for target in targets:
            # Create a temporary output file
            _, fname = tempfile.mkstemp("testssl.json")

            args = [
                exe, "-U", "--connect-timeout", "5", "--openssl-timeout", "5",
                "--jsonfile", fname, target
            ]
            try:
                p = Popen(args, stdout=PIPE, stderr=PIPE)
                out, stderr = p.communicate(input=None)
                stdout = out.decode(sys.stdin.encoding)
            except Exception as e:
                self.error(f"Unable to run testssl.sh: {e}")
                os.unlink(fname)
                continue

            if p.returncode != 0:
                err = None
                if "Unable to open a socket" in stdout:
                    err = "Unable to connect"
                else:
                    err = "Internal error"
                self.error(
                    f"Unable to read testssl.sh output for {target}: {err}")
                os.unlink(fname)
                continue

            if not stdout:
                self.debug(f"testssl.sh returned no output for {target}")
                os.unlink(fname)
                continue

            try:
                with open(fname, "r") as f:
                    result_json = json.loads(f.read())
                os.unlink(fname)
            except Exception as e:
                self.error(
                    f"Could not parse testssl.sh output as JSON: {e}\nstderr: {stderr}\nstdout: {stdout}"
                )
                continue

            if not result_json:
                self.debug(f"testssl.sh returned no output for {target}")
                continue

            for result in result_json:
                if result['finding'] == "not vulnerable":
                    continue

                if result['severity'] not in [
                        "LOW", "MEDIUM", "HIGH", "CRITICAL"
                ]:
                    continue

                if 'cve' in result:
                    for cve in result['cve'].split(" "):
                        etype, cvetext = self.sf.cveInfo(cve)
                        evt = SpiderFootEvent(etype, cvetext, self.__name__,
                                              event)
                        self.notifyListeners(evt)
                else:
                    evt = SpiderFootEvent(
                        "VULNERABILITY_GENERAL",
                        f"{result['id']} ({result['finding']})", self.__name__,
                        event)
                    self.notifyListeners(evt)
Example #9
0
    def handleEvent(self, event):
        eventName = event.eventType
        srcModuleName = event.module
        eventData = event.data

        self.debug(f"Received event, {eventName}, from {srcModuleName}")

        if self.errorState:
            return

        if srcModuleName == "sfp_tool_nbtscan":
            self.debug("Skipping event from myself.")
            return

        if not self.opts['nbtscan_path']:
            self.error("You enabled sfp_tool_nbtscan but did not set a path to the tool!")
            self.errorState = True
            return

        exe = self.opts['nbtscan_path']
        if self.opts['nbtscan_path'].endswith('/'):
            exe = f"{exe}nbtscan"

        if not os.path.isfile(exe):
            self.error(f"File does not exist: {exe}")
            self.errorState = True
            return

        if not SpiderFootHelpers.sanitiseInput(eventData, extra=['/']):
            self.debug("Invalid input, skipping.")
            return

        try:
            if eventName == "NETBLOCK_OWNER" and self.opts['netblockscan']:
                net = IPNetwork(eventData)
                if net.prefixlen < self.opts['netblockscanmax']:
                    self.debug(f"Skipping scanning of {eventData}, too big.")
                    return
        except BaseException as e:
            self.error(f"Strange netblock identified, unable to parse: {eventData} ({e})")
            return

        # Don't look up stuff twice, check IP == IP here
        if eventData in self.results:
            self.debug(f"Skipping {eventData} as already scanned.")
            return
        else:
            # Might be a subnet within a subnet or IP within a subnet
            for addr in self.results:
                if IPNetwork(eventData) in IPNetwork(addr):
                    self.debug(f"Skipping {eventData} as already within a scanned range.")
                    return

        self.results[eventData] = True

        args = [
            exe,
            "-v",
            eventData
        ]

        try:
            p = Popen(args, stdout=PIPE, stderr=PIPE)
            out, _ = p.communicate(input=None)
            stdout = out.decode(sys.stdin.encoding)
        except Exception as e:
            self.error(f"Unable to run nbtscan: {e}")
            return

        if not stdout:
            self.debug(f"nbtscan returned no output for {eventData}")
            return

        inside = False
        info = ""
        for row in stdout.split("\n"):
            if len(row) == 0:
                continue

            if "NetBIOS Name Table" in row:
                inside = True

            if "Adapter address" in row:
                info += f"{row}\n"
                inside = False

            if inside:
                info += f"{row}\n"

            if not inside and len(info) > 0:
                srcEvent = event
                addr = eventData
                if eventName == "NETBLOCK_OWNER":
                    # Extract the IP from the raw nbtscan output
                    addr = info.split("\n")[0].split("for Host ")[1].replace(":", "")
                    srcEvent = SpiderFootEvent("IP_ADDRESS", addr, self.__name__, event)
                    self.notifyListeners(srcEvent)

                evt = SpiderFootEvent('UDP_PORT_OPEN', f"{addr}:137", self.__name__, srcEvent)
                self.notifyListeners(evt)

                evt = SpiderFootEvent('UDP_PORT_OPEN_INFO', info, self.__name__, evt)
                self.notifyListeners(evt)
                info = ""
    def handleEvent(self, event):
        eventName = event.eventType
        srcModuleName = event.module
        eventData = event.data

        self.debug(f"Received event, {eventName}, from {srcModuleName}")

        if self.errorState:
            return

        if eventData in self.results:
            self.debug("Skipping " + eventData + " as already scanned.")
            return

        self.results[eventData] = True

        dnstwistLocation = which('dnstwist')
        if dnstwistLocation and Path(dnstwistLocation).is_file():
            cmd = ['dnstwist']
        else:
            if not self.opts['dnstwistpath']:
                self.error("You enabled sfp_tool_dnstwist but did not set a path to the tool!")
                self.errorState = True
                return

            # Normalize path
            if self.opts['dnstwistpath'].endswith('dnstwist.py'):
                exe = self.opts['dnstwistpath']
            elif self.opts['dnstwistpath'].endswith('/'):
                exe = self.opts['dnstwistpath'] + "dnstwist.py"
            else:
                exe = self.opts['dnstwistpath'] + "/dnstwist.py"

            # If tool is not found, abort
            if not Path(exe).is_file():
                self.error("File does not exist: " + exe)
                self.errorState = True
                return

            cmd = [self.opts['pythonpath'], exe]

        # Sanitize domain name.
        if not SpiderFootHelpers.sanitiseInput(eventData):
            self.error("Invalid input, refusing to run.")
            return

        try:
            p = Popen(cmd + ["-f", "json", "-r", eventData], stdout=PIPE, stderr=PIPE)
            stdout, stderr = p.communicate(input=None)
            if p.returncode == 0:
                content = stdout
            else:
                self.error("Unable to read DNSTwist content.")
                self.debug("Error running DNSTwist: " + stderr + ", " + stdout)
                return

            # For each line in output, generate a SIMILARDOMAIN event
            try:
                j = json.loads(content)
                for r in j:
                    if self.getTarget().matches(r['domain-name']):
                        continue

                    evt = SpiderFootEvent("SIMILARDOMAIN", r['domain-name'],
                                          self.__name__, event)
                    self.notifyListeners(evt)
            except Exception as e:
                self.error("Couldn't parse the JSON output of DNSTwist: " + str(e))
                return
        except Exception as e:
            self.error("Unable to run DNSTwist: " + str(e))
            return
Example #11
0
    def handleEvent(self, event):
        eventName = event.eventType
        srcModuleName = event.module
        eventData = event.data

        self.debug(f"Received event, {eventName}, from {srcModuleName}")

        if self.errorState:
            return

        if eventData in self.results:
            self.debug("Skipping " + eventData + " as already scanned.")
            return

        self.results[eventData] = True

        if not self.opts['whatweb_path']:
            self.error(
                "You enabled sfp_tool_whatweb but did not set a path to the tool!"
            )
            self.errorState = True
            return

        exe = self.opts['whatweb_path']
        if self.opts['whatweb_path'].endswith('/'):
            exe = exe + 'whatweb'

        # If tool is not found, abort
        if not os.path.isfile(exe):
            self.error("File does not exist: " + exe)
            self.errorState = True
            return

        # Sanitize domain name.
        if not SpiderFootHelpers.sanitiseInput(eventData):
            self.error("Invalid input, refusing to run.")
            return

        # Set aggression level
        try:
            aggression = int(self.opts['aggression'])
            if aggression > 4:
                aggression = 4
            if aggression < 1:
                aggression = 1
        except Exception:
            aggression = 1

        # Run WhatWeb
        args = [
            self.opts['ruby_path'], exe, "--quiet",
            "--aggression=" + str(aggression), "--log-json=/dev/stdout",
            "--user-agent=Mozilla/5.0", "--follow-redirect=never", eventData
        ]
        try:
            p = Popen(args, stdout=PIPE, stderr=PIPE)
            stdout, stderr = p.communicate(input=None)
        except Exception as e:
            self.error(f"Unable to run WhatWeb: {e}")
            return

        if p.returncode != 0:
            self.error("Unable to read WhatWeb output.")
            self.debug("Error running WhatWeb: " + stderr + ", " + stdout)
            return

        if not stdout:
            self.debug(f"WhatWeb returned no output for {eventData}")
            return

        try:
            result_json = json.loads(stdout)
        except Exception as e:
            self.error(f"Couldn't parse the JSON output of WhatWeb: {e}")
            return

        if len(result_json) == 0:
            return

        blacklist = [
            'Country', 'IP', 'Script', 'Title', 'HTTPServer',
            'RedirectLocation', 'UncommonHeaders', 'Via-Proxy', 'Cookies',
            'HttpOnly', 'Strict-Transport-Security', 'x-hacker', 'x-machine',
            'x-pingback', 'X-Backend', 'X-Cache', 'X-UA-Compatible',
            'X-Powered-By', 'X-Forwarded-For', 'X-Frame-Options',
            'X-XSS-Protection'
        ]

        found = False
        for result in result_json:
            plugin_matches = result.get('plugins')

            if not plugin_matches:
                continue

            if plugin_matches.get('HTTPServer'):
                for w in plugin_matches.get('HTTPServer').get('string'):
                    evt = SpiderFootEvent('WEBSERVER_BANNER', w, self.__name__,
                                          event)
                    self.notifyListeners(evt)
                    found = True

            if plugin_matches.get('X-Powered-By'):
                for w in plugin_matches.get('X-Powered-By').get('string'):
                    evt = SpiderFootEvent('WEBSERVER_TECHNOLOGY', w,
                                          self.__name__, event)
                    self.notifyListeners(evt)
                    found = True

            for plugin in plugin_matches:
                if plugin in blacklist:
                    continue
                evt = SpiderFootEvent('WEBSERVER_TECHNOLOGY', plugin,
                                      self.__name__, event)
                self.notifyListeners(evt)
                found = True

        if found:
            evt = SpiderFootEvent('RAW_RIR_DATA', str(result_json),
                                  self.__name__, event)
            self.notifyListeners(evt)