Пример #1
0
def test_perms_and_ownership(file_reqs):

    results = GroupTestResult()

    if not file_reqs:
        return TestResult(Result.SKIP, 'Unable to load module config file')

    else:
        for req in file_reqs:

            # if the entry doesn't even contain a file to check, skip it
            if 'file' not in req:
                stats = None
                continue
            else:
                stats = utils.get_stats_on_file(req['file'])

            if stats:
                if 'disallowed_perms' in req:
                    check_name = "Checking perms for: " + req['file']

                    result = _does_perms_meet_req(stats,
                                                  req['disallowed_perms'])
                    if result.result == Result.SKIP:
                        logger.info("Got malformed permission requirement "
                                    "{}".format(req['disallowed_perms']))

                    results.add_result(check_name, result)

                if 'owner' in req or 'group' in req:
                    check_name = "Checking owner/group for: " + req['file']

                    owner_string = None
                    group_string = None

                    if 'owner' in req:
                        owner_string = req['owner']
                    if 'group' in req:
                        group_string = req['group']
                    result = _does_owner_group_meet_req(stats,
                                                        owners=owner_string,
                                                        groups=group_string)
                    results.add_result(check_name, result)

            else:
                check_name = "Checking controls for: " + req['file']
                results.add_result(check_name,
                                   TestResult(Result.SKIP,
                                              notes="Couldn't check file"))

    return results
Пример #2
0
def test_perms_and_ownership(file_reqs):

    results = GroupTestResult()

    if not file_reqs:
        return TestResult(Result.SKIP, 'Unable to load module config file')

    else:
        for req in file_reqs:

            # if the entry doesn't even contain a file to check, skip it
            if 'file' not in req:
                stats = None
                continue
            else:
                stats = utils.get_stats_on_file(req['file'])

            if stats:
                if 'disallowed_perms' in req:
                    check_name = "Checking perms for: " + req['file']

                    result = _does_perms_meet_req(stats,
                                                  req['disallowed_perms'])
                    if result.result == Result.SKIP:
                        logger.info("Got malformed permission requirement "
                                    "{}".format(req['disallowed_perms']))

                    results.add_result(check_name, result)

                if 'owner' in req or 'group' in req:
                    check_name = "Checking owner/group for: " + req['file']

                    owner_string = None
                    group_string = None

                    if 'owner' in req:
                        owner_string = req['owner']
                    if 'group' in req:
                        group_string = req['group']
                    result = _does_owner_group_meet_req(stats,
                                                        owners=owner_string,
                                                        groups=group_string)
                    results.add_result(check_name, result)

            else:
                check_name = "Checking controls for: " + req['file']
                results.add_result(
                    check_name,
                    TestResult(Result.SKIP, notes="Couldn't check file"))

    return results
Пример #3
0
def test_apparmor():
    """Uses return from apparmor_status to check installation and level
    at which AppArmor is monitoring.

    :returns: A TestResult object containing the result and notes
    explaining why it did not pass.
    """

    # initial configurations
    return_result = None
    logger.debug("Attempting to validate AppArmor is installed.")

    # check
    try:
        cmd = 'apparmor_status'
        p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
        stdout, stderr = p.communicate()

        if b'apparmor_status: command not found' in stderr:
            reason = "AppArmor is not installed."
            logger.debug(reason)
            return_result = TestResult(Result.FAIL, notes=reason)

        # enforcing check, no /'s = no directories
        elif b"//" not in stdout:
            reason = "AppArmor has no modules loaded."
            logger.info(reason)
            return_result = TestResult(Result.FAIL, notes=reason)

        elif b"//" in stdout:
            reason = "AppArmor is installed and policy is loaded."
            logger.info(reason)
            return_result = TestResult(Result.PASS)
        else:
            # wth?
            logger.debug(
                "Unexpected error while looking for AppArmor: "
                "    Standard Output from sestatus command: [%s]"
                "    Standard Error from sestatus command: [%s]", stdout,
                stderr)
            return_result = TestResult(Result.SKIP, notes="Unexpected error.")

    except EnvironmentError as e:
        logger.debug("Unexpected error running apparmor_status: [%s]", e)
        return_result = TestResult(Result.SKIP, notes="Unexpected error.")

    return return_result
