Example #1
0
def barstr(width, percent, color=None, inf=False):
    '''
    Returns the string representation of an ASCII 'progress bar'.

    :param width:       the maximum space of the bar in number of of characters
    :param percent:     the percentage of ``width`` that the bar will consume.
    :param color:       string specifying the color of the bar
    :param inf:         boolean determining whether the bar is supposed to be "infinite".
    :return:            the string representation of the progress bar.
    '''
    width = width - 13  # constant number of characters for the numbers
    if not inf:
        barw = int(round(width * percent))
        bar = ''.ljust(barw, '=')
        bar = bar.ljust(width, ' ')
    else:
        bar = infbarstr(width, int(percent))
    if color is not None:
        filler = '\u25A0'
        bar = bar.replace('=', filler)
        bar = stylize('[', colored.attr('bold')) + stylize(
            bar, colored.fg(color)) + stylize(']', colored.attr('bold'))
    else:
        bar = '[%s]' % bar
    if inf:
        return bar
    return '{0} {1: >7.3f} %'.format(bar, percent * 100.)
Example #2
0
    def check_cves(self, vulnerabilities: Dict[Text, List[Text]]) -> None:
        cvelist: Dict[Text, Vulnerability] = {}
        for cve, description in self.vulnerability_list.items():
            version_min = description.get('version_min', "")
            version_max = description.get('version_max', "")
            indocs = description.get('docs', False)
            if self.between_versions(version_min, version_max):
                cvelist[cve] = Vulnerability(cve, indocs)

        cvemessagelist: List[Text] = []
        if cvelist:
            for e in cvelist.values():
                cvemessagelist.append(f"  * {e.cve}: {e.url}")
                if e.cve in vulnerabilities.keys():
                    if isinstance(vulnerabilities[e.cve], list):
                        for e1 in vulnerabilities[e.cve]:
                            cvemessagelist.append(f"    - {e1}")
                    else:
                        cvemessagelist.append("\n".join(
                            [f"    - {v}" for v in vulnerabilities[e.cve]]))

        logging.info("".join([
            stylize(EMOJI['warning'] + " client affected by CVEs:\n",
                    fg('yellow') + attr('bold')), "\n".join(cvemessagelist)
        ]))
Example #3
0
    def connect(self,
                user: Text,
                host: Text,
                port: int,
                method: AuthenticationMethod,
                password: Optional[Text] = None,
                key: Optional[PKey] = None,
                *,
                run_post_auth: bool = True) -> int:
        if not host:
            raise MissingHostException()

        auth_status = paramiko.common.AUTH_FAILED
        self.session.ssh_client = SSHClient(host, port, method, password, user,
                                            key, self.session)
        self.pre_auth_action()
        try:
            if self.session.ssh_client is not None and self.session.ssh_client.connect(
            ):
                auth_status = paramiko.common.AUTH_SUCCESSFUL
        except paramiko.SSHException:
            logging.error(
                stylize("Connection to remote server refused",
                        fg('red') + attr('bold')))
            return paramiko.common.AUTH_FAILED
        if run_post_auth:
            self.post_auth_action(
                auth_status == paramiko.common.AUTH_SUCCESSFUL)
        return auth_status
Example #4
0
    def run_audit(self) -> None:
        vulnerabilities: DefaultDict[Text, List[Text]] = defaultdict(list)
        for k, v in self.check_key_negotiation().items():
            vulnerabilities[k].extend(v)

        vulnerabilities["clientaudit"].extend(self.audit())

        self.check_cves(vulnerabilities)
        client_audits = vulnerabilities.get("clientaudit", [])
        if client_audits:
            logging.info("".join([
                stylize(EMOJI['warning'] + " client audit tests:\n",
                        fg('yellow') + attr('bold')),
                "\n".join([f"  * {v}" for v in client_audits])
            ]))
Example #5
0
 def check_key_negotiation(self) -> Dict[Text, List[Text]]:
     messages: List[Text] = []
     if not self.SERVER_HOST_KEY_ALGORITHMS or not self.SERVER_HOST_KEY_ALGORITHMS_CVE:
         return {}
     if isinstance(self.key_negotiation_data.session.proxyserver.host_key,
                   ECDSAKey):
         logging.warning(
             "%s: ecdsa-sha2 key is a bad choice; this will produce false positives!",
             self.client_name())
     for host_key_algo in self.SERVER_HOST_KEY_ALGORITHMS:
         if self.key_negotiation_data.server_host_key_algorithms == host_key_algo:
             messages.append(
                 stylize(
                     "client connecting for the first time or using default key order!",
                     fg('green')))
             break
     else:
         messages.append(
             stylize("client has a locally cached remote fingerprint.",
                     fg('yellow')))
     messages.append(
         f"Preferred server host key algorithm: {self.key_negotiation_data.server_host_key_algorithms[0]}"
     )
     return {self.SERVER_HOST_KEY_ALGORITHMS_CVE: messages}
Example #6
0
def print_log(predictions, corrects=None):
    max_val = max(predictions)
    colors = [237, 237, 237, 237, 240, 243, 246, 249, 252, 255]
    log = ''
    for idx, p in enumerate(predictions):
        color_id = int((p / max_val) * 10 + 0.5)
        color_id = min(9, color_id)
        color_id = max(0, color_id)
        if corrects is not None:
            c = corrects[idx]
        else:
            c = ''
        log += stylize('%.3f%s ' % (p, c), colored.fg(colors[color_id]))
    argmax_id = np.argmax(predictions.detach().cpu().numpy())
    log += str(decode_desc(argmax_id))
    print(log)
