Exemplo n.º 1
0
def list_policies() -> None:

    # Get a list of all the files in the policies sub-directory, relative to the path of this script.
    installed_dir = os.path.dirname(os.path.abspath(__file__))
    policies_dir = os.path.join(installed_dir, 'policies')

    # If the path is not a directory, print a useful error and exit.
    if not os.path.isdir(policies_dir):
        print(
            "Error: could not find policies directory.  Please report this full output to <%s>:"
            % GITHUB_ISSUES_URL)
        print("\nsys.argv[0]: %s" % sys.argv[0])
        print("__file__: %s" % __file__)
        print("policies_dir: %s" % policies_dir)
        sys.exit(exitcodes.UNKNOWN_ERROR)

    # Get a list of all the files in the policies sub-directory.
    files = []
    for f in os.listdir(policies_dir):
        files.append(f)

    files.sort(
    )  # Now the files will be in order, like 'ubuntu_client_16_04.txt', 'ubuntu_client_18_04.txt', 'ubuntu_client_20_04.txt', ...

    server_policies_summary = []
    client_policies_summary = []
    for f in files:

        # Load each policy, and generate a short summary from its name and absolute file path.
        policy_file = os.path.join(policies_dir, f)
        policy = Policy(policy_file=policy_file)
        policy_summary = "Name:        %s\nPolicy path: %s" % (
            policy.get_name_and_version(), policy_file)

        # We will print the server policies separately from thee client policies...
        if policy.is_server_policy():
            server_policies_summary.append(policy_summary)
        else:
            client_policies_summary.append(policy_summary)

    if len(server_policies_summary) > 0:
        out.head('\nServer policies:\n')
        print("\n\n".join(server_policies_summary))
        print()

    if len(client_policies_summary) > 0:
        out.head('\nClient policies:\n')
        print("\n\n".join(client_policies_summary))
        print()

    if len(server_policies_summary) == 0 and len(client_policies_summary) == 0:
        print("Error: no built-in policies found in %s." % policies_dir)
    else:
        print(
            "\nHint: Use -P and provide the path to a policy to run a policy scan.\n"
        )
Exemplo n.º 2
0
def make_policy(aconf: AuditConf, banner: Optional['Banner'], kex: Optional['SSH2_Kex'], client_host: Optional[str]) -> None:

    # Set the source of this policy to the server host if this is a server audit, otherwise set it to the client address.
    source: Optional[str] = aconf.host
    if aconf.client_audit:
        source = client_host

    policy_data = Policy.create(source, banner, kex, aconf.client_audit)

    if aconf.policy_file is None:
        raise RuntimeError('Internal error: cannot write policy file since filename is None!')

    succeeded = False
    err = ''
    try:
        # Open with mode 'x' (creates the file, or fails if it already exist).
        with open(aconf.policy_file, 'x', encoding='utf-8') as f:
            f.write(policy_data)
        succeeded = True
    except FileExistsError:
        err = "Error: file already exists: %s" % aconf.policy_file
    except PermissionError as e:
        # If installed as a Snap package, print a more useful message with potential work-arounds.
        if SNAP_PACKAGE:
            print(SNAP_PERMISSIONS_ERROR)
            sys.exit(exitcodes.UNKNOWN_ERROR)
        else:
            err = "Error: insufficient permissions: %s" % str(e)

    if succeeded:
        print("Wrote policy to %s.  Customize as necessary, then run a policy scan with -P option." % aconf.policy_file)
    else:
        print(err)
Exemplo n.º 3
0
def make_policy(aconf: AuditConf, banner: Optional['Banner'],
                kex: Optional['SSH2_Kex'], client_host: Optional[str]) -> None:

    # Set the source of this policy to the server host if this is a server audit, otherwise set it to the client address.
    source = aconf.host  # type: Optional[str]
    if aconf.client_audit:
        source = client_host

    policy_data = Policy.create(source, banner, kex, aconf.client_audit)

    if aconf.policy_file is None:
        raise RuntimeError(
            'Internal error: cannot write policy file since filename is None!')

    # Open with mode 'x' (creates the file, or fails if it already exist).
    succeeded = True
    try:
        with open(aconf.policy_file, 'x') as f:
            f.write(policy_data)
    except FileExistsError:
        succeeded = False

    if succeeded:
        print(
            "Wrote policy to %s.  Customize as necessary, then run a policy scan with -P option."
            % aconf.policy_file)
    else:
        print("Error: file already exists: %s" % aconf.policy_file)