Пример #4
0
def test_apparmor():
    """Uses return from apparmor_status to check installation and level
    at which AppArmor is monitoring.

    :returns: A TestResult object containing the result and notes
    explaining why it did not pass.
    """

    # initial configurations
    return_result = None
    logger.debug("Attempting to validate AppArmor is installed.")

    # check
    try:
        cmd = 'apparmor_status'
        p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
        stdout, stderr = p.communicate()

        if b'apparmor_status: command not found' in stderr:
            reason = "AppArmor is not installed."
            logger.debug(reason)
            return_result = TestResult(Result.FAIL, notes=reason)

        # enforcing check, no /'s = no directories
        elif b"//" not in stdout:
            reason = "AppArmor has no modules loaded."
            logger.info(reason)
            return_result = TestResult(Result.FAIL, notes=reason)

        elif b"//" in stdout:
            reason = "AppArmor is installed and policy is loaded."
            logger.info(reason)
            return_result = TestResult(Result.PASS)
        else:
            # wth?
            logger.debug("Unexpected error while looking for AppArmor: "
                         "    Standard Output from sestatus command: [%s]"
                         "    Standard Error from sestatus command: [%s]",
                         stdout, stderr)
            return_result = TestResult(Result.SKIP, notes="Unexpected error.")

    except EnvironmentError as e:
        logger.debug("Unexpected error running apparmor_status: [%s]", e)
        return_result = TestResult(Result.SKIP, notes="Unexpected error.")

    return return_result
Пример #5
0
def test_selinux():
    """Uses return from sestatus command to ensure SELinux is installed

    :returns: A TestResult object containing the result and, on failure,
    notes explaining why it did not pass.
    """

    # logger
    return_result = None
    logger.debug("Attempting to validate SELinux is installed.")

    # check
    try:
        # if sestatus_return is stdout:
        cmd = 'sestatus'
        p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
        stdout, stderr = p.communicate()

        if b'sestatus: not found' in stderr:
            reason = "SELinux is not installed."
            logger.info(reason)
            return_result = TestResult(Result.FAIL, notes=reason)

        elif b'disabled' in stdout:
            reason = "SELinux is disabled."
            logger.info(reason)
            return_result = TestResult(Result.FAIL, notes=reason)

        elif b'permissive' in stdout:
            reason = "SELinux is permissive (disabled but logging)."
            logger.info(reason)
            return_result = TestResult(Result.FAIL, notes=reason)

        elif b'enforcing' in stdout:
            reason = "SELinux is installed and enforcing."
            logger.info(reason)
            return_result = TestResult(Result.PASS)

        else:
            # wth?
            logger.debug(
                "Unexpected error while looking for SELinux: "
                "    Standard Output from sestatus command: [%s]"
                "    Standard Error from sestatus command: [%s]", stdout,
                stderr)
            return_result = TestResult(Result.SKIP, notes="Unexpected error.")

    except EnvironmentError as e:
        # log no selinux
        logger.debug("Unexpected error running sestatus: [{}]".format(e))
        return_result = TestResult(Result.SKIP, notes="Unexpected error.")

    return return_result
Пример #6
0
def test_sysctl_values(sysctl_reqs):
    results = GroupTestResult()

    if not sysctl_reqs:
        return TestResult(Result.SKIP, "Unable to load module config file")

    else:
        for requirement in sysctl_reqs:
            cur_result = None
            notes = ""
            # valid tests must have a key and allowed values
            if 'key' in requirement and 'allowed_values' in requirement:

                # name a test with specified name if it exists, otherwise just
                # use the key
                if 'name' in requirement:
                    test_name = "Sysctl check for " + requirement['name']
                else:
                    test_name = "Sysctl check for " + requirement['key']

                val_str = requirement['allowed_values'].replace(' ', '')
                allowed_values = val_str.split(',')

                try:
                    value = utils.get_sysctl_value(requirement['key'])
                except utils.ValNotFound:
                    cur_result = Result.SKIP
                    notes = "Could not find a value for sysctl key { "
                    notes += requirement['key'] + " }"
                else:
                    if value in allowed_values:
                        cur_result = Result.PASS
                    else:
                        cur_result = Result.FAIL
                        notes = "Key { " + requirement['key']
                        notes += " } expected one of { " + val_str
                        notes += " } but got " + value
                results.add_result(test_name,
                                   TestResult(cur_result, notes=notes))

            else:
                logger.info("Got malformed requirement %s", requirement)
    return results