Example #7
0
    def auth_fallback(self, username: Text) -> int:
        if not self.args.fallback_host:
            if self.session.agent:
                logging.error("\n".join([
                    stylize(
                        EMOJI['exclamation'] +
                        " ssh agent keys are not allowed for signing. Remote authentication not possible.",
                        fg('red') + attr('bold')),
                    stylize(
                        EMOJI['information'] +
                        " To intercept clients, you can provide credentials for a honeypot.",
                        fg('yellow') + attr('bold'))
                ]))
            else:
                logging.error("\n".join([
                    stylize(
                        EMOJI['exclamation'] +
                        " ssh agent not forwarded. Login to remote host not possible with publickey authentication.",
                        fg('red') + attr('bold')),
                    stylize(
                        EMOJI['information'] +
                        " To intercept clients without a forwarded agent, you can provide credentials for a honeypot.",
                        fg('yellow') + attr('bold'))
                ]))
            return paramiko.common.AUTH_FAILED

        auth_status = self.connect(user=self.args.fallback_username
                                   or username,
                                   password=self.args.fallback_password,
                                   host=self.args.fallback_host,
                                   port=self.args.fallback_port,
                                   method=AuthenticationMethod.password,
                                   run_post_auth=False)
        if auth_status == paramiko.common.AUTH_SUCCESSFUL:
            logging.warning(
                stylize(
                    EMOJI['warning'] +
                    " publickey authentication failed - no agent forwarded - connecting to honeypot!",
                    fg('yellow') + attr('bold')), )
        else:
            logging.error(
                stylize(
                    EMOJI['exclamation'] +
                    " Authentication against honeypot failed!",
                    fg('red') + attr('bold')), )
        return auth_status
Example #8
0
def to_color_str(value, max_val):
    colors = [237, 237, 237, 237, 240, 243, 246, 249, 252, 255]
    color_id = int((value / max_val) * 10 + 0.5)
    color_id = min(9, color_id)
    color_id = max(0, color_id)
    return stylize('%.3f' % value, colored.fg(colors[color_id]))
Example #9
0
    def post_auth_action(self, success: bool) -> None:
        @typechecked
        def get_agent_pubkeys() -> List[Tuple[Text, SSHKey, bool, Text]]:
            pubkeyfile_path = None

            keys_parsed: List[Tuple[Text, SSHKey, bool, Text]] = []
            if self.session.agent is None:
                return keys_parsed

            keys = self.session.agent.get_keys()
            for k in keys:
                ssh_pub_key = SSHKey(f"{k.get_name()} {k.get_base64()}")
                ssh_pub_key.parse()
                keys_parsed.append(
                    (k.get_name(), ssh_pub_key, k.can_sign(), k.get_base64()))

            if self.session.session_log_dir:
                os.makedirs(self.session.session_log_dir, exist_ok=True)
                pubkeyfile_path = os.path.join(self.session.session_log_dir,
                                               'publickeys')
                with open(pubkeyfile_path, 'a+') as pubkeyfile:
                    pubkeyfile.write("".join([
                        f"{k[0]} {k[3]} saved-from-agent\n"
                        for k in keys_parsed
                    ]))

            return keys_parsed

        logmessage = []
        if success:
            logmessage.append(
                stylize("Remote authentication succeeded",
                        fg('green') + attr('bold')))
        else:
            logmessage.append(
                stylize("Remote authentication failed", fg('red')))

        if self.session.ssh_client is not None:
            logmessage.append(
                f"\tRemote Address: {self.session.ssh_client.host}:{self.session.ssh_client.port}"
            )
            logmessage.append(f"\tUsername: {self.session.username_provided}")

        if self.session.password_provided:
            display_password = None
            if not self.args.auth_hide_credentials:
                display_password = self.session.password_provided
            logmessage.append(
                f"\tPassword: {display_password or stylize('*******', fg('dark_gray'))}"
            )

        if self.session.accepted_key is not None and self.session.remote_key != self.session.accepted_key:
            ssh_pub_key = SSHKey(
                f"{self.session.accepted_key.get_name()} {self.session.accepted_key.get_base64()}"
            )
            ssh_pub_key.parse()
            logmessage.append(
                f"\tAccepted-Publickey: {self.session.accepted_key.get_name()} {ssh_pub_key.hash_sha256()} {ssh_pub_key.bits}bits"
            )

        if self.session.remote_key is not None:
            ssh_pub_key = SSHKey(
                f"{self.session.remote_key.get_name()} {self.session.remote_key.get_base64()}"
            )
            ssh_pub_key.parse()
            logmessage.append(
                f"\tRemote-Publickey: {self.session.remote_key.get_name()} {ssh_pub_key.hash_sha256()} {ssh_pub_key.bits}bits"
            )

        ssh_keys = None
        if self.session.agent:
            ssh_keys = get_agent_pubkeys()

        logmessage.append(
            f"\tAgent: {f'available keys: {len(ssh_keys or [])}' if ssh_keys else 'no agent'}"
        )
        if ssh_keys is not None:
            logmessage.append("\n".join([
                f"\t\tAgent-Key: {k[0]} {k[1].hash_sha256()} {k[1].bits}bits, can sign: {k[2]}"
                for k in ssh_keys
            ]))

        logging.info("\n".join(logmessage))