Exemplo n.º 4
0
    def test_builtin_policy_consistency(self):
        '''Ensure that the BUILTIN_POLICIES struct is consistent.'''

        for policy_name in Policy.BUILTIN_POLICIES:
            # Ensure that the policy name ends with " (version X)", where X is the 'version' field.
            version_str = " (version %s)" % Policy.BUILTIN_POLICIES[
                policy_name]['version']
            assert (policy_name.endswith(version_str))

            # Ensure that each built-in policy can be loaded with Policy.load_builtin_policy().
            assert (Policy.load_builtin_policy(policy_name) is not None)

        # Ensure that both server and client policy names are returned.
        server_policy_names, client_policy_names = Policy.list_builtin_policies(
        )
        assert (len(server_policy_names) > 0)
        assert (len(client_policy_names) > 0)
Exemplo n.º 5
0
def list_policies(out: OutputBuffer) -> None:
    '''Prints a list of server & client policies.'''

    server_policy_names, client_policy_names = Policy.list_builtin_policies()

    if len(server_policy_names) > 0:
        out.head('\nServer policies:\n')
        out.info("  * \"%s\"" % "\"\n  * \"".join(server_policy_names))

    if len(client_policy_names) > 0:
        out.head('\nClient policies:\n')
        out.info("  * \"%s\"" % "\"\n  * \"".join(client_policy_names))

    out.sep()
    if len(server_policy_names) == 0 and len(client_policy_names) == 0:
        out.fail("Error: no built-in policies found!")
    else:
        out.info("\nHint: Use -P and provide the full name of a policy to run a policy scan with.\n")
    out.write()