Пример #7
0
def test_selinux():
    """Uses return from sestatus command to ensure SELinux is installed

    :returns: A TestResult object containing the result and, on failure,
    notes explaining why it did not pass.
    """

    # logger
    return_result = None
    logger.debug("Attempting to validate SELinux is installed.")

    # check
    try:
        # if sestatus_return is stdout:
        cmd = 'sestatus'
        p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
        stdout, stderr = p.communicate()

        if b'sestatus: not found' in stderr:
            reason = "SELinux is not installed."
            logger.info(reason)
            return_result = TestResult(Result.FAIL, notes=reason)

        elif b'disabled' in stdout:
            reason = "SELinux is disabled."
            logger.info(reason)
            return_result = TestResult(Result.FAIL, notes=reason)

        elif b'permissive' in stdout:
            reason = "SELinux is permissive (disabled but logging)."
            logger.info(reason)
            return_result = TestResult(Result.FAIL, notes=reason)

        elif b'enforcing' in stdout:
            reason = "SELinux is installed and enforcing."
            logger.info(reason)
            return_result = TestResult(Result.PASS)

        else:
            # wth?
            logger.debug("Unexpected error while looking for SELinux: "
                         "    Standard Output from sestatus command: [%s]"
                         "    Standard Error from sestatus command: [%s]",
                         stdout, stderr)
            return_result = TestResult(Result.SKIP, notes="Unexpected error.")

    except EnvironmentError as e:
        # log no selinux
        logger.debug("Unexpected error running sestatus: [{}]".format(e))
        return_result = TestResult(Result.SKIP, notes="Unexpected error.")

    return return_result
Пример #8
0
def test_shellshock(config):
    logger.debug("Testing shell for 'shellshock/bashbug' vulnerability.")

    try:
        cmd = config['exploit_command']
    except KeyError:
        logger.error("Can't find exploit command for shellshock test")
    else:

        p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
        stdout, stderr = p.communicate()

        if b'vulnerable' in stdout:
            reason = "System is vulnerable to Shellshock/Bashbug."
            logger.info(reason)
            result = Result.FAIL
        else:
            reason = "System is not vulnerable to Shellshock/Bashbug."
            logger.info(reason)
            result = Result.PASS
        return TestResult(result, reason)
Пример #9
0
def test_shellshock(config):
    logger.debug("Testing shell for 'shellshock/bashbug' vulnerability.")

    try:
        cmd = config['exploit_command']
    except KeyError:
        logger.error("Can't find exploit command for shellshock test")
    else:

        p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
        stdout, stderr = p.communicate()

        if b'vulnerable' in stdout:
            reason = "System is vulnerable to Shellshock/Bashbug."
            logger.info(reason)
            result = Result.FAIL
        else:
            reason = "System is not vulnerable to Shellshock/Bashbug."
            logger.info(reason)
            result = Result.PASS
        return TestResult(result, reason)
Пример #10
0
def test_accounts_nopassword():
    try:
        import spwd
    except ImportError:
        logger.info("Import of spwd failed ")
        return TestResult(Result.SKIP, "Unable to import 'spwd' module")

    disabled = []
    locked = []
    passworded = []
    no_password = []

    shadow_entries = spwd.getspall()

    for entry in shadow_entries:
        # passwords which start with ! have been locked
        if entry.sp_pwd.startswith('!'):
            locked.append(entry.sp_nam)
        # passwords which start with * have been disabled
        elif entry.sp_pwd.startswith('*'):
            disabled.append(entry.sp_nam)
        # blank passwords are bad!
        elif entry.sp_pwd == "":
            no_password.append(entry.sp_nam)
        # otherwise the account has a password
        else:
            passworded.append(entry.sp_nam)

    if len(no_password) > 0:
        notes = "Account(s) { " + str(no_password) + " } have no password!"
        test_result = Result.FAIL
    else:
        notes = ("Disabled: " + str(len(disabled)) + ", Locked: " +
                 str(len(locked)) + ", Password: "******", No Password: " + str(len(no_password)))
        test_result = Result.PASS

    return TestResult(test_result, notes)
