Esempio n. 1
0
 def __walk(self):
     """
     information.
     :yield: A list with the filtered values
     :rtype: `list`
     """
     for report in os.scandir(self.path):
         if fnmatch.fnmatch(report.name, self.pattern):
             try:
                 nmap_report = NmapParser.parse_fromfile(report.path)
                 yield from nmap_report.hosts
             except NmapParserException as ex:
                 log.error(f"Error parsing {report} - {ex}")
Esempio n. 2
0
    def run(self, target, options, callback):
        """
        Executes the scan on a given target.

        :param target:
        :param options:
        :param callback: callback function to report status to the server.
        :return: report object
        :rtype: `dscan.models.structures.Report`
        """
        self.ctarget = (target, options)
        nmap_proc = None
        try:
            options = " ".join([options, f"-oN {self.report_name('nmap')}"])
            nmap_proc = NmapProcess(targets=target,
                                    options=options,
                                    safe_mode=False,
                                    event_callback=self.show_status)

            log.info("Nmap scan started Sending success status")
            callback(Status.SUCCESS)
            rc = nmap_proc.run()
            if rc == 0:
                # after finished encode and hash the contents for transfer.
                self.__inc()
                data = nmap_proc.stdout.encode("utf-8")
                report_file = self.report_name("xml")
                with open(self.report_name("xml"), "wb") as rfile:
                    rfile.write(data)
                    rfile.flush()
                digest = hashlib.sha512(data).hexdigest()
                report = Report(len(data), os.path.basename(report_file),
                                digest)
                self.print(target, 100)
                return report
            else:
                callback(Status.FAILED)
                log.error(f"Nmap Scan failed {nmap_proc.stderr}")
        except Exception as ex:
            log.error(f"something went wrong {ex}")
            callback(Status.FAILED)
        finally:
            if nmap_proc:
                nmap_proc.stop()
                # orthodox fix NmapProcess is leaving subprocess streams open.
                subproc = getattr(nmap_proc, "_NmapProcess__nmap_proc")
                if subproc:
                    subproc.stdout.close()
                    subproc.stderr.close()
Esempio n. 3
0
    def do_ready(self):
        """
        After the authentication the agent notifies the server, that is
        ready to start scanning.
        This will handle the request and send a target to be scanned.
        """
        log.info("is Ready for targets")

        log.info(f"Agent is running with uid {self.msg.uid}")
        if self.msg.uid != 0:
            log.info("Waning! agent is not running as root "
                     "syn scans might abort not enough privileges!")

        target_data = self.ctx.pop(self.agent)
        if not target_data:
            if self.ctx.is_finished:
                log.info("Target is None and all stages are finished")
                # send empty command and terminate!
                cmd = Command("", "")
                self.request.sendall(cmd.pack())
                self.connected = False
            else:
                log.info("Waiting for a stage to finish")
                cmd = ExitStatus(Status.UNFINISHED)
                self.request.sendall(cmd.pack())
            return

        cmd = Command(*target_data)
        self.request.sendall(cmd.pack())
        status_bytes = self.request.recv(1)

        if len(status_bytes) == 0:
            self.connected = False
            log.info("Disconnected!")
            self.ctx.interrupted(self.agent)
            return

        status, = struct.unpack("<B", status_bytes)
        if status == Status.SUCCESS.value:
            log.info("Started scanning !")
            self.ctx.running(self.agent)
        else:
            log.error("Scan command returned Error")
            log.info("Server is Terminating connection!")
            self.connected = False
            self.ctx.interrupted(self.agent)
Esempio n. 4
0
    def __cstage(self, force_next=False):
        """
        :param force_next: if True wil force the stage to advance one step
        defaults to False.
        :type force_next: `bool`
        :return: An instance of `stage`
        :rtype: `stage`
        """
        try:
            if not self.cstage_name or force_next:
                stage = self.stage_list.pop(0)
                self.active_stages[stage.name] = stage
                self.cstage_name = stage.name

            return self.active_stages[self.cstage_name]
        except IndexError:
            log.error("Stage list is empty !")
            return None
Esempio n. 5
0
 def get_report(self, agent, file_name):
     """
     :param agent: str with ipaddress and port in ip:port format
     :type agent: `str`
     :param file_name: name of the file sent by the agent.
     :type file_name: `str`
     :return: file descriptor to save the scan report.
     """
     try:
         _, tstage = self.__find_task_stage(agent)
         file_name = f"{tstage.name}-{file_name}"
         report_file = open(os.path.join(self.reports_path, file_name),
                            "wb")
         return report_file
     except Exception as ex:
         log.error(f"Unable to open report for {file_name}")
         log.error(f"{ex}")
         return None