Exemplo n.º 6
0
def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[..., None]) -> 'AuditConf':  # pylint: disable=too-many-statements
    # pylint: disable=too-many-branches
    aconf = AuditConf()
    try:
        sopts = 'h1246M:p:P:jbcnvl:t:T:Lmd'
        lopts = ['help', 'ssh1', 'ssh2', 'ipv4', 'ipv6', 'make-policy=', 'port=', 'policy=', 'json', 'batch', 'client-audit', 'no-colors', 'verbose', 'level=', 'timeout=', 'targets=', 'list-policies', 'lookup=', 'threads=', 'manual', 'debug']
        opts, args = getopt.gnu_getopt(args, sopts, lopts)
    except getopt.GetoptError as err:
        usage_cb(str(err))
    aconf.ssh1, aconf.ssh2 = False, False
    host: str = ''
    oport: Optional[str] = None
    port: int = 0
    for o, a in opts:
        if o in ('-h', '--help'):
            usage_cb()
        elif o in ('-1', '--ssh1'):
            aconf.ssh1 = True
        elif o in ('-2', '--ssh2'):
            aconf.ssh2 = True
        elif o in ('-4', '--ipv4'):
            aconf.ipv4 = True
        elif o in ('-6', '--ipv6'):
            aconf.ipv6 = True
        elif o in ('-p', '--port'):
            oport = a
        elif o in ('-b', '--batch'):
            aconf.batch = True
            aconf.verbose = True
        elif o in ('-c', '--client-audit'):
            aconf.client_audit = True
        elif o in ('-n', '--no-colors'):
            aconf.colors = False
            out.use_colors = False
        elif o in ('-j', '--json'):
            if aconf.json:  # If specified twice, enable indent printing.
                aconf.json_print_indent = True
            else:
                aconf.json = True
        elif o in ('-v', '--verbose'):
            aconf.verbose = True
            out.verbose = True
        elif o in ('-l', '--level'):
            if a not in ('info', 'warn', 'fail'):
                usage_cb('level {} is not valid'.format(a))
            aconf.level = a
        elif o in ('-t', '--timeout'):
            aconf.timeout = float(a)
            aconf.timeout_set = True
        elif o in ('-M', '--make-policy'):
            aconf.make_policy = True
            aconf.policy_file = a
        elif o in ('-P', '--policy'):
            aconf.policy_file = a
        elif o in ('-T', '--targets'):
            aconf.target_file = a
        elif o == '--threads':
            aconf.threads = int(a)
        elif o in ('-L', '--list-policies'):
            aconf.list_policies = True
        elif o == '--lookup':
            aconf.lookup = a
        elif o in ('-m', '--manual'):
            aconf.manual = True
        elif o in ('-d', '--debug'):
            aconf.debug = True
            out.debug = True

    if len(args) == 0 and aconf.client_audit is False and aconf.target_file is None and aconf.list_policies is False and aconf.lookup == '' and aconf.manual is False:
        usage_cb()

    if aconf.manual:
        return aconf

    if aconf.lookup != '':
        return aconf

    if aconf.list_policies:
        list_policies(out)
        sys.exit(exitcodes.GOOD)

    if aconf.client_audit is False and aconf.target_file is None:
        if oport is not None:
            host = args[0]
        else:
            host, port = Utils.parse_host_and_port(args[0])
        if not host and aconf.target_file is None:
            usage_cb('host is empty')

    if port == 0 and oport is None:
        if aconf.client_audit:  # The default port to listen on during a client audit is 2222.
            port = 2222
        else:
            port = 22

    if oport is not None:
        port = Utils.parse_int(oport)
        if port <= 0 or port > 65535:
            usage_cb('port {} is not valid'.format(oport))

    aconf.host = host
    aconf.port = port
    if not (aconf.ssh1 or aconf.ssh2):
        aconf.ssh1, aconf.ssh2 = True, True

    # If a file containing a list of targets was given, read it.
    if aconf.target_file is not None:
        try:
            with open(aconf.target_file, 'r', encoding='utf-8') as f:
                aconf.target_list = f.readlines()
        except PermissionError as e:
            # If installed as a Snap package, print a more useful message with potential work-arounds.
            if SNAP_PACKAGE:
                print(SNAP_PERMISSIONS_ERROR)
            else:
                print("Error: insufficient permissions: %s" % str(e))
            sys.exit(exitcodes.UNKNOWN_ERROR)

        # Strip out whitespace from each line in target file, and skip empty lines.
        aconf.target_list = [target.strip() for target in aconf.target_list if target not in ("", "\n")]

    # If a policy file was provided, validate it.
    if (aconf.policy_file is not None) and (aconf.make_policy is False):

        # First, see if this is a built-in policy name.  If not, assume a file path was provided, and try to load it from disk.
        aconf.policy = Policy.load_builtin_policy(aconf.policy_file)
        if aconf.policy is None:
            try:
                aconf.policy = Policy(policy_file=aconf.policy_file)
            except Exception as e:
                out.fail("Error while loading policy file: %s: %s" % (str(e), traceback.format_exc()))
                out.write()
                sys.exit(exitcodes.UNKNOWN_ERROR)

        # If the user wants to do a client audit, but provided a server policy, terminate.
        if aconf.client_audit and aconf.policy.is_server_policy():
            out.fail("Error: client audit selected, but server policy provided.")
            out.write()
            sys.exit(exitcodes.UNKNOWN_ERROR)

        # If the user wants to do a server audit, but provided a client policy, terminate.
        if aconf.client_audit is False and aconf.policy.is_server_policy() is False:
            out.fail("Error: server audit selected, but client policy provided.")
            out.write()
            sys.exit(exitcodes.UNKNOWN_ERROR)

    return aconf