Пример #11
0
def test_accounts_nopassword():
    try:
        import spwd
    except ImportError:
        logger.info("Import of spwd failed ")
        return TestResult(Result.SKIP, "Unable to import 'spwd' module")

    disabled = []
    locked = []
    passworded = []
    no_password = []

    shadow_entries = spwd.getspall()

    for entry in shadow_entries:
        # passwords which start with ! have been locked
        if entry.sp_pwd.startswith('!'):
            locked.append(entry.sp_nam)
        # passwords which start with * have been disabled
        elif entry.sp_pwd.startswith('*'):
            disabled.append(entry.sp_nam)
        # blank passwords are bad!
        elif entry.sp_pwd == "":
            no_password.append(entry.sp_nam)
        # otherwise the account has a password
        else:
            passworded.append(entry.sp_nam)

    if len(no_password) > 0:
        notes = "Account(s) { " + str(no_password) + " } have no password!"
        test_result = Result.FAIL
    else:
        notes = ("Disabled: " + str(len(disabled)) + ", Locked: " +
                 str(len(locked)) + ", Password: "******", No Password: " + str(len(no_password)))
        test_result = Result.PASS

    return TestResult(test_result, notes)
Пример #12
0
def test_secure_communication():
    # TODO: check if there is a 'well known' HDP container that either
    # acts as an intermediate CA (for --tlscacert option), or a server
    # that clients connect to securely (for --tlscert and tlskey), and
    # if so, break them into separate tests for better profile coverage

    logger.debug("Testing for insecure registries.")
    reason = "No Docker containers found."

    docker_ps = _get_docker_processes()
    if docker_ps is None:
        return TestResult(Result.SKIP, "Docker is not running.")

    for entry in docker_ps:
        if '--tlsverify' in entry:
            if '--tlscert' in entry:
                if '--tlskey' in entry:
                    if '--tlscacert' in entry:
                        reason = ("Container set to validate certificates, "
                                  "has both certificate and key in place, "
                                  "and can act as an intermediate CA.")
                        logger.info(reason)
                    else:
                        reason = ("No CA certificate, container cannot act "
                                  "as intermediate CA.")
                        logger.info(reason)
                else:
                    reason = ("A public Certificate exists, but key does not."
                              " Communciation unable to be decrypted.")
                    logger.info(reason)

            else:
                reason = ("No certificate available, container will only be"
                          " able to act as client and accept server cert.")

        else:
            reason = "Docker is not configured to validate certificates."
            result = TestResult(Result.FAIL, reason)
            return result

    result = TestResult(Result.PASS)

    return result
Пример #13
0
def test_secure_communication():
    # TODO: check if there is a 'well known' HDP container that either
    # acts as an intermediate CA (for --tlscacert option), or a server
    # that clients connect to securely (for --tlscert and tlskey), and
    # if so, break them into separate tests for better profile coverage

    logger.debug("Testing for insecure registries.")
    reason = "No Docker containers found."

    docker_ps = _get_docker_processes()
    if docker_ps is None:
        return TestResult(Result.SKIP, "Docker is not running.")

    for entry in docker_ps:
        if '--tlsverify' in entry:
            if '--tlscert' in entry:
                if '--tlskey' in entry:
                    if '--tlscacert' in entry:
                        reason = ("Container set to validate certificates, "
                                  "has both certificate and key in place, "
                                  "and can act as an intermediate CA.")
                        logger.info(reason)
                    else:
                        reason = ("No CA certificate, container cannot act "
                                  "as intermediate CA.")
                        logger.info(reason)
                else:
                    reason = ("A public Certificate exists, but key does not."
                              " Communciation unable to be decrypted.")
                    logger.info(reason)

            else:
                reason = ("No certificate available, container will only be"
                          " able to act as client and accept server cert.")

        else:
            reason = "Docker is not configured to validate certificates."
            result = TestResult(Result.FAIL, reason)
            return result

    result = TestResult(Result.PASS)

    return result