Esempio n. 6
0
    def save(self, targets):
        """
        Takes a list of targets to optimize and saves it in the workspace path.

        :param targets: `list` of targets (`str` and top optimize.
        :type: targets: `list` of `str`
        """
        assert targets, "Empty target list"
        ips = []

        with open(self.fpath, 'wt') as qfile:
            for target in targets:
                try:
                    if "/" in target:
                        net = ipaddress.ip_network(target.strip())
                        if net.prefixlen < 24:
                            subs = map(lambda n: f"{n.with_prefixlen}\n",
                                       net.subnets(new_prefix=24))
                            qfile.writelines(subs)
                        else:
                            qfile.write(f"{net.with_prefixlen}\n")
                    else:
                        ips.append(ipaddress.ip_address(target.strip()))
                except (TypeError, ValueError):
                    log.error(f"Error optimizing target: {target}")

            # sorting the ip addresses.
            ips.sort(key=ipaddress.get_mixed_type_key)
            # find consecutive ip address ranges.
            if ips:
                for first, last in ipaddress._find_address_range(ips):
                    ip_range = list(
                        ipaddress.summarize_address_range(first, last))
                    # if the number of ranges is more than one network in cidr
                    # format then the glob format x.x.x.x-y is more efficient,
                    # since nmap supports this format.
                    if len(ip_range) > 1:
                        qfile.write(f"{first}-{last.exploded.split('.')[3]}\n")
                    else:
                        qfile.write(f"{ip_range.pop().with_prefixlen}\n")
Esempio n. 7
0
    def __init__(self, config, options):
        """
        Holds the configuration parameters
        used at runtime for both server and agent!

        :param config: configparser with the configuration
        :type config: `configparser.ConfigParser`
        :param options: argument parser `argparse.ArgumentParser`
            with the user options
        """
        self.wspace = options.name
        self.port = options.p
        self.outdir = os.path.join(options.name, config.get(*self.BASE))
        os.makedirs(self.outdir, exist_ok=True)
        self.config = None
        if options.cmd == 'srv':
            self.config = ServerConfig(config, options, self.outdir)
            self.sslkey = self.get_work_path(
                config.get(*self.SSL_CERTS[0:3:2]))
            assert os.path.isfile(
                self.sslkey), "Certificate Private key not found"
            self.ciphers = config.get(*self.SSL_CERTS[0:4:3])
        else:
            self.host = options.s
        # set cert properties

        self.sslcert = self.get_work_path(config.get(*self.SSL_CERTS[0:2:1]))
        self.srv_hostname = config.get(*self.SSL_CERTS[0:5:4])

        assert os.path.isfile(self.sslcert), "Certificate file not found"

        digest: hashlib.sha512 = hashlib.sha512()
        try:
            with open(self.sslcert, 'rt') as cert:
                digest.update(cert.read().strip().encode("utf-8"))
                self.secret_key = digest.hexdigest().encode("utf-8")
        except OSError as ex:
            log.error(f"failed to open cert file {ex}")
            raise ex
Esempio n. 8
0
    def do_report(self):
        """
        When the scan the ends, the agent notifies the server that is ready
        to send the report.
        This method will handle the report transfer save the report in the
        reports directory and make the target as finished
        if the file hashes match.
        """
        log.info("Agent Reporting Complete Scan!")
        log.info(f"Filename {self.msg.filename} total file size "
                 f"{self.msg.filesize} file hash {self.msg.filehash}")

        file_size = self.msg.filesize
        nbytes = 0
        report = self.ctx.get_report(self.agent,
                                     self.msg.filename.decode("utf-8"))
        try:
            digest = hashlib.sha512()
            self.ctx.downloading(self.agent)
            while nbytes < file_size:
                data = self.request.recv(1024)
                report.write(data)
                digest.update(data)
                nbytes = nbytes + len(data)

            if not hmac.compare_digest(digest.hexdigest().encode("utf-8"),
                                       self.msg.filehash):
                log.error(f"Files are not equal! {digest.hexdigest()}")
                self.send_status(Status.FAILED)
            else:
                log.info("files are equal!")
                self.ctx.completed(self.agent)
                self.send_status(Status.SUCCESS)
        finally:
            if report:
                report.flush()
                report.close()