Exemplo n.º 7
0
def process_commandline(
    args: List[str], usage_cb: Callable[..., None]
) -> 'AuditConf':  # pylint: disable=too-many-statements
    # pylint: disable=too-many-branches
    aconf = AuditConf()
    try:
        sopts = 'h1246M:p:P:jbcnvl:t:T:L'
        lopts = [
            'help', 'ssh1', 'ssh2', 'ipv4', 'ipv6', 'make-policy=', 'port=',
            'policy=', 'json', 'batch', 'client-audit', 'no-colors', 'verbose',
            'level=', 'timeout=', 'targets=', 'list-policies', 'lookup='
        ]
        opts, args = getopt.gnu_getopt(args, sopts, lopts)
    except getopt.GetoptError as err:
        usage_cb(str(err))
    aconf.ssh1, aconf.ssh2 = False, False
    host = ''  # type: str
    oport = None  # type: Optional[str]
    port = 0  # type: int
    for o, a in opts:
        if o in ('-h', '--help'):
            usage_cb()
        elif o in ('-1', '--ssh1'):
            aconf.ssh1 = True
        elif o in ('-2', '--ssh2'):
            aconf.ssh2 = True
        elif o in ('-4', '--ipv4'):
            aconf.ipv4 = True
        elif o in ('-6', '--ipv6'):
            aconf.ipv6 = True
        elif o in ('-p', '--port'):
            oport = a
        elif o in ('-b', '--batch'):
            aconf.batch = True
            aconf.verbose = True
        elif o in ('-c', '--client-audit'):
            aconf.client_audit = True
        elif o in ('-n', '--no-colors'):
            aconf.colors = False
        elif o in ('-j', '--json'):
            aconf.json = True
        elif o in ('-v', '--verbose'):
            aconf.verbose = True
        elif o in ('-l', '--level'):
            if a not in ('info', 'warn', 'fail'):
                usage_cb('level {} is not valid'.format(a))
            aconf.level = a
        elif o in ('-t', '--timeout'):
            aconf.timeout = float(a)
            aconf.timeout_set = True
        elif o in ('-M', '--make-policy'):
            aconf.make_policy = True
            aconf.policy_file = a
        elif o in ('-P', '--policy'):
            aconf.policy_file = a
        elif o in ('-T', '--targets'):
            aconf.target_file = a
        elif o in ('-L', '--list-policies'):
            aconf.list_policies = True
        elif o == '--lookup':
            aconf.lookup = a

    if len(
            args
    ) == 0 and aconf.client_audit is False and aconf.target_file is None and aconf.list_policies is False and aconf.lookup == '':
        usage_cb()

    if aconf.lookup != '':
        return aconf

    if aconf.list_policies:
        list_policies()
        sys.exit(exitcodes.GOOD)

    if aconf.client_audit is False and aconf.target_file is None:
        if oport is not None:
            host = args[0]
        else:
            host, port = Utils.parse_host_and_port(args[0])
        if not host and aconf.target_file is None:
            usage_cb('host is empty')

    if port == 0 and oport is None:
        if aconf.client_audit:  # The default port to listen on during a client audit is 2222.
            port = 2222
        else:
            port = 22

    if oport is not None:
        port = Utils.parse_int(oport)
        if port <= 0 or port > 65535:
            usage_cb('port {} is not valid'.format(oport))

    aconf.host = host
    aconf.port = port
    if not (aconf.ssh1 or aconf.ssh2):
        aconf.ssh1, aconf.ssh2 = True, True

    # If a file containing a list of targets was given, read it.
    if aconf.target_file is not None:
        with open(aconf.target_file, 'r') as f:
            aconf.target_list = f.readlines()

        # Strip out whitespace from each line in target file, and skip empty lines.
        aconf.target_list = [
            target.strip() for target in aconf.target_list
            if target not in ("", "\n")
        ]

    # If a policy file was provided, validate it.
    if (aconf.policy_file is not None) and (aconf.make_policy is False):
        try:
            aconf.policy = Policy(policy_file=aconf.policy_file)
        except Exception as e:
            print("Error while loading policy file: %s: %s" %
                  (str(e), traceback.format_exc()))
            sys.exit(exitcodes.UNKNOWN_ERROR)

        # If the user wants to do a client audit, but provided a server policy, terminate.
        if aconf.client_audit and aconf.policy.is_server_policy():
            print("Error: client audit selected, but server policy provided.")
            sys.exit(exitcodes.UNKNOWN_ERROR)

        # If the user wants to do a server audit, but provided a client policy, terminate.
        if aconf.client_audit is False and aconf.policy.is_server_policy(
        ) is False:
            print("Error: server audit selected, but client policy provided.")
            sys.exit(exitcodes.UNKNOWN_ERROR)

    return aconf