OpenSCAP Evaluation Report

## About profile

CIS Red Hat Enterprise Linux 9 Benchmark for Level 1 - Workstation
This profile defines a baseline that aligns to the "Level 1 - Workstation" configuration from the Center for Internet Security® Red Hat Enterprise Linux 9 Benchmark™, v1.0.0, released 2022-11-28. This profile includes Center for Internet Security® Red Hat Enterprise Linux 9 CIS Benchmarks™ content.

## Compliance and Scoring

Danger alert: The target system did not satisfy the conditions of 3 rules!
Furthermore, the results of 99 rules were inconclusive.

Please review rule results and consider applying remediation.

## Rule results

119 Pass
3 Fail
99 Other

## Severity of failed rules

1 Low
2 Medium

## Score

74.99 of 100.00

###

- Profile ID:
  xccdf_org.ssgproject.content_profile_cis_workstation_l1
- This profile is applicable for this CPE platforms:
  cpe:/o:redhat:enterprise_linux:9
- CPE platforms that were found applicable on the evaluated machine:
  cpe:/o:redhat:enterprise_linux:9
- Evaluation target:
  rhel90-2
- Performed by:
  jrodak
- Scanner:
  OpenSCAP1.3.6
- Benchmark ID:
  xccdf_org.ssgproject.content_benchmark_RHEL-9
- Benchmark url:
  #scap_org.open-scap_comp_ssg-rhel9-xccdf.xml
- Benchmark version:
  0.1.66
- Started at:
  2023-03-16T15:33:34+01:00
- Finished at:
  2023-03-16T15:33:34+01:00
- Test system:
  cpe:/a:redhat:openscap:1.3.6

## Rule Overview

### Advanced search options

Search by result:
Pass Fail Not checked Not applicable Fixed Error Fix failed Fix unsuccessful Informational Unknown
Search by severity:
high Medium Low Unknown

| Rule | Severity | Result
--- | --- | --- | ---
| Set Account Expiration Following Inactivity | medium | fix failed
Rule ID: | xccdf_org.ssgproject.content_rule_account_disable_post_pw_expiration
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:16+01:00
Weight: | 1.0
Severity:
| medium
Identifiers: | CCE-83627-0
References: | 1, 12, 13, 14, 15, 16, 18, 3, 5, 7, 8, 5.6.2.1.1, DSS01.03, DSS03.05, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 3.5.6, CCI-000017, CCI-000795, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 6.2, A.12.4.1, A.12.4.3, A.18.1.4, A.6.1.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, CIP-004-6 R2.2.2, CIP-004-6 R2.2.3, CIP-007-3 R.1.3, CIP-007-3 R5, CIP-007-3 R5.1.1, CIP-007-3 R5.1.3, CIP-007-3 R5.2.1, CIP-007-3 R5.2.3, IA-4(e), AC-2(3), CM-6(a), DE.CM-1, DE.CM-3, PR.AC-1, PR.AC-4, PR.AC-6, PR.AC-7, Req-8.1.4, SRG-OS-000118-GPOS-00060, SRG-OS-000003-VMM-000030, SRG-OS-000118-VMM-000590, 5.6.1.4
Description: | To specify the number of days after a password expires (which signifies inactivity) until an account is permanently disabled, add or correct the following line in `/etc/default/useradd`:
    INACTIVE=30
If a password is currently on the verge of expiration, then `30` day(s) remain(s) until the account is automatically disabled. However, if the password will not expire for another 60 days, then 60 days plus `30` day(s) could elapse until the account would be automatically disabled. See the `useradd` man page for more information.
Rationale: | Inactive identifiers pose a risk to systems and applications because attackers may exploit an inactive identifier and potentially obtain undetected access to the system. Disabling inactive accounts ensures that accounts which may not have been responsibly removed are not available to attackers who may have compromised their credentials. Owners of inactive accounts will not notice if unauthorized access to their user account has been obtained.
Messages: | Message: Message:
    Fix execution completed and returned: 4
Message: Message:
    sed: couldn't open temporary file /etc/default/sedWABpOp: Permission denied
Message: Message:
    Failed to verify applied fix: Checking engine returns: fail
Message: Message:
    The OVAL graph of the rule as it was displayed before the fix was performed.
Remediation Shell script
    # Remediation is applicable only in certain platforms
    if rpm --quiet -q shadow-utils; then

    var_account_disable_post_pw_expiration='30'

    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/default/useradd"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^INACTIVE")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s=%s" "$stripped_key" "$var_account_disable_post_pw_expiration"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^INACTIVE\\>" "/etc/default/useradd"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^INACTIVE\\>.*/$escaped_formatted_output/gi" "/etc/default/useradd"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-83627-0"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/default/useradd" >> "/etc/default/useradd"
        printf '%s\n' "$formatted_output" >> "/etc/default/useradd"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi
Remediation Ansible snippet
Complexity: | low
Disruption: | low
Strategy: | restrict
    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-83627-0
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.6
      - NIST-800-53-AC-2(3)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-4(e)
      - PCI-DSS-Req-8.1.4
      - account_disable_post_pw_expiration
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
    - name: XCCDF Value var_account_disable_post_pw_expiration # promote to variable
      set_fact:
        var_account_disable_post_pw_expiration: !!str 30
      tags:
        - always

    - name: Set Account Expiration Following Inactivity
      lineinfile:
        create: true
        dest: /etc/default/useradd
        regexp: ^INACTIVE
        line: INACTIVE={{ var_account_disable_post_pw_expiration }}
      when: '"shadow-utils" in ansible_facts.packages'
      tags:
      - CCE-83627-0
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.6
      - NIST-800-53-AC-2(3)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-4(e)
      - PCI-DSS-Req-8.1.4
      - account_disable_post_pw_expiration
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
OVAL definition:
Definition ID: | oval:ssg-account_disable_post_pw_expiration:def:1
Class: | compliance
Title: | Set Account Expiration Following Inactivity
Version: | 2
Description: | The accounts should be configured to expire automatically following password expiration.
Result explained: | Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.
OVAL graph of OVAL definition: oval:ssg-account_disable_post_pw_expiration:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#login_defs

Ensure All Accounts on the System Have Unique User IDs medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_account_unique_id
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-88493-2

References:

CCI-000135, CCI-000764, CCI-000804, SRG-OS-000104-GPOS-00051, SRG-OS-000121-GPOS-00062, SRG-OS-000042-GPOS-00020, 6.2.4
Description:
Change user IDs (UIDs), or delete accounts, so each has a unique name.
Rationale:

To assure accountability and prevent unauthenticated access, interactive users must be identified and authenticated to prevent potential misuse and compromise of the system.

Warnings:

General warning
Automatic remediation of this control is not available due to unique requirements of each system.
OVAL definition:

Definition ID:

oval:ssg-account_unique_id:def:1

Class:

compliance

Title:

Ensure All Accounts on the System Have Unique User IDs

Version:

1

Description:

All accounts on the system should have unique IDs for proper accountability.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-account_unique_id:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Ensure All Accounts on the System Have Unique Names medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_account_unique_name
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83628-8

References:

5.5.2, CCI-000770, CCI-000804, Req-8.1.1, 6.2.6
Description:
Ensure accounts on the system have unique names. To ensure all accounts have unique names, run the following command:

    $ sudo getent passwd | awk -F: '{ print $1}' | uniq -d

If a username is returned, change or delete the username.
Rationale:

Unique usernames allow for accountability on the system.

OVAL definition:

Definition ID:

oval:ssg-account_unique_name:def:1

Class:

compliance

Title:

Ensure All Accounts on the System Have Unique Names

Version:

1

Description:

All accounts on the system should have unique names for proper accountability.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-account_unique_name:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Set Password Maximum Age medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_maximum_age_login_defs
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:16+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83606-4

References:

BP28(R18), 1, 12, 15, 16, 5, 5.6.2.1, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 3.5.6, CCI-000199, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.2, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, 0418, 1055, 1402, A.18.1.4, A.7.1.1, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.2, A.9.4.3, IA-5(f), IA-5(1)(d), CM-6(a), PR.AC-1, PR.AC-6, PR.AC-7, Req-8.2.4, SRG-OS-000076-GPOS-00044, 5.6.1.1
Description:
To specify password maximum age for new accounts, edit the file `/etc/login.defs` and add or correct the following line:

    PASS_MAX_DAYS 365

A value of 180 days is sufficient for many environments. The DoD requirement is 60. The profile requirement is `365`.
Rationale:

Any password, no matter how complex, can eventually be cracked. Therefore, passwords need to be changed periodically. If the operating system does not limit the lifetime of passwords and force users to change their passwords, there is the risk that the operating system passwords could be compromised.
Setting the password maximum age ensures users are required to periodically change their passwords. Requiring shorter password lifetimes increases the risk of users writing down the password in a convenient location subject to physical compromise.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    sed: couldn't open temporary file /etc/sedwJF8mA: Permission denied
    /tmp/oscap.BpbDle/fix-XXk6nE2c: line 10: /etc/login.defs: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q shadow-utils; then

    var_accounts_maximum_age_login_defs='365'

    grep -q ^PASS_MAX_DAYS /etc/login.defs && \
      sed -i "s/PASS_MAX_DAYS.*/PASS_MAX_DAYS     $var_accounts_maximum_age_login_defs/g" /etc/login.defs
    if ! [ $? -eq 0 ]; then
        echo "PASS_MAX_DAYS      $var_accounts_maximum_age_login_defs" >> /etc/login.defs
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-83606-4
      - CJIS-5.6.2.1
      - NIST-800-171-3.5.6
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(1)(d)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.2.4
      - accounts_maximum_age_login_defs
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
    - name: XCCDF Value var_accounts_maximum_age_login_defs # promote to variable
      set_fact:
        var_accounts_maximum_age_login_defs: !!str 365
      tags:
        - always

    - name: Set Password Maximum Age
      lineinfile:
        create: true
        dest: /etc/login.defs
        regexp: ^#?PASS_MAX_DAYS
        line: PASS_MAX_DAYS {{ var_accounts_maximum_age_login_defs }}
      when: '"shadow-utils" in ansible_facts.packages'
      tags:
      - CCE-83606-4
      - CJIS-5.6.2.1
      - NIST-800-171-3.5.6
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(1)(d)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.2.4
      - accounts_maximum_age_login_defs
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-accounts_maximum_age_login_defs:def:1

Class:

compliance

Title:

Set Password Maximum Age

Version:

3

Description:

The maximum password age policy should meet minimum requirements.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_maximum_age_login_defs:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#login_defs
Set Password Minimum Age medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_minimum_age_login_defs
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:16+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83610-6

References:

1, 12, 15, 16, 5, 5.6.2.1.1, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 3.5.8, CCI-000198, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.2, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, 0418, 1055, 1402, A.18.1.4, A.7.1.1, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.2, A.9.4.3, IA-5(f), IA-5(1)(d), CM-6(a), PR.AC-1, PR.AC-6, PR.AC-7, Req-8.3.9, SRG-OS-000075-GPOS-00043, 5.6.1.2
Description:
To specify password minimum age for new accounts, edit the file `/etc/login.defs` and add or correct the following line:

    PASS_MIN_DAYS 1

A value of 1 day is considered sufficient for many environments. The DoD requirement is 1. The profile requirement is `1`.
Rationale:

Enforcing a minimum password lifetime helps to prevent repeated password changes to defeat the password reuse or history enforcement requirement. If users are allowed to immediately and continually change their password, then the password could be repeatedly changed in a short period of time to defeat the organization's policy regarding password reuse.
Setting the minimum password age protects against users cycling back to a favorite password after satisfying the password reuse requirement.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    sed: couldn't open temporary file /etc/sedd5XB9E: Permission denied
    /tmp/oscap.nfL7Ez/fix-XXRLluhN: line 10: /etc/login.defs: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q shadow-utils; then

    var_accounts_minimum_age_login_defs='1'

    grep -q ^PASS_MIN_DAYS /etc/login.defs && \
      sed -i "s/PASS_MIN_DAYS.*/PASS_MIN_DAYS     $var_accounts_minimum_age_login_defs/g" /etc/login.defs
    if ! [ $? -eq 0 ]; then
        echo "PASS_MIN_DAYS      $var_accounts_minimum_age_login_defs" >> /etc/login.defs
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-83610-6
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.8
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(1)(d)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.3.9
      - accounts_minimum_age_login_defs
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
    - name: XCCDF Value var_accounts_minimum_age_login_defs # promote to variable
      set_fact:
        var_accounts_minimum_age_login_defs: !!str 1
      tags:
        - always

    - name: Set Password Minimum Age
      lineinfile:
        create: true
        dest: /etc/login.defs
        regexp: ^#?PASS_MIN_DAYS
        line: PASS_MIN_DAYS {{ var_accounts_minimum_age_login_defs }}
      when: '"shadow-utils" in ansible_facts.packages'
      tags:
      - CCE-83610-6
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.8
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(1)(d)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.3.9
      - accounts_minimum_age_login_defs
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-accounts_minimum_age_login_defs:def:1

Class:

compliance

Title:

Set Password Minimum Age

Version:

3

Description:

The minimum password age policy should be set appropriately.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_minimum_age_login_defs:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#login_defs
Verify Only Root Has UID 0 high pass

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_no_uid_except_zero
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

high

Identifiers:

CCE-83624-7

References:

1, 12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.02, DSS06.03, DSS06.10, 3.1.1, 3.1.5, CCI-000366, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.18.1.4, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.2.3, CIP-004-6 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.2, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, IA-2, AC-6(5), IA-4(b), PR.AC-1, PR.AC-4, PR.AC-6, PR.AC-7, PR.DS-5, Req-8.2.1, SRG-OS-000480-GPOS-00227, 6.2.9
Description:
If any account other than root has a UID of 0, this misconfiguration should be investigated and the accounts other than root should be removed or have their UID changed.
If the account is associated with system commands or applications the UID should be changed to one greater than "0" but less than "1000." Otherwise assign a UID greater than "1000" that has not already been assigned.
Rationale:

An account has root authority if it has a UID of 0. Multiple accounts with a UID of 0 afford more opportunity for potential intruders to guess a password for a privileged account. Proper configuration of sudo is recommended to afford multiple system administrators access to root privileges in an accountable manner.

Remediation Shell script

    awk -F: '$3 == 0 && $1 != "root" { print $1 }' /etc/passwd | xargs --no-run-if-empty --max-lines=1 passwd -l

OVAL definition:

Definition ID:

oval:ssg-accounts_no_uid_except_zero:def:1

Class:

compliance

Title:

Verify Only Root Has UID 0

Version:

1

Description:

Only the root account should be assigned a user id of 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_no_uid_except_zero:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify All Account Password Hashes are Shadowed medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_password_all_shadowed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83618-9

References:

1, 12, 15, 16, 5, 5.5.2, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 3.5.10, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.2, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, 1410, A.18.1.4, A.7.1.1, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.2, A.9.4.3, IA-5(h), CM-6(a), PR.AC-1, PR.AC-6, PR.AC-7, Req-8.2.1, 6.2.1
Description:
If any password hashes are stored in `/etc/passwd` (in the second field, instead of an `x` or `*`), the cause of this misconfiguration should be investigated. The account should have its password reset and the hash should be properly stored, or the account should be deleted entirely.
Rationale:

The hashes for all user account passwords should be stored in the file `/etc/shadow` and never in `/etc/passwd`, which is readable by all users.

OVAL definition:

Definition ID:

oval:ssg-accounts_password_all_shadowed:def:1

Class:

compliance

Title:

Verify All Account Password Hashes are Shadowed

Version:

1

Description:

All password hashes should be shadowed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_password_all_shadowed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Ensure PAM Enforces Password Requirements - Minimum Different Categories medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_password_pam_minclass
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83563-7

References:

1, 12, 15, 16, 5, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, CCI-000195, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.2, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, A.18.1.4, A.7.1.1, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.2, A.9.4.3, IA-5(c), IA-5(1)(a), CM-6(a), IA-5(4), PR.AC-1, PR.AC-6, PR.AC-7, SRG-OS-000072-GPOS-00040, 5.5.1
Description:
The pam_pwquality module's `minclass` parameter controls requirements for usage of different character classes, or types, of character that must exist in a password before it is considered valid. For example, setting this value to three (3) requires that any password must have characters from at least three different categories in order to be approved. The default value is zero (0), meaning there are no required classes. There are four categories available:

    * Upper-case characters
    * Lower-case characters
    * Digits
    * Special characters (for example, punctuation)

Modify the `minclass` setting in `/etc/security/pwquality.conf` entry to require 4 differing categories of characters when changing passwords.
Rationale:

Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks.
Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before the password is compromised.
Requiring a minimum number of character categories makes password guessing attacks more difficult by ensuring a larger search space.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    /tmp/oscap.BQXLSM/fix-XXowZS6y: line 34: /etc/security/pwquality.conf: Permission denied
    /tmp/oscap.BQXLSM/fix-XXowZS6y: line 35: /etc/security/pwquality.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q pam; then

    var_password_pam_minclass='4'

    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/security/pwquality.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^minclass")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$var_password_pam_minclass"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^minclass\\>" "/etc/security/pwquality.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^minclass\\>.*/$escaped_formatted_output/gi" "/etc/security/pwquality.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-83563-7"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/security/pwquality.conf" >> "/etc/security/pwquality.conf"
        printf '%s\n' "$formatted_output" >> "/etc/security/pwquality.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-83563-7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(1)(a)
      - NIST-800-53-IA-5(4)
      - NIST-800-53-IA-5(c)
      - accounts_password_pam_minclass
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
    - name: XCCDF Value var_password_pam_minclass # promote to variable
      set_fact:
        var_password_pam_minclass: !!str 4
      tags:
        - always

    - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories -
        Ensure PAM variable minclass is set accordingly
      ansible.builtin.lineinfile:
        create: true
        dest: /etc/security/pwquality.conf
        regexp: ^#?\s*minclass
        line: minclass = {{ var_password_pam_minclass }}
      when: '"pam" in ansible_facts.packages'
      tags:
      - CCE-83563-7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(1)(a)
      - NIST-800-53-IA-5(4)
      - NIST-800-53-IA-5(c)
      - accounts_password_pam_minclass
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-accounts_password_pam_minclass:def:1

Class:

compliance

Title:

Ensure PAM Enforces Password Requirements - Minimum Different Categories

Version:

3

Description:

The password minclass should meet minimum requirements

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_password_pam_minclass:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#package_pam
Ensure PAM Enforces Password Requirements - Minimum Length medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_password_pam_minlen
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83579-3

References:

BP28(R18), 1, 12, 15, 16, 5, 5.6.2.1.1, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, CCI-000205, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.2, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, A.18.1.4, A.7.1.1, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.2, A.9.4.3, IA-5(c), IA-5(1)(a), CM-6(a), IA-5(4), PR.AC-1, PR.AC-6, PR.AC-7, FMT_SMF_EXT.1, Req-8.2.3, SRG-OS-000078-GPOS-00046, SRG-OS-000072-VMM-000390, SRG-OS-000078-VMM-000450, 5.5.1
Description:
The pam_pwquality module's `minlen` parameter controls requirements for minimum characters required in a password. Add `minlen=14` after pam_pwquality to set minimum password length requirements.
Rationale:

The shorter the password, the lower the number of possible combinations that need to be tested before the password is compromised.
Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. Password length is one factor of several that helps to determine strength and how long it takes to crack a password. Use of more characters in a password helps to exponentially increase the time and/or resources required to compromise the password.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    /tmp/oscap.PxBqfL/fix-XXncLp1l: line 34: /etc/security/pwquality.conf: Permission denied
    /tmp/oscap.PxBqfL/fix-XXncLp1l: line 35: /etc/security/pwquality.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q pam; then

    var_password_pam_minlen='14'

    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/security/pwquality.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^minlen")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$var_password_pam_minlen"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^minlen\\>" "/etc/security/pwquality.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^minlen\\>.*/$escaped_formatted_output/gi" "/etc/security/pwquality.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-83579-3"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/security/pwquality.conf" >> "/etc/security/pwquality.conf"
        printf '%s\n' "$formatted_output" >> "/etc/security/pwquality.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-83579-3
      - CJIS-5.6.2.1.1
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(1)(a)
      - NIST-800-53-IA-5(4)
      - NIST-800-53-IA-5(c)
      - PCI-DSS-Req-8.2.3
      - accounts_password_pam_minlen
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
    - name: XCCDF Value var_password_pam_minlen # promote to variable
      set_fact:
        var_password_pam_minlen: !!str 14
      tags:
        - always

    - name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure PAM variable
        minlen is set accordingly
      ansible.builtin.lineinfile:
        create: true
        dest: /etc/security/pwquality.conf
        regexp: ^#?\s*minlen
        line: minlen = {{ var_password_pam_minlen }}
      when: '"pam" in ansible_facts.packages'
      tags:
      - CCE-83579-3
      - CJIS-5.6.2.1.1
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(1)(a)
      - NIST-800-53-IA-5(4)
      - NIST-800-53-IA-5(c)
      - PCI-DSS-Req-8.2.3
      - accounts_password_pam_minlen
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-accounts_password_pam_minlen:def:1

Class:

compliance

Title:

Ensure PAM Enforces Password Requirements - Minimum Length

Version:

3

Description:

The password minlen should meet minimum requirements

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_password_pam_minlen:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#package_pam
Limit Password Reuse: password-auth medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_password_auth
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86354-8

References:

BP28(R18), 1, 12, 15, 16, 5, 5.6.2.1.1, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 3.5.8, CCI-000200, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.2, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, A.18.1.4, A.7.1.1, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.2, A.9.4.3, IA-5(f), IA-5(1)(e), PR.AC-1, PR.AC-6, PR.AC-7, Req-8.2.5, SRG-OS-000077-GPOS-00045, SRG-OS-000077-VMM-000440, 5.5.3
Description:
Do not allow users to reuse recent passwords. This can be accomplished by using the `remember` option for the `pam_pwhistory` PAM module.
On systems with newer versions of `authselect`, the `pam_pwhistory` PAM module can be enabled via authselect feature:

    authselect enable-feature with-pwhistory

Otherwise, it should be enabled using an authselect custom profile.
Newer systems also have the `/etc/security/pwhistory.conf` file for setting `pam_pwhistory` module options. This file should be used whenever available. Otherwise, the `pam_pwhistory` module options can be set in PAM files.
The value for `remember` option must be equal or greater than 5
Rationale:

Preventing re-use of previous passwords helps ensure that a compromised password is not re-used by a user.

Warnings:

General warning
If the system relies on `authselect` tool to manage PAM settings, the remediation will also use `authselect` tool. However, if any manual modification was made in PAM files, the `authselect` integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will be shown in the remediation report.

General warning
Newer versions of `authselect` contain an authselect feature to easily and properly enable `pam_pwhistory.so` module. If this feature is not yet available in your system, an authselect custom profile must be used to avoid integrity issues in PAM files. If a custom profile was created and used in the system before this authselect feature was available, the new feature can't be used with this custom profile and the remediation will fail. In this case, the custom profile should be recreated or manually updated.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    System was not configured with authselect.

            authselect integrity check failed. Remediation aborted!
            This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
            It is not recommended to manually edit the PAM files when authselect tool is available.
            In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended.

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q pam; then

    var_password_pam_remember='5'
    var_password_pam_remember_control_flag='requisite,required'

    var_password_pam_remember_control_flag="$(echo $var_password_pam_remember_control_flag | cut -d \, -f 1)"

    if [ -f /usr/bin/authselect ]; then
        if authselect list-features minimal | grep -q with-pwhistory; then
            if ! authselect check; then
            echo "
            authselect integrity check failed. Remediation aborted!
            This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
            It is not recommended to manually edit the PAM files when authselect tool is available.
            In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
            exit 1
            fi
            authselect enable-feature with-pwhistory

            authselect apply-changes -b
        else

            if ! authselect check; then
            echo "
            authselect integrity check failed. Remediation aborted!
            This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
            It is not recommended to manually edit the PAM files when authselect tool is available.
            In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
            exit 1
            fi

            CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
            # If not already in use, a custom profile is created preserving the enabled features.
            if [[ ! $CURRENT_PROFILE == custom/* ]]; then
                ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
                authselect create-profile hardening -b $CURRENT_PROFILE
                CURRENT_PROFILE="custom/hardening"

                authselect apply-changes -b --backup=before-hardening-custom-profile
                authselect select $CURRENT_PROFILE
                for feature in $ENABLED_FEATURES; do
                    authselect enable-feature $feature;
                done

                authselect apply-changes -b --backup=after-hardening-custom-profile
            fi
            PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth")
            PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"

            authselect apply-changes -b
            if ! grep -qP '^\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so\s*.*' "$PAM_FILE_PATH"; then
                # Line matching group + control + module was not found. Check group + module.
                if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then
                    # The control is updated only if one single line matches.
                    sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"$var_password_pam_remember_control_flag"' \2/' "$PAM_FILE_PATH"
                else
                    LAST_MATCH_LINE=$(grep -nP "^password.*requisite.*pam_pwquality\.so" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1)
                    if [ ! -z $LAST_MATCH_LINE ]; then
                        sed -i --follow-symlinks $LAST_MATCH_LINE' a password     '"$var_password_pam_remember_control_flag"'    pam_pwhistory.so' "$PAM_FILE_PATH"
                    else
                        echo 'password    '"$var_password_pam_remember_control_flag"'    pam_pwhistory.so' >> "$PAM_FILE_PATH"
                    fi
                fi
            fi
        fi
    else
        if ! grep -qP '^\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so\s*.*' "/etc/pam.d/password-auth"; then
            # Line matching group + control + module was not found. Check group + module.
            if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "/etc/pam.d/password-auth")" -eq 1 ]; then
                # The control is updated only if one single line matches.
                sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"$var_password_pam_remember_control_flag"' \2/' "/etc/pam.d/password-auth"
            else
                LAST_MATCH_LINE=$(grep -nP "^password.*requisite.*pam_pwquality\.so" "/etc/pam.d/password-auth" | tail -n 1 | cut -d: -f 1)
                if [ ! -z $LAST_MATCH_LINE ]; then
                    sed -i --follow-symlinks $LAST_MATCH_LINE' a password     '"$var_password_pam_remember_control_flag"'    pam_pwhistory.so' "/etc/pam.d/password-auth"
                else
                    echo 'password    '"$var_password_pam_remember_control_flag"'    pam_pwhistory.so' >> "/etc/pam.d/password-auth"
                fi
            fi
        fi
    fi

    PWHISTORY_CONF="/etc/security/pwhistory.conf"
    if [ -f $PWHISTORY_CONF ]; then
        regex="^\s*remember\s*="
        line="remember = $var_password_pam_remember"
        if ! grep -q $regex $PWHISTORY_CONF; then
            echo $line >> $PWHISTORY_CONF
        else
            sed -i --follow-symlinks 's|^\s*\(remember\s*=\s*\)\(\S\+\)|\1'"$var_password_pam_remember"'|g' $PWHISTORY_CONF
        fi
        if [ -e "/etc/pam.d/password-auth" ] ; then
            PAM_FILE_PATH="/etc/pam.d/password-auth"
            if [ -f /usr/bin/authselect ]; then

                if ! authselect check; then
                echo "
                authselect integrity check failed. Remediation aborted!
                This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
                It is not recommended to manually edit the PAM files when authselect tool is available.
                In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
                exit 1
                fi

                CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
                # If not already in use, a custom profile is created preserving the enabled features.
                if [[ ! $CURRENT_PROFILE == custom/* ]]; then
                    ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
                    authselect create-profile hardening -b $CURRENT_PROFILE
                    CURRENT_PROFILE="custom/hardening"

                    authselect apply-changes -b --backup=before-hardening-custom-profile
                    authselect select $CURRENT_PROFILE
                    for feature in $ENABLED_FEATURES; do
                        authselect enable-feature $feature;
                    done

                    authselect apply-changes -b --backup=after-hardening-custom-profile
                fi
                PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth")
                PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"

                authselect apply-changes -b
            fi

        if grep -qP '^\s*password\s.*\bpam_pwhistory.so\s.*\bremember\b' "$PAM_FILE_PATH"; then
            sed -i -E --follow-symlinks 's/(.*password.*pam_pwhistory.so.*)\bremember\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH"
        fi
            if [ -f /usr/bin/authselect ]; then

                authselect apply-changes -b
            fi
        else
            echo "/etc/pam.d/password-auth was not found" >&2
        fi
    else
        PAM_FILE_PATH="/etc/pam.d/password-auth"
        if [ -f /usr/bin/authselect ]; then

            if ! authselect check; then
            echo "
            authselect integrity check failed. Remediation aborted!
            This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
            It is not recommended to manually edit the PAM files when authselect tool is available.
            In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
            exit 1
            fi

            CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
            # If not already in use, a custom profile is created preserving the enabled features.
            if [[ ! $CURRENT_PROFILE == custom/* ]]; then
                ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
                authselect create-profile hardening -b $CURRENT_PROFILE
                CURRENT_PROFILE="custom/hardening"

                authselect apply-changes -b --backup=before-hardening-custom-profile
                authselect select $CURRENT_PROFILE
                for feature in $ENABLED_FEATURES; do
                    authselect enable-feature $feature;
                done

                authselect apply-changes -b --backup=after-hardening-custom-profile
            fi
            PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth")
            PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"

            authselect apply-changes -b
        fi
        if ! grep -qP '^\s*password\s+'"requisite"'\s+pam_pwhistory.so\s*.*' "$PAM_FILE_PATH"; then
            # Line matching group + control + module was not found. Check group + module.
            if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then
                # The control is updated only if one single line matches.
                sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"requisite"' \2/' "$PAM_FILE_PATH"
            else
                echo 'password    '"requisite"'    pam_pwhistory.so' >> "$PAM_FILE_PATH"
            fi
        fi
        # Check the option
        if ! grep -qP '^\s*password\s+'"requisite"'\s+pam_pwhistory.so\s*.*\sremember\b' "$PAM_FILE_PATH"; then
            sed -i -E --follow-symlinks '/\s*password\s+'"requisite"'\s+pam_pwhistory.so.*/ s/$/ remember='"$var_password_pam_remember"'/' "$PAM_FILE_PATH"
        else
            sed -i -E --follow-symlinks 's/(\s*password\s+'"requisite"'\s+pam_pwhistory.so\s+.*)('"remember"'=)[[:alnum:]]+\s*(.*)/\1\2'"$var_password_pam_remember"' \3/' "$PAM_FILE_PATH"
        fi
        if [ -f /usr/bin/authselect ]; then

            authselect apply-changes -b
        fi
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | configure

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-86354-8
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.8
      - NIST-800-53-IA-5(1)(e)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.2.5
      - accounts_password_pam_pwhistory_remember_password_auth
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
    - name: XCCDF Value var_password_pam_remember # promote to variable
      set_fact:
        var_password_pam_remember: !!str 5
      tags:
        - always
    - name: XCCDF Value var_password_pam_remember_control_flag # promote to variable
      set_fact:
        var_password_pam_remember_control_flag: !!str requisite,required
      tags:
        - always

    - name: 'Limit Password Reuse: password-auth - Check if system relies on authselect
        tool'
      ansible.builtin.stat:
        path: /usr/bin/authselect
      register: result_authselect_present
      when: '"pam" in ansible_facts.packages'
      tags:
      - CCE-86354-8
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.8
      - NIST-800-53-IA-5(1)(e)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.2.5
      - accounts_password_pam_pwhistory_remember_password_auth
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

    - name: 'Limit Password Reuse: password-auth - Collect the available authselect features'
      ansible.builtin.command:
        cmd: authselect list-features minimal
      register: result_authselect_available_features
      changed_when: false
      when:
      - '"pam" in ansible_facts.packages'
      - result_authselect_present.stat.exists
      tags:
      - CCE-86354-8
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.8
      - NIST-800-53-IA-5(1)(e)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.2.5
      - accounts_password_pam_pwhistory_remember_password_auth
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

    - name: 'Limit Password Reuse: password-auth - Enable pam_pwhistory.so using authselect
        feature'
      block:

      - name: 'Limit Password Reuse: password-auth - Check integrity of authselect current
          profile'
        ansible.builtin.command:
          cmd: authselect check
        register: result_authselect_check_cmd
        changed_when: false
        ignore_errors: true

      - name: 'Limit Password Reuse: password-auth - Informative message based on the
          authselect integrity check result'
        ansible.builtin.assert:
          that:
          - result_authselect_check_cmd is success
          fail_msg:
          - authselect integrity check failed. Remediation aborted!
          - This remediation could not be applied because an authselect profile was not
            selected or the selected profile is not intact.
          - It is not recommended to manually edit the PAM files when authselect tool
            is available.
          - In cases where the default authselect profile does not cover a specific demand,
            a custom authselect profile is recommended.
          success_msg:
          - authselect integrity check passed

      - name: 'Limit Password Reuse: password-auth - Get authselect current features'
        ansible.builtin.shell:
          cmd: authselect current | tail -n+3 | awk '{ print $2 }'
        register: result_authselect_features
        changed_when: false
        when:
        - result_authselect_check_cmd is success

      - name: 'Limit Password Reuse: password-auth - Ensure "with-pwhistory" feature is
          enabled using authselect tool'
        ansible.builtin.command:
          cmd: authselect enable-feature with-pwhistory
        register: result_authselect_enable_feature_cmd
        when:
        - result_authselect_check_cmd is success
        - result_authselect_features.stdout is not search("with-pwhistory")

      - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are applied'
        ansible.builtin.command:
          cmd: authselect apply-changes -b
        when:
        - result_authselect_enable_feature_cmd is not skipped
        - result_authselect_enable_feature_cmd is success
      when:
      - '"pam" in ansible_facts.packages'
      - result_authselect_present.stat.exists
      - result_authselect_available_features.stdout is search("with-pwhistory")
      tags:
      - CCE-86354-8
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.8
      - NIST-800-53-IA-5(1)(e)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.2.5
      - accounts_password_pam_pwhistory_remember_password_auth
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

    - name: 'Limit Password Reuse: password-auth - Enable pam_pwhistory.so in appropriate
        PAM files'
      block:

      - name: 'Limit Password Reuse: password-auth - Define the PAM file to be edited
          as a local fact'
        ansible.builtin.set_fact:
          pam_file_path: /etc/pam.d/password-auth

      - name: 'Limit Password Reuse: password-auth - Check if system relies on authselect
          tool'
        ansible.builtin.stat:
          path: /usr/bin/authselect
        register: result_authselect_present

      - name: 'Limit Password Reuse: password-auth - Ensure authselect custom profile
          is used if authselect is present'
        block:

        - name: 'Limit Password Reuse: password-auth - Check integrity of authselect current
            profile'
          ansible.builtin.command:
            cmd: authselect check
          register: result_authselect_check_cmd
          changed_when: false
          ignore_errors: true

        - name: 'Limit Password Reuse: password-auth - Informative message based on the
            authselect integrity check result'
          ansible.builtin.assert:
            that:
            - result_authselect_check_cmd is success
            fail_msg:
            - authselect integrity check failed. Remediation aborted!
            - This remediation could not be applied because an authselect profile was
              not selected or the selected profile is not intact.
            - It is not recommended to manually edit the PAM files when authselect tool
              is available.
            - In cases where the default authselect profile does not cover a specific
              demand, a custom authselect profile is recommended.
            success_msg:
            - authselect integrity check passed

        - name: 'Limit Password Reuse: password-auth - Get authselect current profile'
          ansible.builtin.shell:
            cmd: authselect current -r | awk '{ print $1 }'
          register: result_authselect_profile
          changed_when: false
          when:
          - result_authselect_check_cmd is success

        - name: 'Limit Password Reuse: password-auth - Define the current authselect profile
            as a local fact'
          ansible.builtin.set_fact:
            authselect_current_profile: '{{ result_authselect_profile.stdout }}'
            authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
          when:
          - result_authselect_profile is not skipped
          - result_authselect_profile.stdout is match("custom/")

        - name: 'Limit Password Reuse: password-auth - Define the new authselect custom
            profile as a local fact'
          ansible.builtin.set_fact:
            authselect_current_profile: '{{ result_authselect_profile.stdout }}'
            authselect_custom_profile: custom/hardening
          when:
          - result_authselect_profile is not skipped
          - result_authselect_profile.stdout is not match("custom/")

        - name: 'Limit Password Reuse: password-auth - Get authselect current features
            to also enable them in the custom profile'
          ansible.builtin.shell:
            cmd: authselect current | tail -n+3 | awk '{ print $2 }'
          register: result_authselect_features
          changed_when: false
          when:
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")

        - name: 'Limit Password Reuse: password-auth - Check if any custom profile with
            the same name was already created'
          ansible.builtin.stat:
            path: /etc/authselect/{{ authselect_custom_profile }}
          register: result_authselect_custom_profile_present
          changed_when: false
          when:
          - authselect_current_profile is not match("custom/")

        - name: 'Limit Password Reuse: password-auth - Create an authselect custom profile
            based on the current profile'
          ansible.builtin.command:
            cmd: authselect create-profile hardening -b {{ authselect_current_profile
              }}
          when:
          - result_authselect_check_cmd is success
          - authselect_current_profile is not match("custom/")
          - not result_authselect_custom_profile_present.stat.exists

        - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are applied'
          ansible.builtin.command:
            cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")
          - authselect_custom_profile is not match(authselect_current_profile)

        - name: 'Limit Password Reuse: password-auth - Ensure the authselect custom profile
            is selected'
          ansible.builtin.command:
            cmd: authselect select {{ authselect_custom_profile }}
          register: result_pam_authselect_select_profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")
          - authselect_custom_profile is not match(authselect_current_profile)

        - name: 'Limit Password Reuse: password-auth - Restore the authselect features
            in the custom profile'
          ansible.builtin.command:
            cmd: authselect enable-feature {{ item }}
          loop: '{{ result_authselect_features.stdout_lines }}'
          register: result_pam_authselect_restore_features
          when:
          - result_authselect_profile is not skipped
          - result_authselect_features is not skipped
          - result_pam_authselect_select_profile is not skipped

        - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are applied'
          ansible.builtin.command:
            cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - result_pam_authselect_restore_features is not skipped

        - name: 'Limit Password Reuse: password-auth - Change the PAM file to be edited
            according to the custom authselect profile'
          ansible.builtin.set_fact:
            pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
              | basename }}
        when:
        - result_authselect_present.stat.exists

      - name: 'Limit Password Reuse: password-auth - Check if expected PAM module line
          is present in {{ pam_file_path }}'
        ansible.builtin.lineinfile:
          path: '{{ pam_file_path }}'
          regexp: ^\s*password\s+{{ var_password_pam_remember_control_flag.split(",")[0]
            }}\s+pam_pwhistory.so\s*.*
          state: absent
        check_mode: true
        changed_when: false
        register: result_pam_line_present

      - name: 'Limit Password Reuse: password-auth - Include or update the PAM module
          line in {{ pam_file_path }}'
        block:

        - name: 'Limit Password Reuse: password-auth - Check if required PAM module line
            is present in {{ pam_file_path }} with different control'
          ansible.builtin.lineinfile:
            path: '{{ pam_file_path }}'
            regexp: ^\s*password\s+.*\s+pam_pwhistory.so\s*
            state: absent
          check_mode: true
          changed_when: false
          register: result_pam_line_other_control_present

        - name: 'Limit Password Reuse: password-auth - Ensure the correct control for
            the required PAM module line in {{ pam_file_path }}'
          ansible.builtin.replace:
            dest: '{{ pam_file_path }}'
            regexp: ^(\s*password\s+).*(\bpam_pwhistory.so.*)
            replace: \1{{ var_password_pam_remember_control_flag.split(",")[0] }} \2
          register: result_pam_module_edit
          when:
          - result_pam_line_other_control_present.found == 1

        - name: 'Limit Password Reuse: password-auth - Ensure the required PAM module
            line is included in {{ pam_file_path }}'
          ansible.builtin.lineinfile:
            dest: '{{ pam_file_path }}'
            insertafter: ^password.*requisite.*pam_pwquality\.so
            line: password    {{ var_password_pam_remember_control_flag.split(",")[0]
              }}    pam_pwhistory.so
          register: result_pam_module_add
          when:
          - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found
            > 1

        - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are applied'
          ansible.builtin.command:
            cmd: authselect apply-changes -b
          when: |
            result_authselect_present is defined and result_authselect_present.stat.exists and ((result_pam_module_add is defined and result_pam_module_add.changed) or (result_pam_module_edit is defined and result_pam_module_edit.changed))
        when:
        - result_pam_line_present.found is defined
        - result_pam_line_present.found == 0
      when:
      - '"pam" in ansible_facts.packages'
      - |
        (result_authselect_available_features.stdout is defined and result_authselect_available_features.stdout is not search("with-pwhistory")) or result_authselect_available_features is not defined
      tags:
      - CCE-86354-8
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.8
      - NIST-800-53-IA-5(1)(e)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.2.5
      - accounts_password_pam_pwhistory_remember_password_auth
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

    - name: 'Limit Password Reuse: password-auth - Check the presence of /etc/security/pwhistory.conf
        file'
      ansible.builtin.stat:
        path: /etc/security/pwhistory.conf
      register: result_pwhistory_conf_check
      when: '"pam" in ansible_facts.packages'
      tags:
      - CCE-86354-8
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.8
      - NIST-800-53-IA-5(1)(e)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.2.5
      - accounts_password_pam_pwhistory_remember_password_auth
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

    - name: 'Limit Password Reuse: password-auth - pam_pwhistory.so parameters are configured
        in /etc/security/pwhistory.conf file'
      block:

      - name: 'Limit Password Reuse: password-auth - Ensure the pam_pwhistory.so remember
          parameter in /etc/security/pwhistory.conf'
        ansible.builtin.lineinfile:
          path: /etc/security/pwhistory.conf
          regexp: ^\s*remember\s*=
          line: remember = {{ var_password_pam_remember }}
          state: present

      - name: 'Limit Password Reuse: password-auth - Ensure the pam_pwhistory.so remember
          parameter is removed from PAM files'
        block:

        - name: 'Limit Password Reuse: password-auth - Check if /etc/pam.d/password-auth
            file is present'
          ansible.builtin.stat:
            path: /etc/pam.d/password-auth
          register: result_pam_file_present

        - name: 'Limit Password Reuse: password-auth - Check the proper remediation for
            the system'
          block:

          - name: 'Limit Password Reuse: password-auth - Define the PAM file to be edited
              as a local fact'
            ansible.builtin.set_fact:
              pam_file_path: /etc/pam.d/password-auth

          - name: 'Limit Password Reuse: password-auth - Check if system relies on authselect
              tool'
            ansible.builtin.stat:
              path: /usr/bin/authselect
            register: result_authselect_present

          - name: 'Limit Password Reuse: password-auth - Ensure authselect custom profile
              is used if authselect is present'
            block:

            - name: 'Limit Password Reuse: password-auth - Check integrity of authselect
                current profile'
              ansible.builtin.command:
                cmd: authselect check
              register: result_authselect_check_cmd
              changed_when: false
              ignore_errors: true

            - name: 'Limit Password Reuse: password-auth - Informative message based on
                the authselect integrity check result'
              ansible.builtin.assert:
                that:
                - result_authselect_check_cmd is success
                fail_msg:
                - authselect integrity check failed. Remediation aborted!
                - This remediation could not be applied because an authselect profile
                  was not selected or the selected profile is not intact.
                - It is not recommended to manually edit the PAM files when authselect
                  tool is available.
                - In cases where the default authselect profile does not cover a specific
                  demand, a custom authselect profile is recommended.
                success_msg:
                - authselect integrity check passed

            - name: 'Limit Password Reuse: password-auth - Get authselect current profile'
              ansible.builtin.shell:
                cmd: authselect current -r | awk '{ print $1 }'
              register: result_authselect_profile
              changed_when: false
              when:
              - result_authselect_check_cmd is success

            - name: 'Limit Password Reuse: password-auth - Define the current authselect
                profile as a local fact'
              ansible.builtin.set_fact:
                authselect_current_profile: '{{ result_authselect_profile.stdout }}'
                authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
              when:
              - result_authselect_profile is not skipped
              - result_authselect_profile.stdout is match("custom/")

            - name: 'Limit Password Reuse: password-auth - Define the new authselect custom
                profile as a local fact'
              ansible.builtin.set_fact:
                authselect_current_profile: '{{ result_authselect_profile.stdout }}'
                authselect_custom_profile: custom/hardening
              when:
              - result_authselect_profile is not skipped
              - result_authselect_profile.stdout is not match("custom/")

            - name: 'Limit Password Reuse: password-auth - Get authselect current features
                to also enable them in the custom profile'
              ansible.builtin.shell:
                cmd: authselect current | tail -n+3 | awk '{ print $2 }'
              register: result_authselect_features
              changed_when: false
              when:
              - result_authselect_profile is not skipped
              - authselect_current_profile is not match("custom/")

            - name: 'Limit Password Reuse: password-auth - Check if any custom profile
                with the same name was already created'
              ansible.builtin.stat:
                path: /etc/authselect/{{ authselect_custom_profile }}
              register: result_authselect_custom_profile_present
              changed_when: false
              when:
              - authselect_current_profile is not match("custom/")

            - name: 'Limit Password Reuse: password-auth - Create an authselect custom
                profile based on the current profile'
              ansible.builtin.command:
                cmd: authselect create-profile hardening -b {{ authselect_current_profile
                  }}
              when:
              - result_authselect_check_cmd is success
              - authselect_current_profile is not match("custom/")
              - not result_authselect_custom_profile_present.stat.exists

            - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are
                applied'
              ansible.builtin.command:
                cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
              when:
              - result_authselect_check_cmd is success
              - result_authselect_profile is not skipped
              - authselect_current_profile is not match("custom/")
              - authselect_custom_profile is not match(authselect_current_profile)

            - name: 'Limit Password Reuse: password-auth - Ensure the authselect custom
                profile is selected'
              ansible.builtin.command:
                cmd: authselect select {{ authselect_custom_profile }}
              register: result_pam_authselect_select_profile
              when:
              - result_authselect_check_cmd is success
              - result_authselect_profile is not skipped
              - authselect_current_profile is not match("custom/")
              - authselect_custom_profile is not match(authselect_current_profile)

            - name: 'Limit Password Reuse: password-auth - Restore the authselect features
                in the custom profile'
              ansible.builtin.command:
                cmd: authselect enable-feature {{ item }}
              loop: '{{ result_authselect_features.stdout_lines }}'
              register: result_pam_authselect_restore_features
              when:
              - result_authselect_profile is not skipped
              - result_authselect_features is not skipped
              - result_pam_authselect_select_profile is not skipped

            - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are
                applied'
              ansible.builtin.command:
                cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
              when:
              - result_authselect_check_cmd is success
              - result_authselect_profile is not skipped
              - result_pam_authselect_restore_features is not skipped

            - name: 'Limit Password Reuse: password-auth - Change the PAM file to be edited
                according to the custom authselect profile'
              ansible.builtin.set_fact:
                pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
                  | basename }}
            when:
            - result_authselect_present.stat.exists

          - name: 'Limit Password Reuse: password-auth - Ensure the "remember" option
              from "pam_pwhistory.so" is not present in {{ pam_file_path }}'
            ansible.builtin.replace:
              dest: '{{ pam_file_path }}'
              regexp: (.*password.*pam_pwhistory.so.*)\bremember\b=?[0-9a-zA-Z]*(.*)
              replace: \1\2
            register: result_pam_option_removal

          - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are
              applied'
            ansible.builtin.command:
              cmd: authselect apply-changes -b
            when:
            - result_authselect_present.stat.exists
            - result_pam_option_removal is changed
          when:
          - result_pam_file_present.stat.exists
      when:
      - '"pam" in ansible_facts.packages'
      - result_pwhistory_conf_check.stat.exists
      tags:
      - CCE-86354-8
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.8
      - NIST-800-53-IA-5(1)(e)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.2.5
      - accounts_password_pam_pwhistory_remember_password_auth
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

    - name: 'Limit Password Reuse: password-auth - pam_pwhistory.so parameters are configured
        in PAM files'
      block:

      - name: 'Limit Password Reuse: password-auth - Define the PAM file to be edited
          as a local fact'
        ansible.builtin.set_fact:
          pam_file_path: /etc/pam.d/password-auth

      - name: 'Limit Password Reuse: password-auth - Check if system relies on authselect
          tool'
        ansible.builtin.stat:
          path: /usr/bin/authselect
        register: result_authselect_present

      - name: 'Limit Password Reuse: password-auth - Ensure authselect custom profile
          is used if authselect is present'
        block:

        - name: 'Limit Password Reuse: password-auth - Check integrity of authselect current
            profile'
          ansible.builtin.command:
            cmd: authselect check
          register: result_authselect_check_cmd
          changed_when: false
          ignore_errors: true

        - name: 'Limit Password Reuse: password-auth - Informative message based on the
            authselect integrity check result'
          ansible.builtin.assert:
            that:
            - result_authselect_check_cmd is success
            fail_msg:
            - authselect integrity check failed. Remediation aborted!
            - This remediation could not be applied because an authselect profile was
              not selected or the selected profile is not intact.
            - It is not recommended to manually edit the PAM files when authselect tool
              is available.
            - In cases where the default authselect profile does not cover a specific
              demand, a custom authselect profile is recommended.
            success_msg:
            - authselect integrity check passed

        - name: 'Limit Password Reuse: password-auth - Get authselect current profile'
          ansible.builtin.shell:
            cmd: authselect current -r | awk '{ print $1 }'
          register: result_authselect_profile
          changed_when: false
          when:
          - result_authselect_check_cmd is success

        - name: 'Limit Password Reuse: password-auth - Define the current authselect profile
            as a local fact'
          ansible.builtin.set_fact:
            authselect_current_profile: '{{ result_authselect_profile.stdout }}'
            authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
          when:
          - result_authselect_profile is not skipped
          - result_authselect_profile.stdout is match("custom/")

        - name: 'Limit Password Reuse: password-auth - Define the new authselect custom
            profile as a local fact'
          ansible.builtin.set_fact:
            authselect_current_profile: '{{ result_authselect_profile.stdout }}'
            authselect_custom_profile: custom/hardening
          when:
          - result_authselect_profile is not skipped
          - result_authselect_profile.stdout is not match("custom/")

        - name: 'Limit Password Reuse: password-auth - Get authselect current features
            to also enable them in the custom profile'
          ansible.builtin.shell:
            cmd: authselect current | tail -n+3 | awk '{ print $2 }'
          register: result_authselect_features
          changed_when: false
          when:
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")

        - name: 'Limit Password Reuse: password-auth - Check if any custom profile with
            the same name was already created'
          ansible.builtin.stat:
            path: /etc/authselect/{{ authselect_custom_profile }}
          register: result_authselect_custom_profile_present
          changed_when: false
          when:
          - authselect_current_profile is not match("custom/")

        - name: 'Limit Password Reuse: password-auth - Create an authselect custom profile
            based on the current profile'
          ansible.builtin.command:
            cmd: authselect create-profile hardening -b {{ authselect_current_profile
              }}
          when:
          - result_authselect_check_cmd is success
          - authselect_current_profile is not match("custom/")
          - not result_authselect_custom_profile_present.stat.exists

        - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are applied'
          ansible.builtin.command:
            cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")
          - authselect_custom_profile is not match(authselect_current_profile)

        - name: 'Limit Password Reuse: password-auth - Ensure the authselect custom profile
            is selected'
          ansible.builtin.command:
            cmd: authselect select {{ authselect_custom_profile }}
          register: result_pam_authselect_select_profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")
          - authselect_custom_profile is not match(authselect_current_profile)

        - name: 'Limit Password Reuse: password-auth - Restore the authselect features
            in the custom profile'
          ansible.builtin.command:
            cmd: authselect enable-feature {{ item }}
          loop: '{{ result_authselect_features.stdout_lines }}'
          register: result_pam_authselect_restore_features
          when:
          - result_authselect_profile is not skipped
          - result_authselect_features is not skipped
          - result_pam_authselect_select_profile is not skipped

        - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are applied'
          ansible.builtin.command:
            cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - result_pam_authselect_restore_features is not skipped

        - name: 'Limit Password Reuse: password-auth - Change the PAM file to be edited
            according to the custom authselect profile'
          ansible.builtin.set_fact:
            pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
              | basename }}
        when:
        - result_authselect_present.stat.exists

      - name: 'Limit Password Reuse: password-auth - Check if expected PAM module line
          is present in {{ pam_file_path }}'
        ansible.builtin.lineinfile:
          path: '{{ pam_file_path }}'
          regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.*
          state: absent
        check_mode: true
        changed_when: false
        register: result_pam_line_present

      - name: 'Limit Password Reuse: password-auth - Include or update the PAM module
          line in {{ pam_file_path }}'
        block:

        - name: 'Limit Password Reuse: password-auth - Check if required PAM module line
            is present in {{ pam_file_path }} with different control'
          ansible.builtin.lineinfile:
            path: '{{ pam_file_path }}'
            regexp: ^\s*password\s+.*\s+pam_pwhistory.so\s*
            state: absent
          check_mode: true
          changed_when: false
          register: result_pam_line_other_control_present

        - name: 'Limit Password Reuse: password-auth - Ensure the correct control for
            the required PAM module line in {{ pam_file_path }}'
          ansible.builtin.replace:
            dest: '{{ pam_file_path }}'
            regexp: ^(\s*password\s+).*(\bpam_pwhistory.so.*)
            replace: \1requisite \2
          register: result_pam_module_edit
          when:
          - result_pam_line_other_control_present.found == 1

        - name: 'Limit Password Reuse: password-auth - Ensure the required PAM module
            line is included in {{ pam_file_path }}'
          ansible.builtin.lineinfile:
            dest: '{{ pam_file_path }}'
            line: password    requisite    pam_pwhistory.so
          register: result_pam_module_add
          when:
          - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found
            > 1

        - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are applied'
          ansible.builtin.command:
            cmd: authselect apply-changes -b
          when: |
            result_authselect_present is defined and result_authselect_present.stat.exists and ((result_pam_module_add is defined and result_pam_module_add.changed) or (result_pam_module_edit is defined and result_pam_module_edit.changed))
        when:
        - result_pam_line_present.found is defined
        - result_pam_line_present.found == 0

      - name: 'Limit Password Reuse: password-auth - Check if the required PAM module
          option is present in {{ pam_file_path }}'
        ansible.builtin.lineinfile:
          path: '{{ pam_file_path }}'
          regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.*\sremember\b
          state: absent
        check_mode: true
        changed_when: false
        register: result_pam_module_remember_option_present

      - name: 'Limit Password Reuse: password-auth - Ensure the "remember" PAM option
          for "pam_pwhistory.so" is included in {{ pam_file_path }}'
        ansible.builtin.lineinfile:
          path: '{{ pam_file_path }}'
          backrefs: true
          regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so.*)
          line: \1 remember={{ var_password_pam_remember }}
          state: present
        register: result_pam_remember_add
        when:
        - result_pam_module_remember_option_present.found == 0

      - name: 'Limit Password Reuse: password-auth - Ensure the required value for "remember"
          PAM option from "pam_pwhistory.so" in {{ pam_file_path }}'
        ansible.builtin.lineinfile:
          path: '{{ pam_file_path }}'
          backrefs: true
          regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*)
          line: \1\2={{ var_password_pam_remember }} \3
        register: result_pam_remember_edit
        when:
        - result_pam_module_remember_option_present.found > 0

      - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are applied'
        ansible.builtin.command:
          cmd: authselect apply-changes -b
        when:
        - result_authselect_present.stat.exists
        - (result_pam_remember_add is defined and result_pam_remember_add.changed) or
          (result_pam_remember_edit is defined and result_pam_remember_edit.changed)
      when:
      - '"pam" in ansible_facts.packages'
      - not result_pwhistory_conf_check.stat.exists
      tags:
      - CCE-86354-8
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.8
      - NIST-800-53-IA-5(1)(e)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.2.5
      - accounts_password_pam_pwhistory_remember_password_auth
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-accounts_password_pam_pwhistory_remember_password_auth:def:1

Class:

compliance

Title:

Limit Password Reuse: password-auth

Version:

2

Description:

The passwords to remember should be set correctly.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_password_pam_pwhistory_remember_password_auth:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#package_pam
Limit Password Reuse: system-auth medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_system_auth
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-89176-2

References:

BP28(R18), 1, 12, 15, 16, 5, 5.6.2.1.1, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 3.5.8, CCI-000200, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.2, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, A.18.1.4, A.7.1.1, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.2, A.9.4.3, IA-5(f), IA-5(1)(e), PR.AC-1, PR.AC-6, PR.AC-7, Req-8.2.5, SRG-OS-000077-GPOS-00045, SRG-OS-000077-VMM-000440, 5.5.3
Description:
Do not allow users to reuse recent passwords. This can be accomplished by using the `remember` option for the `pam_pwhistory` PAM module.
On systems with newer versions of `authselect`, the `pam_pwhistory` PAM module can be enabled via authselect feature:

    authselect enable-feature with-pwhistory

Otherwise, it should be enabled using an authselect custom profile.
Newer systems also have the `/etc/security/pwhistory.conf` file for setting `pam_pwhistory` module options. This file should be used whenever available. Otherwise, the `pam_pwhistory` module options can be set in PAM files.
The value for `remember` option must be equal or greater than 5
Rationale:

Preventing re-use of previous passwords helps ensure that a compromised password is not re-used by a user.

Warnings:

General warning
If the system relies on `authselect` tool to manage PAM settings, the remediation will also use `authselect` tool. However, if any manual modification was made in PAM files, the `authselect` integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will be shown in the remediation report.

General warning
Newer versions of `authselect` contain an authselect feature to easily and properly enable `pam_pwhistory.so` module. If this feature is not yet available in your system, an authselect custom profile must be used to avoid integrity issues in PAM files.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    System was not configured with authselect.

            authselect integrity check failed. Remediation aborted!
            This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
            It is not recommended to manually edit the PAM files when authselect tool is available.
            In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended.

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q pam; then

    var_password_pam_remember='5'
    var_password_pam_remember_control_flag='requisite,required'

    var_password_pam_remember_control_flag="$(echo $var_password_pam_remember_control_flag | cut -d \, -f 1)"

    if [ -f /usr/bin/authselect ]; then
        if authselect list-features minimal | grep -q with-pwhistory; then
            if ! authselect check; then
            echo "
            authselect integrity check failed. Remediation aborted!
            This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
            It is not recommended to manually edit the PAM files when authselect tool is available.
            In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
            exit 1
            fi
            authselect enable-feature with-pwhistory

            authselect apply-changes -b
        else

            if ! authselect check; then
            echo "
            authselect integrity check failed. Remediation aborted!
            This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
            It is not recommended to manually edit the PAM files when authselect tool is available.
            In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
            exit 1
            fi

            CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
            # If not already in use, a custom profile is created preserving the enabled features.
            if [[ ! $CURRENT_PROFILE == custom/* ]]; then
                ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
                authselect create-profile hardening -b $CURRENT_PROFILE
                CURRENT_PROFILE="custom/hardening"

                authselect apply-changes -b --backup=before-hardening-custom-profile
                authselect select $CURRENT_PROFILE
                for feature in $ENABLED_FEATURES; do
                    authselect enable-feature $feature;
                done

                authselect apply-changes -b --backup=after-hardening-custom-profile
            fi
            PAM_FILE_NAME=$(basename "/etc/pam.d/system-auth")
            PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"

            authselect apply-changes -b
            if ! grep -qP '^\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so\s*.*' "$PAM_FILE_PATH"; then
                # Line matching group + control + module was not found. Check group + module.
                if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then
                    # The control is updated only if one single line matches.
                    sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"$var_password_pam_remember_control_flag"' \2/' "$PAM_FILE_PATH"
                else
                    LAST_MATCH_LINE=$(grep -nP "^password.*requisite.*pam_pwquality\.so" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1)
                    if [ ! -z $LAST_MATCH_LINE ]; then
                        sed -i --follow-symlinks $LAST_MATCH_LINE' a password     '"$var_password_pam_remember_control_flag"'    pam_pwhistory.so' "$PAM_FILE_PATH"
                    else
                        echo 'password    '"$var_password_pam_remember_control_flag"'    pam_pwhistory.so' >> "$PAM_FILE_PATH"
                    fi
                fi
            fi
        fi
    else
        if ! grep -qP '^\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so\s*.*' "/etc/pam.d/system-auth"; then
            # Line matching group + control + module was not found. Check group + module.
            if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "/etc/pam.d/system-auth")" -eq 1 ]; then
                # The control is updated only if one single line matches.
                sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"$var_password_pam_remember_control_flag"' \2/' "/etc/pam.d/system-auth"
            else
                LAST_MATCH_LINE=$(grep -nP "^password.*requisite.*pam_pwquality\.so" "/etc/pam.d/system-auth" | tail -n 1 | cut -d: -f 1)
                if [ ! -z $LAST_MATCH_LINE ]; then
                    sed -i --follow-symlinks $LAST_MATCH_LINE' a password     '"$var_password_pam_remember_control_flag"'    pam_pwhistory.so' "/etc/pam.d/system-auth"
                else
                    echo 'password    '"$var_password_pam_remember_control_flag"'    pam_pwhistory.so' >> "/etc/pam.d/system-auth"
                fi
            fi
        fi
    fi

    PWHISTORY_CONF="/etc/security/pwhistory.conf"
    if [ -f $PWHISTORY_CONF ]; then
        regex="^\s*remember\s*="
        line="remember = $var_password_pam_remember"
        if ! grep -q $regex $PWHISTORY_CONF; then
            echo $line >> $PWHISTORY_CONF
        else
            sed -i --follow-symlinks 's|^\s*\(remember\s*=\s*\)\(\S\+\)|\1'"$var_password_pam_remember"'|g' $PWHISTORY_CONF
        fi
        if [ -e "/etc/pam.d/system-auth" ] ; then
            PAM_FILE_PATH="/etc/pam.d/system-auth"
            if [ -f /usr/bin/authselect ]; then

                if ! authselect check; then
                echo "
                authselect integrity check failed. Remediation aborted!
                This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
                It is not recommended to manually edit the PAM files when authselect tool is available.
                In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
                exit 1
                fi

                CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
                # If not already in use, a custom profile is created preserving the enabled features.
                if [[ ! $CURRENT_PROFILE == custom/* ]]; then
                    ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
                    authselect create-profile hardening -b $CURRENT_PROFILE
                    CURRENT_PROFILE="custom/hardening"

                    authselect apply-changes -b --backup=before-hardening-custom-profile
                    authselect select $CURRENT_PROFILE
                    for feature in $ENABLED_FEATURES; do
                        authselect enable-feature $feature;
                    done

                    authselect apply-changes -b --backup=after-hardening-custom-profile
                fi
                PAM_FILE_NAME=$(basename "/etc/pam.d/system-auth")
                PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"

                authselect apply-changes -b
            fi

        if grep -qP '^\s*password\s.*\bpam_pwhistory.so\s.*\bremember\b' "$PAM_FILE_PATH"; then
            sed -i -E --follow-symlinks 's/(.*password.*pam_pwhistory.so.*)\bremember\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH"
        fi
            if [ -f /usr/bin/authselect ]; then

                authselect apply-changes -b
            fi
        else
            echo "/etc/pam.d/system-auth was not found" >&2
        fi
    else
        PAM_FILE_PATH="/etc/pam.d/system-auth"
        if [ -f /usr/bin/authselect ]; then

            if ! authselect check; then
            echo "
            authselect integrity check failed. Remediation aborted!
            This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
            It is not recommended to manually edit the PAM files when authselect tool is available.
            In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
            exit 1
            fi

            CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
            # If not already in use, a custom profile is created preserving the enabled features.
            if [[ ! $CURRENT_PROFILE == custom/* ]]; then
                ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
                authselect create-profile hardening -b $CURRENT_PROFILE
                CURRENT_PROFILE="custom/hardening"

                authselect apply-changes -b --backup=before-hardening-custom-profile
                authselect select $CURRENT_PROFILE
                for feature in $ENABLED_FEATURES; do
                    authselect enable-feature $feature;
                done

                authselect apply-changes -b --backup=after-hardening-custom-profile
            fi
            PAM_FILE_NAME=$(basename "/etc/pam.d/system-auth")
            PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"

            authselect apply-changes -b
        fi
        if ! grep -qP '^\s*password\s+'"requisite"'\s+pam_pwhistory.so\s*.*' "$PAM_FILE_PATH"; then
            # Line matching group + control + module was not found. Check group + module.
            if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then
                # The control is updated only if one single line matches.
                sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"requisite"' \2/' "$PAM_FILE_PATH"
            else
                echo 'password    '"requisite"'    pam_pwhistory.so' >> "$PAM_FILE_PATH"
            fi
        fi
        # Check the option
        if ! grep -qP '^\s*password\s+'"requisite"'\s+pam_pwhistory.so\s*.*\sremember\b' "$PAM_FILE_PATH"; then
            sed -i -E --follow-symlinks '/\s*password\s+'"requisite"'\s+pam_pwhistory.so.*/ s/$/ remember='"$var_password_pam_remember"'/' "$PAM_FILE_PATH"
        else
            sed -i -E --follow-symlinks 's/(\s*password\s+'"requisite"'\s+pam_pwhistory.so\s+.*)('"remember"'=)[[:alnum:]]+\s*(.*)/\1\2'"$var_password_pam_remember"' \3/' "$PAM_FILE_PATH"
        fi
        if [ -f /usr/bin/authselect ]; then

            authselect apply-changes -b
        fi
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | configure

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-89176-2
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.8
      - NIST-800-53-IA-5(1)(e)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.2.5
      - accounts_password_pam_pwhistory_remember_system_auth
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
    - name: XCCDF Value var_password_pam_remember # promote to variable
      set_fact:
        var_password_pam_remember: !!str 5
      tags:
        - always
    - name: XCCDF Value var_password_pam_remember_control_flag # promote to variable
      set_fact:
        var_password_pam_remember_control_flag: !!str requisite,required
      tags:
        - always

    - name: 'Limit Password Reuse: system-auth - Check if system relies on authselect
        tool'
      ansible.builtin.stat:
        path: /usr/bin/authselect
      register: result_authselect_present
      when: '"pam" in ansible_facts.packages'
      tags:
      - CCE-89176-2
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.8
      - NIST-800-53-IA-5(1)(e)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.2.5
      - accounts_password_pam_pwhistory_remember_system_auth
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

    - name: 'Limit Password Reuse: system-auth - Collect the available authselect features'
      ansible.builtin.command:
        cmd: authselect list-features minimal
      register: result_authselect_available_features
      changed_when: false
      when:
      - '"pam" in ansible_facts.packages'
      - result_authselect_present.stat.exists
      tags:
      - CCE-89176-2
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.8
      - NIST-800-53-IA-5(1)(e)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.2.5
      - accounts_password_pam_pwhistory_remember_system_auth
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

    - name: 'Limit Password Reuse: system-auth - Enable pam_pwhistory.so using authselect
        feature'
      block:

      - name: 'Limit Password Reuse: system-auth - Check integrity of authselect current
          profile'
        ansible.builtin.command:
          cmd: authselect check
        register: result_authselect_check_cmd
        changed_when: false
        ignore_errors: true

      - name: 'Limit Password Reuse: system-auth - Informative message based on the authselect
          integrity check result'
        ansible.builtin.assert:
          that:
          - result_authselect_check_cmd is success
          fail_msg:
          - authselect integrity check failed. Remediation aborted!
          - This remediation could not be applied because an authselect profile was not
            selected or the selected profile is not intact.
          - It is not recommended to manually edit the PAM files when authselect tool
            is available.
          - In cases where the default authselect profile does not cover a specific demand,
            a custom authselect profile is recommended.
          success_msg:
          - authselect integrity check passed

      - name: 'Limit Password Reuse: system-auth - Get authselect current features'
        ansible.builtin.shell:
          cmd: authselect current | tail -n+3 | awk '{ print $2 }'
        register: result_authselect_features
        changed_when: false
        when:
        - result_authselect_check_cmd is success

      - name: 'Limit Password Reuse: system-auth - Ensure "with-pwhistory" feature is
          enabled using authselect tool'
        ansible.builtin.command:
          cmd: authselect enable-feature with-pwhistory
        register: result_authselect_enable_feature_cmd
        when:
        - result_authselect_check_cmd is success
        - result_authselect_features.stdout is not search("with-pwhistory")

      - name: 'Limit Password Reuse: system-auth - Ensure authselect changes are applied'
        ansible.builtin.command:
          cmd: authselect apply-changes -b
        when:
        - result_authselect_enable_feature_cmd is not skipped
        - result_authselect_enable_feature_cmd is success
      when:
      - '"pam" in ansible_facts.packages'
      - result_authselect_present.stat.exists
      - result_authselect_available_features.stdout is search("with-pwhistory")
      tags:
      - CCE-89176-2
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.8
      - NIST-800-53-IA-5(1)(e)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.2.5
      - accounts_password_pam_pwhistory_remember_system_auth
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

    - name: 'Limit Password Reuse: system-auth - Enable pam_pwhistory.so in appropriate
        PAM files'
      block:

      - name: 'Limit Password Reuse: system-auth - Define the PAM file to be edited as
          a local fact'
        ansible.builtin.set_fact:
          pam_file_path: /etc/pam.d/system-auth

      - name: 'Limit Password Reuse: system-auth - Check if system relies on authselect
          tool'
        ansible.builtin.stat:
          path: /usr/bin/authselect
        register: result_authselect_present

      - name: 'Limit Password Reuse: system-auth - Ensure authselect custom profile is
          used if authselect is present'
        block:

        - name: 'Limit Password Reuse: system-auth - Check integrity of authselect current
            profile'
          ansible.builtin.command:
            cmd: authselect check
          register: result_authselect_check_cmd
          changed_when: false
          ignore_errors: true

        - name: 'Limit Password Reuse: system-auth - Informative message based on the
            authselect integrity check result'
          ansible.builtin.assert:
            that:
            - result_authselect_check_cmd is success
            fail_msg:
            - authselect integrity check failed. Remediation aborted!
            - This remediation could not be applied because an authselect profile was
              not selected or the selected profile is not intact.
            - It is not recommended to manually edit the PAM files when authselect tool
              is available.
            - In cases where the default authselect profile does not cover a specific
              demand, a custom authselect profile is recommended.
            success_msg:
            - authselect integrity check passed

        - name: 'Limit Password Reuse: system-auth - Get authselect current profile'
          ansible.builtin.shell:
            cmd: authselect current -r | awk '{ print $1 }'
          register: result_authselect_profile
          changed_when: false
          when:
          - result_authselect_check_cmd is success

        - name: 'Limit Password Reuse: system-auth - Define the current authselect profile
            as a local fact'
          ansible.builtin.set_fact:
            authselect_current_profile: '{{ result_authselect_profile.stdout }}'
            authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
          when:
          - result_authselect_profile is not skipped
          - result_authselect_profile.stdout is match("custom/")

        - name: 'Limit Password Reuse: system-auth - Define the new authselect custom
            profile as a local fact'
          ansible.builtin.set_fact:
            authselect_current_profile: '{{ result_authselect_profile.stdout }}'
            authselect_custom_profile: custom/hardening
          when:
          - result_authselect_profile is not skipped
          - result_authselect_profile.stdout is not match("custom/")

        - name: 'Limit Password Reuse: system-auth - Get authselect current features to
            also enable them in the custom profile'
          ansible.builtin.shell:
            cmd: authselect current | tail -n+3 | awk '{ print $2 }'
          register: result_authselect_features
          changed_when: false
          when:
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")

        - name: 'Limit Password Reuse: system-auth - Check if any custom profile with
            the same name was already created'
          ansible.builtin.stat:
            path: /etc/authselect/{{ authselect_custom_profile }}
          register: result_authselect_custom_profile_present
          changed_when: false
          when:
          - authselect_current_profile is not match("custom/")

        - name: 'Limit Password Reuse: system-auth - Create an authselect custom profile
            based on the current profile'
          ansible.builtin.command:
            cmd: authselect create-profile hardening -b {{ authselect_current_profile
              }}
          when:
          - result_authselect_check_cmd is success
          - authselect_current_profile is not match("custom/")
          - not result_authselect_custom_profile_present.stat.exists

        - name: 'Limit Password Reuse: system-auth - Ensure authselect changes are applied'
          ansible.builtin.command:
            cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")
          - authselect_custom_profile is not match(authselect_current_profile)

        - name: 'Limit Password Reuse: system-auth - Ensure the authselect custom profile
            is selected'
          ansible.builtin.command:
            cmd: authselect select {{ authselect_custom_profile }}
          register: result_pam_authselect_select_profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")
          - authselect_custom_profile is not match(authselect_current_profile)

        - name: 'Limit Password Reuse: system-auth - Restore the authselect features in
            the custom profile'
          ansible.builtin.command:
            cmd: authselect enable-feature {{ item }}
          loop: '{{ result_authselect_features.stdout_lines }}'
          register: result_pam_authselect_restore_features
          when:
          - result_authselect_profile is not skipped
          - result_authselect_features is not skipped
          - result_pam_authselect_select_profile is not skipped

        - name: 'Limit Password Reuse: system-auth - Ensure authselect changes are applied'
          ansible.builtin.command:
            cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - result_pam_authselect_restore_features is not skipped

        - name: 'Limit Password Reuse: system-auth - Change the PAM file to be edited
            according to the custom authselect profile'
          ansible.builtin.set_fact:
            pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
              | basename }}
        when:
        - result_authselect_present.stat.exists

      - name: 'Limit Password Reuse: system-auth - Check if expected PAM module line is
          present in {{ pam_file_path }}'
        ansible.builtin.lineinfile:
          path: '{{ pam_file_path }}'
          regexp: ^\s*password\s+{{ var_password_pam_remember_control_flag.split(",")[0]
            }}\s+pam_pwhistory.so\s*.*
          state: absent
        check_mode: true
        changed_when: false
        register: result_pam_line_present

      - name: 'Limit Password Reuse: system-auth - Include or update the PAM module line
          in {{ pam_file_path }}'
        block:

        - name: 'Limit Password Reuse: system-auth - Check if required PAM module line
            is present in {{ pam_file_path }} with different control'
          ansible.builtin.lineinfile:
            path: '{{ pam_file_path }}'
            regexp: ^\s*password\s+.*\s+pam_pwhistory.so\s*
            state: absent
          check_mode: true
          changed_when: false
          register: result_pam_line_other_control_present

        - name: 'Limit Password Reuse: system-auth - Ensure the correct control for the
            required PAM module line in {{ pam_file_path }}'
          ansible.builtin.replace:
            dest: '{{ pam_file_path }}'
            regexp: ^(\s*password\s+).*(\bpam_pwhistory.so.*)
            replace: \1{{ var_password_pam_remember_control_flag.split(",")[0] }} \2
          register: result_pam_module_edit
          when:
          - result_pam_line_other_control_present.found == 1

        - name: 'Limit Password Reuse: system-auth - Ensure the required PAM module line
            is included in {{ pam_file_path }}'
          ansible.builtin.lineinfile:
            dest: '{{ pam_file_path }}'
            insertafter: ^password.*requisite.*pam_pwquality\.so
            line: password    {{ var_password_pam_remember_control_flag.split(",")[0]
              }}    pam_pwhistory.so
          register: result_pam_module_add
          when:
          - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found
            > 1

        - name: 'Limit Password Reuse: system-auth - Ensure authselect changes are applied'
          ansible.builtin.command:
            cmd: authselect apply-changes -b
          when: |
            result_authselect_present is defined and result_authselect_present.stat.exists and ((result_pam_module_add is defined and result_pam_module_add.changed) or (result_pam_module_edit is defined and result_pam_module_edit.changed))
        when:
        - result_pam_line_present.found is defined
        - result_pam_line_present.found == 0
      when:
      - '"pam" in ansible_facts.packages'
      - |
        (result_authselect_available_features.stdout is defined and result_authselect_available_features.stdout is not search("with-pwhistory")) or result_authselect_available_features is not defined
      tags:
      - CCE-89176-2
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.8
      - NIST-800-53-IA-5(1)(e)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.2.5
      - accounts_password_pam_pwhistory_remember_system_auth
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

    - name: 'Limit Password Reuse: system-auth - Check the presence of /etc/security/pwhistory.conf
        file'
      ansible.builtin.stat:
        path: /etc/security/pwhistory.conf
      register: result_pwhistory_conf_check
      when: '"pam" in ansible_facts.packages'
      tags:
      - CCE-89176-2
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.8
      - NIST-800-53-IA-5(1)(e)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.2.5
      - accounts_password_pam_pwhistory_remember_system_auth
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

    - name: 'Limit Password Reuse: system-auth - pam_pwhistory.so parameters are configured
        in /etc/security/pwhistory.conf file'
      block:

      - name: 'Limit Password Reuse: system-auth - Ensure the pam_pwhistory.so remember
          parameter in /etc/security/pwhistory.conf'
        ansible.builtin.lineinfile:
          path: /etc/security/pwhistory.conf
          regexp: ^\s*remember\s*=
          line: remember = {{ var_password_pam_remember }}
          state: present

      - name: 'Limit Password Reuse: system-auth - Ensure the pam_pwhistory.so remember
          parameter is removed from PAM files'
        block:

        - name: 'Limit Password Reuse: system-auth - Check if /etc/pam.d/system-auth file
            is present'
          ansible.builtin.stat:
            path: /etc/pam.d/system-auth
          register: result_pam_file_present

        - name: 'Limit Password Reuse: system-auth - Check the proper remediation for
            the system'
          block:

          - name: 'Limit Password Reuse: system-auth - Define the PAM file to be edited
              as a local fact'
            ansible.builtin.set_fact:
              pam_file_path: /etc/pam.d/system-auth

          - name: 'Limit Password Reuse: system-auth - Check if system relies on authselect
              tool'
            ansible.builtin.stat:
              path: /usr/bin/authselect
            register: result_authselect_present

          - name: 'Limit Password Reuse: system-auth - Ensure authselect custom profile
              is used if authselect is present'
            block:

            - name: 'Limit Password Reuse: system-auth - Check integrity of authselect
                current profile'
              ansible.builtin.command:
                cmd: authselect check
              register: result_authselect_check_cmd
              changed_when: false
              ignore_errors: true

            - name: 'Limit Password Reuse: system-auth - Informative message based on
                the authselect integrity check result'
              ansible.builtin.assert:
                that:
                - result_authselect_check_cmd is success
                fail_msg:
                - authselect integrity check failed. Remediation aborted!
                - This remediation could not be applied because an authselect profile
                  was not selected or the selected profile is not intact.
                - It is not recommended to manually edit the PAM files when authselect
                  tool is available.
                - In cases where the default authselect profile does not cover a specific
                  demand, a custom authselect profile is recommended.
                success_msg:
                - authselect integrity check passed

            - name: 'Limit Password Reuse: system-auth - Get authselect current profile'
              ansible.builtin.shell:
                cmd: authselect current -r | awk '{ print $1 }'
              register: result_authselect_profile
              changed_when: false
              when:
              - result_authselect_check_cmd is success

            - name: 'Limit Password Reuse: system-auth - Define the current authselect
                profile as a local fact'
              ansible.builtin.set_fact:
                authselect_current_profile: '{{ result_authselect_profile.stdout }}'
                authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
              when:
              - result_authselect_profile is not skipped
              - result_authselect_profile.stdout is match("custom/")

            - name: 'Limit Password Reuse: system-auth - Define the new authselect custom
                profile as a local fact'
              ansible.builtin.set_fact:
                authselect_current_profile: '{{ result_authselect_profile.stdout }}'
                authselect_custom_profile: custom/hardening
              when:
              - result_authselect_profile is not skipped
              - result_authselect_profile.stdout is not match("custom/")

            - name: 'Limit Password Reuse: system-auth - Get authselect current features
                to also enable them in the custom profile'
              ansible.builtin.shell:
                cmd: authselect current | tail -n+3 | awk '{ print $2 }'
              register: result_authselect_features
              changed_when: false
              when:
              - result_authselect_profile is not skipped
              - authselect_current_profile is not match("custom/")

            - name: 'Limit Password Reuse: system-auth - Check if any custom profile with
                the same name was already created'
              ansible.builtin.stat:
                path: /etc/authselect/{{ authselect_custom_profile }}
              register: result_authselect_custom_profile_present
              changed_when: false
              when:
              - authselect_current_profile is not match("custom/")

            - name: 'Limit Password Reuse: system-auth - Create an authselect custom profile
                based on the current profile'
              ansible.builtin.command:
                cmd: authselect create-profile hardening -b {{ authselect_current_profile
                  }}
              when:
              - result_authselect_check_cmd is success
              - authselect_current_profile is not match("custom/")
              - not result_authselect_custom_profile_present.stat.exists

            - name: 'Limit Password Reuse: system-auth - Ensure authselect changes are
                applied'
              ansible.builtin.command:
                cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
              when:
              - result_authselect_check_cmd is success
              - result_authselect_profile is not skipped
              - authselect_current_profile is not match("custom/")
              - authselect_custom_profile is not match(authselect_current_profile)

            - name: 'Limit Password Reuse: system-auth - Ensure the authselect custom
                profile is selected'
              ansible.builtin.command:
                cmd: authselect select {{ authselect_custom_profile }}
              register: result_pam_authselect_select_profile
              when:
              - result_authselect_check_cmd is success
              - result_authselect_profile is not skipped
              - authselect_current_profile is not match("custom/")
              - authselect_custom_profile is not match(authselect_current_profile)

            - name: 'Limit Password Reuse: system-auth - Restore the authselect features
                in the custom profile'
              ansible.builtin.command:
                cmd: authselect enable-feature {{ item }}
              loop: '{{ result_authselect_features.stdout_lines }}'
              register: result_pam_authselect_restore_features
              when:
              - result_authselect_profile is not skipped
              - result_authselect_features is not skipped
              - result_pam_authselect_select_profile is not skipped

            - name: 'Limit Password Reuse: system-auth - Ensure authselect changes are
                applied'
              ansible.builtin.command:
                cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
              when:
              - result_authselect_check_cmd is success
              - result_authselect_profile is not skipped
              - result_pam_authselect_restore_features is not skipped

            - name: 'Limit Password Reuse: system-auth - Change the PAM file to be edited
                according to the custom authselect profile'
              ansible.builtin.set_fact:
                pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
                  | basename }}
            when:
            - result_authselect_present.stat.exists

          - name: 'Limit Password Reuse: system-auth - Ensure the "remember" option from
              "pam_pwhistory.so" is not present in {{ pam_file_path }}'
            ansible.builtin.replace:
              dest: '{{ pam_file_path }}'
              regexp: (.*password.*pam_pwhistory.so.*)\bremember\b=?[0-9a-zA-Z]*(.*)
              replace: \1\2
            register: result_pam_option_removal

          - name: 'Limit Password Reuse: system-auth - Ensure authselect changes are applied'
            ansible.builtin.command:
              cmd: authselect apply-changes -b
            when:
            - result_authselect_present.stat.exists
            - result_pam_option_removal is changed
          when:
          - result_pam_file_present.stat.exists
      when:
      - '"pam" in ansible_facts.packages'
      - result_pwhistory_conf_check.stat.exists
      tags:
      - CCE-89176-2
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.8
      - NIST-800-53-IA-5(1)(e)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.2.5
      - accounts_password_pam_pwhistory_remember_system_auth
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

    - name: 'Limit Password Reuse: system-auth - pam_pwhistory.so parameters are configured
        in PAM files'
      block:

      - name: 'Limit Password Reuse: system-auth - Define the PAM file to be edited as
          a local fact'
        ansible.builtin.set_fact:
          pam_file_path: /etc/pam.d/system-auth

      - name: 'Limit Password Reuse: system-auth - Check if system relies on authselect
          tool'
        ansible.builtin.stat:
          path: /usr/bin/authselect
        register: result_authselect_present

      - name: 'Limit Password Reuse: system-auth - Ensure authselect custom profile is
          used if authselect is present'
        block:

        - name: 'Limit Password Reuse: system-auth - Check integrity of authselect current
            profile'
          ansible.builtin.command:
            cmd: authselect check
          register: result_authselect_check_cmd
          changed_when: false
          ignore_errors: true

        - name: 'Limit Password Reuse: system-auth - Informative message based on the
            authselect integrity check result'
          ansible.builtin.assert:
            that:
            - result_authselect_check_cmd is success
            fail_msg:
            - authselect integrity check failed. Remediation aborted!
            - This remediation could not be applied because an authselect profile was
              not selected or the selected profile is not intact.
            - It is not recommended to manually edit the PAM files when authselect tool
              is available.
            - In cases where the default authselect profile does not cover a specific
              demand, a custom authselect profile is recommended.
            success_msg:
            - authselect integrity check passed

        - name: 'Limit Password Reuse: system-auth - Get authselect current profile'
          ansible.builtin.shell:
            cmd: authselect current -r | awk '{ print $1 }'
          register: result_authselect_profile
          changed_when: false
          when:
          - result_authselect_check_cmd is success

        - name: 'Limit Password Reuse: system-auth - Define the current authselect profile
            as a local fact'
          ansible.builtin.set_fact:
            authselect_current_profile: '{{ result_authselect_profile.stdout }}'
            authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
          when:
          - result_authselect_profile is not skipped
          - result_authselect_profile.stdout is match("custom/")

        - name: 'Limit Password Reuse: system-auth - Define the new authselect custom
            profile as a local fact'
          ansible.builtin.set_fact:
            authselect_current_profile: '{{ result_authselect_profile.stdout }}'
            authselect_custom_profile: custom/hardening
          when:
          - result_authselect_profile is not skipped
          - result_authselect_profile.stdout is not match("custom/")

        - name: 'Limit Password Reuse: system-auth - Get authselect current features to
            also enable them in the custom profile'
          ansible.builtin.shell:
            cmd: authselect current | tail -n+3 | awk '{ print $2 }'
          register: result_authselect_features
          changed_when: false
          when:
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")

        - name: 'Limit Password Reuse: system-auth - Check if any custom profile with
            the same name was already created'
          ansible.builtin.stat:
            path: /etc/authselect/{{ authselect_custom_profile }}
          register: result_authselect_custom_profile_present
          changed_when: false
          when:
          - authselect_current_profile is not match("custom/")

        - name: 'Limit Password Reuse: system-auth - Create an authselect custom profile
            based on the current profile'
          ansible.builtin.command:
            cmd: authselect create-profile hardening -b {{ authselect_current_profile
              }}
          when:
          - result_authselect_check_cmd is success
          - authselect_current_profile is not match("custom/")
          - not result_authselect_custom_profile_present.stat.exists

        - name: 'Limit Password Reuse: system-auth - Ensure authselect changes are applied'
          ansible.builtin.command:
            cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")
          - authselect_custom_profile is not match(authselect_current_profile)

        - name: 'Limit Password Reuse: system-auth - Ensure the authselect custom profile
            is selected'
          ansible.builtin.command:
            cmd: authselect select {{ authselect_custom_profile }}
          register: result_pam_authselect_select_profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")
          - authselect_custom_profile is not match(authselect_current_profile)

        - name: 'Limit Password Reuse: system-auth - Restore the authselect features in
            the custom profile'
          ansible.builtin.command:
            cmd: authselect enable-feature {{ item }}
          loop: '{{ result_authselect_features.stdout_lines }}'
          register: result_pam_authselect_restore_features
          when:
          - result_authselect_profile is not skipped
          - result_authselect_features is not skipped
          - result_pam_authselect_select_profile is not skipped

        - name: 'Limit Password Reuse: system-auth - Ensure authselect changes are applied'
          ansible.builtin.command:
            cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - result_pam_authselect_restore_features is not skipped

        - name: 'Limit Password Reuse: system-auth - Change the PAM file to be edited
            according to the custom authselect profile'
          ansible.builtin.set_fact:
            pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
              | basename }}
        when:
        - result_authselect_present.stat.exists

      - name: 'Limit Password Reuse: system-auth - Check if expected PAM module line is
          present in {{ pam_file_path }}'
        ansible.builtin.lineinfile:
          path: '{{ pam_file_path }}'
          regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.*
          state: absent
        check_mode: true
        changed_when: false
        register: result_pam_line_present

      - name: 'Limit Password Reuse: system-auth - Include or update the PAM module line
          in {{ pam_file_path }}'
        block:

        - name: 'Limit Password Reuse: system-auth - Check if required PAM module line
            is present in {{ pam_file_path }} with different control'
          ansible.builtin.lineinfile:
            path: '{{ pam_file_path }}'
            regexp: ^\s*password\s+.*\s+pam_pwhistory.so\s*
            state: absent
          check_mode: true
          changed_when: false
          register: result_pam_line_other_control_present

        - name: 'Limit Password Reuse: system-auth - Ensure the correct control for the
            required PAM module line in {{ pam_file_path }}'
          ansible.builtin.replace:
            dest: '{{ pam_file_path }}'
            regexp: ^(\s*password\s+).*(\bpam_pwhistory.so.*)
            replace: \1requisite \2
          register: result_pam_module_edit
          when:
          - result_pam_line_other_control_present.found == 1

        - name: 'Limit Password Reuse: system-auth - Ensure the required PAM module line
            is included in {{ pam_file_path }}'
          ansible.builtin.lineinfile:
            dest: '{{ pam_file_path }}'
            line: password    requisite    pam_pwhistory.so
          register: result_pam_module_add
          when:
          - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found
            > 1

        - name: 'Limit Password Reuse: system-auth - Ensure authselect changes are applied'
          ansible.builtin.command:
            cmd: authselect apply-changes -b
          when: |
            result_authselect_present is defined and result_authselect_present.stat.exists and ((result_pam_module_add is defined and result_pam_module_add.changed) or (result_pam_module_edit is defined and result_pam_module_edit.changed))
        when:
        - result_pam_line_present.found is defined
        - result_pam_line_present.found == 0

      - name: 'Limit Password Reuse: system-auth - Check if the required PAM module option
          is present in {{ pam_file_path }}'
        ansible.builtin.lineinfile:
          path: '{{ pam_file_path }}'
          regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.*\sremember\b
          state: absent
        check_mode: true
        changed_when: false
        register: result_pam_module_remember_option_present

      - name: 'Limit Password Reuse: system-auth - Ensure the "remember" PAM option for
          "pam_pwhistory.so" is included in {{ pam_file_path }}'
        ansible.builtin.lineinfile:
          path: '{{ pam_file_path }}'
          backrefs: true
          regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so.*)
          line: \1 remember={{ var_password_pam_remember }}
          state: present
        register: result_pam_remember_add
        when:
        - result_pam_module_remember_option_present.found == 0

      - name: 'Limit Password Reuse: system-auth - Ensure the required value for "remember"
          PAM option from "pam_pwhistory.so" in {{ pam_file_path }}'
        ansible.builtin.lineinfile:
          path: '{{ pam_file_path }}'
          backrefs: true
          regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*)
          line: \1\2={{ var_password_pam_remember }} \3
        register: result_pam_remember_edit
        when:
        - result_pam_module_remember_option_present.found > 0

      - name: 'Limit Password Reuse: system-auth - Ensure authselect changes are applied'
        ansible.builtin.command:
          cmd: authselect apply-changes -b
        when:
        - result_authselect_present.stat.exists
        - (result_pam_remember_add is defined and result_pam_remember_add.changed) or
          (result_pam_remember_edit is defined and result_pam_remember_edit.changed)
      when:
      - '"pam" in ansible_facts.packages'
      - not result_pwhistory_conf_check.stat.exists
      tags:
      - CCE-89176-2
      - CJIS-5.6.2.1.1
      - NIST-800-171-3.5.8
      - NIST-800-53-IA-5(1)(e)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.2.5
      - accounts_password_pam_pwhistory_remember_system_auth
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-accounts_password_pam_pwhistory_remember_system_auth:def:1

Class:

compliance

Title:

Limit Password Reuse: system-auth

Version:

2

Description:

The passwords to remember should be set correctly.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_password_pam_pwhistory_remember_system_auth:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#package_pam
Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_password_pam_retry
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83569-4

References:

1, 11, 12, 15, 16, 3, 5, 9, 5.5.3, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, CCI-000192, CCI-000366, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.2, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.18.1.4, A.7.1.1, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.2, A.9.4.3, CM-6(a), AC-7(a), IA-5(4), PR.AC-1, PR.AC-6, PR.AC-7, PR.IP-1, FMT_MOF_EXT.1, SRG-OS-000069-GPOS-00037, SRG-OS-000480-GPOS-00227, 5.5.1
Description:
To configure the number of retry prompts that are permitted per-session: Edit the `/etc/security/pwquality.conf` to include `retry=3`, or a lower value if site policy is more restrictive. The DoD requirement is a maximum of 3 prompts per session.
Rationale:

Setting the password retry prompts that are permitted on a per-session basis to a low value requires some software, such as SSH, to re-connect. This can slow down and draw additional attention to some types of password-guessing attacks. Note that this is different from account lockout, which is provided by the pam_faillock module.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q pam; then

    var_password_pam_retry='3'

    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/security/pwquality.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^retry")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$var_password_pam_retry"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^retry\\>" "/etc/security/pwquality.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^retry\\>.*/$escaped_formatted_output/gi" "/etc/security/pwquality.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-83569-4"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/security/pwquality.conf" >> "/etc/security/pwquality.conf"
        printf '%s\n' "$formatted_output" >> "/etc/security/pwquality.conf"
    fi

    		if [ -e "/etc/pam.d/password-auth" ] ; then
        PAM_FILE_PATH="/etc/pam.d/password-auth"
        if [ -f /usr/bin/authselect ]; then

            if ! authselect check; then
            echo "
            authselect integrity check failed. Remediation aborted!
            This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
            It is not recommended to manually edit the PAM files when authselect tool is available.
            In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
            exit 1
            fi

            CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
            # If not already in use, a custom profile is created preserving the enabled features.
            if [[ ! $CURRENT_PROFILE == custom/* ]]; then
                ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
                authselect create-profile hardening -b $CURRENT_PROFILE
                CURRENT_PROFILE="custom/hardening"

                authselect apply-changes -b --backup=before-hardening-custom-profile
                authselect select $CURRENT_PROFILE
                for feature in $ENABLED_FEATURES; do
                    authselect enable-feature $feature;
                done

                authselect apply-changes -b --backup=after-hardening-custom-profile
            fi
            PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth")
            PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"

            authselect apply-changes -b
        fi

    if grep -qP '^\s*password\s+'".*"'\s+pam_pwquality.so\s.*\bretry\b' "$PAM_FILE_PATH"; then
        sed -i -E --follow-symlinks 's/(.*password.*'".*"'.*pam_pwquality.so.*)\sretry=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH"
    fi
        if [ -f /usr/bin/authselect ]; then

            authselect apply-changes -b
        fi
    else
        echo "/etc/pam.d/password-auth was not found" >&2
    fi

    		if [ -e "/etc/pam.d/system-auth" ] ; then
        PAM_FILE_PATH="/etc/pam.d/system-auth"
        if [ -f /usr/bin/authselect ]; then

            if ! authselect check; then
            echo "
            authselect integrity check failed. Remediation aborted!
            This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
            It is not recommended to manually edit the PAM files when authselect tool is available.
            In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
            exit 1
            fi

            CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
            # If not already in use, a custom profile is created preserving the enabled features.
            if [[ ! $CURRENT_PROFILE == custom/* ]]; then
                ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
                authselect create-profile hardening -b $CURRENT_PROFILE
                CURRENT_PROFILE="custom/hardening"

                authselect apply-changes -b --backup=before-hardening-custom-profile
                authselect select $CURRENT_PROFILE
                for feature in $ENABLED_FEATURES; do
                    authselect enable-feature $feature;
                done

                authselect apply-changes -b --backup=after-hardening-custom-profile
            fi
            PAM_FILE_NAME=$(basename "/etc/pam.d/system-auth")
            PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"

            authselect apply-changes -b
        fi

    if grep -qP '^\s*password\s+'".*"'\s+pam_pwquality.so\s.*\bretry\b' "$PAM_FILE_PATH"; then
        sed -i -E --follow-symlinks 's/(.*password.*'".*"'.*pam_pwquality.so.*)\sretry=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH"
    fi
        if [ -f /usr/bin/authselect ]; then

            authselect apply-changes -b
        fi
    else
        echo "/etc/pam.d/system-auth was not found" >&2
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | configure

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-83569-4
      - CJIS-5.5.3
      - NIST-800-53-AC-7(a)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(4)
      - accounts_password_pam_retry
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
    - name: XCCDF Value var_password_pam_retry # promote to variable
      set_fact:
        var_password_pam_retry: !!str 3
      tags:
        - always

    - name: Ensure PAM variable retry is set accordingly
      ansible.builtin.lineinfile:
        create: true
        dest: /etc/security/pwquality.conf
        regexp: ^\s*retry
        line: retry = {{ var_password_pam_retry }}
      when: '"pam" in ansible_facts.packages'
      tags:
      - CCE-83569-4
      - CJIS-5.5.3
      - NIST-800-53-AC-7(a)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(4)
      - accounts_password_pam_retry
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted
        Per-Session - Check if /etc/pam.d/password-auth file is present
      ansible.builtin.stat:
        path: /etc/pam.d/password-auth
      register: result_pam_file_present
      when: '"pam" in ansible_facts.packages'
      tags:
      - CCE-83569-4
      - CJIS-5.5.3
      - NIST-800-53-AC-7(a)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(4)
      - accounts_password_pam_retry
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted
        Per-Session - Check the proper remediation for the system
      block:

      - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
          Permitted Per-Session - Define the PAM file to be edited as a local fact
        ansible.builtin.set_fact:
          pam_file_path: /etc/pam.d/password-auth

      - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
          Permitted Per-Session - Check if system relies on authselect tool
        ansible.builtin.stat:
          path: /usr/bin/authselect
        register: result_authselect_present

      - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
          Permitted Per-Session - Ensure authselect custom profile is used if authselect
          is present
        block:

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Check integrity of authselect current profile
          ansible.builtin.command:
            cmd: authselect check
          register: result_authselect_check_cmd
          changed_when: false
          ignore_errors: true

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Informative message based on the authselect integrity
            check result
          ansible.builtin.assert:
            that:
            - result_authselect_check_cmd is success
            fail_msg:
            - authselect integrity check failed. Remediation aborted!
            - This remediation could not be applied because an authselect profile was
              not selected or the selected profile is not intact.
            - It is not recommended to manually edit the PAM files when authselect tool
              is available.
            - In cases where the default authselect profile does not cover a specific
              demand, a custom authselect profile is recommended.
            success_msg:
            - authselect integrity check passed

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Get authselect current profile
          ansible.builtin.shell:
            cmd: authselect current -r | awk '{ print $1 }'
          register: result_authselect_profile
          changed_when: false
          when:
          - result_authselect_check_cmd is success

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Define the current authselect profile as a local fact
          ansible.builtin.set_fact:
            authselect_current_profile: '{{ result_authselect_profile.stdout }}'
            authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
          when:
          - result_authselect_profile is not skipped
          - result_authselect_profile.stdout is match("custom/")

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Define the new authselect custom profile as a local
            fact
          ansible.builtin.set_fact:
            authselect_current_profile: '{{ result_authselect_profile.stdout }}'
            authselect_custom_profile: custom/hardening
          when:
          - result_authselect_profile is not skipped
          - result_authselect_profile.stdout is not match("custom/")

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Get authselect current features to also enable them
            in the custom profile
          ansible.builtin.shell:
            cmd: authselect current | tail -n+3 | awk '{ print $2 }'
          register: result_authselect_features
          changed_when: false
          when:
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Check if any custom profile with the same name was
            already created
          ansible.builtin.stat:
            path: /etc/authselect/{{ authselect_custom_profile }}
          register: result_authselect_custom_profile_present
          changed_when: false
          when:
          - authselect_current_profile is not match("custom/")

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Create an authselect custom profile based on the current
            profile
          ansible.builtin.command:
            cmd: authselect create-profile hardening -b {{ authselect_current_profile
              }}
          when:
          - result_authselect_check_cmd is success
          - authselect_current_profile is not match("custom/")
          - not result_authselect_custom_profile_present.stat.exists

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Ensure authselect changes are applied
          ansible.builtin.command:
            cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")
          - authselect_custom_profile is not match(authselect_current_profile)

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Ensure the authselect custom profile is selected
          ansible.builtin.command:
            cmd: authselect select {{ authselect_custom_profile }}
          register: result_pam_authselect_select_profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")
          - authselect_custom_profile is not match(authselect_current_profile)

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Restore the authselect features in the custom profile
          ansible.builtin.command:
            cmd: authselect enable-feature {{ item }}
          loop: '{{ result_authselect_features.stdout_lines }}'
          register: result_pam_authselect_restore_features
          when:
          - result_authselect_profile is not skipped
          - result_authselect_features is not skipped
          - result_pam_authselect_select_profile is not skipped

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Ensure authselect changes are applied
          ansible.builtin.command:
            cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - result_pam_authselect_restore_features is not skipped

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Change the PAM file to be edited according to the
            custom authselect profile
          ansible.builtin.set_fact:
            pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
              | basename }}
        when:
        - result_authselect_present.stat.exists

      - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
          Permitted Per-Session - Ensure the "retry" option from "pam_pwquality.so" is
          not present in {{ pam_file_path }}
        ansible.builtin.replace:
          dest: '{{ pam_file_path }}'
          regexp: (.*password.*.*.*pam_pwquality.so.*)\bretry\b=?[0-9a-zA-Z]*(.*)
          replace: \1\2
        register: result_pam_option_removal

      - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
          Permitted Per-Session - Ensure authselect changes are applied
        ansible.builtin.command:
          cmd: authselect apply-changes -b
        when:
        - result_authselect_present.stat.exists
        - result_pam_option_removal is changed
      when:
      - '"pam" in ansible_facts.packages'
      - result_pam_file_present.stat.exists
      tags:
      - CCE-83569-4
      - CJIS-5.5.3
      - NIST-800-53-AC-7(a)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(4)
      - accounts_password_pam_retry
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted
        Per-Session - Check if /etc/pam.d/system-auth file is present
      ansible.builtin.stat:
        path: /etc/pam.d/system-auth
      register: result_pam_file_present
      when: '"pam" in ansible_facts.packages'
      tags:
      - CCE-83569-4
      - CJIS-5.5.3
      - NIST-800-53-AC-7(a)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(4)
      - accounts_password_pam_retry
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted
        Per-Session - Check the proper remediation for the system
      block:

      - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
          Permitted Per-Session - Define the PAM file to be edited as a local fact
        ansible.builtin.set_fact:
          pam_file_path: /etc/pam.d/system-auth

      - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
          Permitted Per-Session - Check if system relies on authselect tool
        ansible.builtin.stat:
          path: /usr/bin/authselect
        register: result_authselect_present

      - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
          Permitted Per-Session - Ensure authselect custom profile is used if authselect
          is present
        block:

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Check integrity of authselect current profile
          ansible.builtin.command:
            cmd: authselect check
          register: result_authselect_check_cmd
          changed_when: false
          ignore_errors: true

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Informative message based on the authselect integrity
            check result
          ansible.builtin.assert:
            that:
            - result_authselect_check_cmd is success
            fail_msg:
            - authselect integrity check failed. Remediation aborted!
            - This remediation could not be applied because an authselect profile was
              not selected or the selected profile is not intact.
            - It is not recommended to manually edit the PAM files when authselect tool
              is available.
            - In cases where the default authselect profile does not cover a specific
              demand, a custom authselect profile is recommended.
            success_msg:
            - authselect integrity check passed

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Get authselect current profile
          ansible.builtin.shell:
            cmd: authselect current -r | awk '{ print $1 }'
          register: result_authselect_profile
          changed_when: false
          when:
          - result_authselect_check_cmd is success

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Define the current authselect profile as a local fact
          ansible.builtin.set_fact:
            authselect_current_profile: '{{ result_authselect_profile.stdout }}'
            authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
          when:
          - result_authselect_profile is not skipped
          - result_authselect_profile.stdout is match("custom/")

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Define the new authselect custom profile as a local
            fact
          ansible.builtin.set_fact:
            authselect_current_profile: '{{ result_authselect_profile.stdout }}'
            authselect_custom_profile: custom/hardening
          when:
          - result_authselect_profile is not skipped
          - result_authselect_profile.stdout is not match("custom/")

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Get authselect current features to also enable them
            in the custom profile
          ansible.builtin.shell:
            cmd: authselect current | tail -n+3 | awk '{ print $2 }'
          register: result_authselect_features
          changed_when: false
          when:
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Check if any custom profile with the same name was
            already created
          ansible.builtin.stat:
            path: /etc/authselect/{{ authselect_custom_profile }}
          register: result_authselect_custom_profile_present
          changed_when: false
          when:
          - authselect_current_profile is not match("custom/")

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Create an authselect custom profile based on the current
            profile
          ansible.builtin.command:
            cmd: authselect create-profile hardening -b {{ authselect_current_profile
              }}
          when:
          - result_authselect_check_cmd is success
          - authselect_current_profile is not match("custom/")
          - not result_authselect_custom_profile_present.stat.exists

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Ensure authselect changes are applied
          ansible.builtin.command:
            cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")
          - authselect_custom_profile is not match(authselect_current_profile)

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Ensure the authselect custom profile is selected
          ansible.builtin.command:
            cmd: authselect select {{ authselect_custom_profile }}
          register: result_pam_authselect_select_profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")
          - authselect_custom_profile is not match(authselect_current_profile)

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Restore the authselect features in the custom profile
          ansible.builtin.command:
            cmd: authselect enable-feature {{ item }}
          loop: '{{ result_authselect_features.stdout_lines }}'
          register: result_pam_authselect_restore_features
          when:
          - result_authselect_profile is not skipped
          - result_authselect_features is not skipped
          - result_pam_authselect_select_profile is not skipped

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Ensure authselect changes are applied
          ansible.builtin.command:
            cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - result_pam_authselect_restore_features is not skipped

        - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
            Permitted Per-Session - Change the PAM file to be edited according to the
            custom authselect profile
          ansible.builtin.set_fact:
            pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
              | basename }}
        when:
        - result_authselect_present.stat.exists

      - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
          Permitted Per-Session - Ensure the "retry" option from "pam_pwquality.so" is
          not present in {{ pam_file_path }}
        ansible.builtin.replace:
          dest: '{{ pam_file_path }}'
          regexp: (.*password.*.*.*pam_pwquality.so.*)\bretry\b=?[0-9a-zA-Z]*(.*)
          replace: \1\2
        register: result_pam_option_removal

      - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
          Permitted Per-Session - Ensure authselect changes are applied
        ansible.builtin.command:
          cmd: authselect apply-changes -b
        when:
        - result_authselect_present.stat.exists
        - result_pam_option_removal is changed
      when:
      - '"pam" in ansible_facts.packages'
      - result_pam_file_present.stat.exists
      tags:
      - CCE-83569-4
      - CJIS-5.5.3
      - NIST-800-53-AC-7(a)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(4)
      - accounts_password_pam_retry
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-accounts_password_pam_retry:def:1

Class:

compliance

Title:

Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session

Version:

2

Description:

The password retry should meet minimum requirements

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_password_pam_retry:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#package_pam
Set Existing Passwords Maximum Age medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_password_set_max_life_existing
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86031-2

References:

CCI-000199, IA-5(f), IA-5(1)(d), CM-6(a), SRG-OS-000076-GPOS-00044, SRG-OS-000076-VMM-000430, 5.6.1.1
Description:
Configure non-compliant accounts to enforce a 365-day maximum password lifetime restriction by running the following command:

    $ sudo chage -M 365 USER

Rationale:

Any password, no matter how complex, can eventually be cracked. Therefore, passwords need to be changed periodically. If the operating system does not limit the lifetime of passwords and force users to change their passwords, there is the risk that the operating system passwords could be compromised.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    var_accounts_maximum_age_login_defs='365'

    while IFS= read -r i; do
        chage -M $var_accounts_maximum_age_login_defs $i
    done <   <(awk -v var="$var_accounts_maximum_age_login_defs" -F: '(/^[^:]+:[^!*]/ && ($5 > var || $5 == "")) {print $1}' /etc/shadow)

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: XCCDF Value var_accounts_maximum_age_login_defs # promote to variable
      set_fact:
        var_accounts_maximum_age_login_defs: !!str 365
      tags:
        - always

    - name: Collect users with not correct maximum time period between password changes
      ansible.builtin.command:
        cmd: awk -F':' '(/^[^:]+:[^!*]/ && ($5 > {{ var_accounts_maximum_age_login_defs
          }} || $5 == "")) {print $1}' /etc/shadow
      register: user_names
      tags:
      - CCE-86031-2
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(1)(d)
      - NIST-800-53-IA-5(f)
      - accounts_password_set_max_life_existing
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Change the maximum time period between password changes
      ansible.builtin.user:
        user: '{{ item }}'
        password_expire_max: '{{ var_accounts_maximum_age_login_defs }}'
      with_items: '{{ user_names.stdout_lines }}'
      when: user_names.stdout_lines | length > 0
      tags:
      - CCE-86031-2
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(1)(d)
      - NIST-800-53-IA-5(f)
      - accounts_password_set_max_life_existing
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-accounts_password_set_max_life_existing:def:1

Class:

compliance

Title:

Set Existing Passwords Maximum Age

Version:

2

Description:

Set Existing Passwords Maximum Age

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_password_set_max_life_existing:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Set Existing Passwords Minimum Age medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_password_set_min_life_existing
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-89069-9

References:

CCI-000198, IA-5(f), IA-5(1)(d), CM-6(a), SRG-OS-000075-GPOS-00043, SRG-OS-000075-VMM000420, 5.6.1.2
Description:
Configure non-compliant accounts to enforce a 24 hours/1 day minimum password lifetime by running the following command:

    $ sudo chage -m 1 USER

Rationale:

Enforcing a minimum password lifetime helps to prevent repeated password changes to defeat the password reuse or history enforcement requirement. If users are allowed to immediately and continually change their password, the password could be repeatedly changed in a short period of time to defeat the organization's policy regarding password reuse.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    var_accounts_minimum_age_login_defs='1'

    while IFS= read -r i; do
        chage -m $var_accounts_minimum_age_login_defs $i
    done <   <(awk -v var="$var_accounts_minimum_age_login_defs" -F: '(/^[^:]+:[^!*]/ && ($4 < var || $4 == "")) {print $1}' /etc/shadow)

OVAL definition:

Definition ID:

oval:ssg-accounts_password_set_min_life_existing:def:1

Class:

compliance

Title:

Set Existing Passwords Minimum Age

Version:

1

Description:

Passwords for existing accounts much satisfy minimum age requirements

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_password_set_min_life_existing:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Set Password Warning Age medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_password_warn_age_login_defs
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83609-8

References:

1, 12, 13, 14, 15, 16, 18, 3, 5, 7, 8, DSS01.03, DSS03.05, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 3.5.8, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 6.2, 0418, 1055, 1402, A.12.4.1, A.12.4.3, A.18.1.4, A.6.1.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, IA-5(f), IA-5(1)(d), CM-6(a), DE.CM-1, DE.CM-3, PR.AC-1, PR.AC-4, PR.AC-6, PR.AC-7, Req-8.3.9, 5.6.1.3
Description:
To specify how many days prior to password expiration that a warning will be issued to users, edit the file `/etc/login.defs` and add or correct the following line:

    PASS_WARN_AGE 7

The DoD requirement is 7. The profile requirement is `7`.
Rationale:

Setting the password warning age enables users to make the change at a practical time.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q shadow-utils; then

    var_accounts_password_warn_age_login_defs='7'

    grep -q ^PASS_WARN_AGE /etc/login.defs && \
    sed -i "s/PASS_WARN_AGE.*/PASS_WARN_AGE\t$var_accounts_password_warn_age_login_defs/g" /etc/login.defs
    if ! [ $? -eq 0 ]
    then
      echo -e "PASS_WARN_AGE\t$var_accounts_password_warn_age_login_defs" >> /etc/login.defs
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-83609-8
      - NIST-800-171-3.5.8
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(1)(d)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.3.9
      - accounts_password_warn_age_login_defs
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
    - name: XCCDF Value var_accounts_password_warn_age_login_defs # promote to variable
      set_fact:
        var_accounts_password_warn_age_login_defs: !!str 7
      tags:
        - always

    - name: Set Password Warning Age
      lineinfile:
        dest: /etc/login.defs
        regexp: ^PASS_WARN_AGE *[0-9]*
        state: present
        line: PASS_WARN_AGE        {{ var_accounts_password_warn_age_login_defs }}
        create: true
      when: '"shadow-utils" in ansible_facts.packages'
      tags:
      - CCE-83609-8
      - NIST-800-171-3.5.8
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(1)(d)
      - NIST-800-53-IA-5(f)
      - PCI-DSS-Req-8.3.9
      - accounts_password_warn_age_login_defs
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-accounts_password_warn_age_login_defs:def:1

Class:

compliance

Title:

Set Password Warning Age

Version:

3

Description:

The password expiration warning age should be set appropriately.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_password_warn_age_login_defs:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#login_defs
Lock Accounts After Failed Password Attempts medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_deny
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83587-6

References:

BP28(R18), 1, 12, 15, 16, 5.5.3, DSS05.04, DSS05.10, DSS06.10, 3.1.8, CCI-000044, CCI-002236, CCI-002237, CCI-002238, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, CM-6(a), AC-7(a), PR.AC-7, FIA_AFL.1, Req-8.1.6, SRG-OS-000329-GPOS-00128, SRG-OS-000021-GPOS-00005, SRG-OS-000021-VMM-000050, 5.4.2, 5.5.2
Description:
This rule configures the system to lock out accounts after a number of incorrect login attempts using `pam_faillock.so`. pam_faillock.so module requires multiple entries in pam files. These entries must be carefully defined to work as expected. In order to avoid errors when manually editing these files, it is recommended to use the appropriate tools, such as `authselect` or `authconfig`, depending on the OS version.
Rationale:

By limiting the number of failed logon attempts, the risk of unauthorized system access via user password guessing, also known as brute-forcing, is reduced. Limits are imposed by locking the account.

Warnings:

General warning
If the system relies on `authselect` tool to manage PAM settings, the remediation will also use `authselect` tool. However, if any manual modification was made in PAM files, the `authselect` integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will be shown in the remediation report. If the system supports the `/etc/security/faillock.conf` file, the pam_faillock parameters should be defined in `faillock.conf` file.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    System was not configured with authselect.

    authselect integrity check failed. Remediation aborted!
    This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
    It is not recommended to manually edit the PAM files when authselect tool is available.
    In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended.

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q pam; then

    var_accounts_passwords_pam_faillock_deny='3'

    if [ -f /usr/bin/authselect ]; then
        if ! authselect check; then
    echo "
    authselect integrity check failed. Remediation aborted!
    This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
    It is not recommended to manually edit the PAM files when authselect tool is available.
    In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
    exit 1
    fi
    authselect enable-feature with-faillock

    authselect apply-changes -b
    else

    AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth")
    for pam_file in "${AUTH_FILES[@]}"
    do
        if ! grep -qE '^\s*auth\s+required\s+pam_faillock\.so\s+(preauth silent|authfail).*$' "$pam_file" ; then
            sed -i --follow-symlinks '/^auth.*sufficient.*pam_unix\.so.*/i auth        required      pam_faillock.so preauth silent' "$pam_file"
            sed -i --follow-symlinks '/^auth.*required.*pam_deny\.so.*/i auth        required      pam_faillock.so authfail' "$pam_file"
            sed -i --follow-symlinks '/^account.*required.*pam_unix\.so.*/i account     required      pam_faillock.so' "$pam_file"
        fi
        sed -Ei 's/(auth.*)(\[default=die\])(.*pam_faillock\.so)/\1required     \3/g' "$pam_file"
    done

    fi

    AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth")

    FAILLOCK_CONF="/etc/security/faillock.conf"
    if [ -f $FAILLOCK_CONF ]; then
        regex="^\s*deny\s*="
        line="deny = $var_accounts_passwords_pam_faillock_deny"
        if ! grep -q $regex $FAILLOCK_CONF; then
            echo $line >> $FAILLOCK_CONF
        else
            sed -i --follow-symlinks 's|^\s*\(deny\s*=\s*\)\(\S\+\)|\1'"$var_accounts_passwords_pam_faillock_deny"'|g' $FAILLOCK_CONF
        fi
        for pam_file in "${AUTH_FILES[@]}"
        do
            if [ -e "$pam_file" ] ; then
                PAM_FILE_PATH="$pam_file"
                if [ -f /usr/bin/authselect ]; then

                    if ! authselect check; then
                    echo "
                    authselect integrity check failed. Remediation aborted!
                    This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
                    It is not recommended to manually edit the PAM files when authselect tool is available.
                    In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
                    exit 1
                    fi

                    CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
                    # If not already in use, a custom profile is created preserving the enabled features.
                    if [[ ! $CURRENT_PROFILE == custom/* ]]; then
                        ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
                        authselect create-profile hardening -b $CURRENT_PROFILE
                        CURRENT_PROFILE="custom/hardening"

                        authselect apply-changes -b --backup=before-hardening-custom-profile
                        authselect select $CURRENT_PROFILE
                        for feature in $ENABLED_FEATURES; do
                            authselect enable-feature $feature;
                        done

                        authselect apply-changes -b --backup=after-hardening-custom-profile
                    fi
                    PAM_FILE_NAME=$(basename "$pam_file")
                    PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"

                    authselect apply-changes -b
                fi

            if grep -qP '^\s*auth\s.*\bpam_faillock.so\s.*\bdeny\b' "$PAM_FILE_PATH"; then
                sed -i -E --follow-symlinks 's/(.*auth.*pam_faillock.so.*)\bdeny\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH"
            fi
                if [ -f /usr/bin/authselect ]; then

                    authselect apply-changes -b
                fi
            else
                echo "$pam_file was not found" >&2
            fi
        done
    else
        for pam_file in "${AUTH_FILES[@]}"
        do
            if ! grep -qE '^\s*auth.*pam_faillock\.so (preauth|authfail).*deny' "$pam_file"; then
                sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*silent.*/ s/$/ deny='"$var_accounts_passwords_pam_faillock_deny"'/' "$pam_file"
                sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*authfail.*/ s/$/ deny='"$var_accounts_passwords_pam_faillock_deny"'/' "$pam_file"
            else
                sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*preauth.*silent.*\)\('"deny"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_deny"'\3/' "$pam_file"
                sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*authfail.*\)\('"deny"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_deny"'\3/' "$pam_file"
            fi
        done
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-83587-6
      - CJIS-5.5.3
      - NIST-800-171-3.1.8
      - NIST-800-53-AC-7(a)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.6
      - accounts_passwords_pam_faillock_deny
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Lock Accounts After Failed Password Attempts - Check if system relies on authselect
        tool
      ansible.builtin.stat:
        path: /usr/bin/authselect
      register: result_authselect_present
      when: '"pam" in ansible_facts.packages'
      tags:
      - CCE-83587-6
      - CJIS-5.5.3
      - NIST-800-171-3.1.8
      - NIST-800-53-AC-7(a)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.6
      - accounts_passwords_pam_faillock_deny
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Lock Accounts After Failed Password Attempts - Remediation where authselect
        tool is present
      block:

      - name: Lock Accounts After Failed Password Attempts - Check integrity of authselect
          current profile
        ansible.builtin.command:
          cmd: authselect check
        register: result_authselect_check_cmd
        changed_when: false
        ignore_errors: true

      - name: Lock Accounts After Failed Password Attempts - Informative message based
          on the authselect integrity check result
        ansible.builtin.assert:
          that:
          - result_authselect_check_cmd is success
          fail_msg:
          - authselect integrity check failed. Remediation aborted!
          - This remediation could not be applied because an authselect profile was not
            selected or the selected profile is not intact.
          - It is not recommended to manually edit the PAM files when authselect tool
            is available.
          - In cases where the default authselect profile does not cover a specific demand,
            a custom authselect profile is recommended.
          success_msg:
          - authselect integrity check passed

      - name: Lock Accounts After Failed Password Attempts - Get authselect current features
        ansible.builtin.shell:
          cmd: authselect current | tail -n+3 | awk '{ print $2 }'
        register: result_authselect_features
        changed_when: false
        when:
        - result_authselect_check_cmd is success

      - name: Lock Accounts After Failed Password Attempts - Ensure "with-faillock" feature
          is enabled using authselect tool
        ansible.builtin.command:
          cmd: authselect enable-feature with-faillock
        register: result_authselect_enable_feature_cmd
        when:
        - result_authselect_check_cmd is success
        - result_authselect_features.stdout is not search("with-faillock")

      - name: Lock Accounts After Failed Password Attempts - Ensure authselect changes
          are applied
        ansible.builtin.command:
          cmd: authselect apply-changes -b
        when:
        - result_authselect_enable_feature_cmd is not skipped
        - result_authselect_enable_feature_cmd is success
      when:
      - '"pam" in ansible_facts.packages'
      - result_authselect_present.stat.exists
      tags:
      - CCE-83587-6
      - CJIS-5.5.3
      - NIST-800-171-3.1.8
      - NIST-800-53-AC-7(a)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.6
      - accounts_passwords_pam_faillock_deny
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Lock Accounts After Failed Password Attempts - Remediation where authselect
        tool is not present
      block:

      - name: Lock Accounts After Failed Password Attempts - Check if pam_faillock.so
          is already enabled
        ansible.builtin.lineinfile:
          path: /etc/pam.d/system-auth
          regexp: .*auth.*pam_faillock\.so (preauth|authfail)
          state: absent
        check_mode: true
        changed_when: false
        register: result_pam_faillock_is_enabled

      - name: Lock Accounts After Failed Password Attempts - Enable pam_faillock.so preauth
          editing PAM files
        ansible.builtin.lineinfile:
          path: '{{ item }}'
          line: auth        required      pam_faillock.so preauth
          insertbefore: ^auth.*sufficient.*pam_unix\.so.*
          state: present
        loop:
        - /etc/pam.d/system-auth
        - /etc/pam.d/password-auth
        when:
        - result_pam_faillock_is_enabled.found == 0

      - name: Lock Accounts After Failed Password Attempts - Enable pam_faillock.so authfail
          editing PAM files
        ansible.builtin.lineinfile:
          path: '{{ item }}'
          line: auth        required      pam_faillock.so authfail
          insertbefore: ^auth.*required.*pam_deny\.so.*
          state: present
        loop:
        - /etc/pam.d/system-auth
        - /etc/pam.d/password-auth
        when:
        - result_pam_faillock_is_enabled.found == 0

      - name: Lock Accounts After Failed Password Attempts - Enable pam_faillock.so account
          section editing PAM files
        ansible.builtin.lineinfile:
          path: '{{ item }}'
          line: account     required      pam_faillock.so
          insertbefore: ^account.*required.*pam_unix\.so.*
          state: present
        loop:
        - /etc/pam.d/system-auth
        - /etc/pam.d/password-auth
        when:
        - result_pam_faillock_is_enabled.found == 0
      when:
      - '"pam" in ansible_facts.packages'
      - not result_authselect_present.stat.exists
      tags:
      - CCE-83587-6
      - CJIS-5.5.3
      - NIST-800-171-3.1.8
      - NIST-800-53-AC-7(a)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.6
      - accounts_passwords_pam_faillock_deny
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
    - name: XCCDF Value var_accounts_passwords_pam_faillock_deny # promote to variable
      set_fact:
        var_accounts_passwords_pam_faillock_deny: !!str 3
      tags:
        - always

    - name: Lock Accounts After Failed Password Attempts - Check the presence of /etc/security/faillock.conf
        file
      ansible.builtin.stat:
        path: /etc/security/faillock.conf
      register: result_faillock_conf_check
      when: '"pam" in ansible_facts.packages'
      tags:
      - CCE-83587-6
      - CJIS-5.5.3
      - NIST-800-171-3.1.8
      - NIST-800-53-AC-7(a)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.6
      - accounts_passwords_pam_faillock_deny
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Lock Accounts After Failed Password Attempts - Ensure the pam_faillock.so
        deny parameter in /etc/security/faillock.conf
      ansible.builtin.lineinfile:
        path: /etc/security/faillock.conf
        regexp: ^\s*deny\s*=
        line: deny = {{ var_accounts_passwords_pam_faillock_deny }}
        state: present
      when:
      - '"pam" in ansible_facts.packages'
      - result_faillock_conf_check.stat.exists
      tags:
      - CCE-83587-6
      - CJIS-5.5.3
      - NIST-800-171-3.1.8
      - NIST-800-53-AC-7(a)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.6
      - accounts_passwords_pam_faillock_deny
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Lock Accounts After Failed Password Attempts - Ensure the pam_faillock.so
        deny parameter not in PAM files
      block:

      - name: Lock Accounts After Failed Password Attempts - Check if /etc/pam.d/system-auth
          file is present
        ansible.builtin.stat:
          path: /etc/pam.d/system-auth
        register: result_pam_file_present

      - name: Lock Accounts After Failed Password Attempts - Check the proper remediation
          for the system
        block:

        - name: Lock Accounts After Failed Password Attempts - Define the PAM file to
            be edited as a local fact
          ansible.builtin.set_fact:
            pam_file_path: /etc/pam.d/system-auth

        - name: Lock Accounts After Failed Password Attempts - Check if system relies
            on authselect tool
          ansible.builtin.stat:
            path: /usr/bin/authselect
          register: result_authselect_present

        - name: Lock Accounts After Failed Password Attempts - Ensure authselect custom
            profile is used if authselect is present
          block:

          - name: Lock Accounts After Failed Password Attempts - Check integrity of authselect
              current profile
            ansible.builtin.command:
              cmd: authselect check
            register: result_authselect_check_cmd
            changed_when: false
            ignore_errors: true

          - name: Lock Accounts After Failed Password Attempts - Informative message based
              on the authselect integrity check result
            ansible.builtin.assert:
              that:
              - result_authselect_check_cmd is success
              fail_msg:
              - authselect integrity check failed. Remediation aborted!
              - This remediation could not be applied because an authselect profile was
                not selected or the selected profile is not intact.
              - It is not recommended to manually edit the PAM files when authselect tool
                is available.
              - In cases where the default authselect profile does not cover a specific
                demand, a custom authselect profile is recommended.
              success_msg:
              - authselect integrity check passed

          - name: Lock Accounts After Failed Password Attempts - Get authselect current
              profile
            ansible.builtin.shell:
              cmd: authselect current -r | awk '{ print $1 }'
            register: result_authselect_profile
            changed_when: false
            when:
            - result_authselect_check_cmd is success

          - name: Lock Accounts After Failed Password Attempts - Define the current authselect
              profile as a local fact
            ansible.builtin.set_fact:
              authselect_current_profile: '{{ result_authselect_profile.stdout }}'
              authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
            when:
            - result_authselect_profile is not skipped
            - result_authselect_profile.stdout is match("custom/")

          - name: Lock Accounts After Failed Password Attempts - Define the new authselect
              custom profile as a local fact
            ansible.builtin.set_fact:
              authselect_current_profile: '{{ result_authselect_profile.stdout }}'
              authselect_custom_profile: custom/hardening
            when:
            - result_authselect_profile is not skipped
            - result_authselect_profile.stdout is not match("custom/")

          - name: Lock Accounts After Failed Password Attempts - Get authselect current
              features to also enable them in the custom profile
            ansible.builtin.shell:
              cmd: authselect current | tail -n+3 | awk '{ print $2 }'
            register: result_authselect_features
            changed_when: false
            when:
            - result_authselect_profile is not skipped
            - authselect_current_profile is not match("custom/")

          - name: Lock Accounts After Failed Password Attempts - Check if any custom profile
              with the same name was already created
            ansible.builtin.stat:
              path: /etc/authselect/{{ authselect_custom_profile }}
            register: result_authselect_custom_profile_present
            changed_when: false
            when:
            - authselect_current_profile is not match("custom/")

          - name: Lock Accounts After Failed Password Attempts - Create an authselect
              custom profile based on the current profile
            ansible.builtin.command:
              cmd: authselect create-profile hardening -b {{ authselect_current_profile
                }}
            when:
            - result_authselect_check_cmd is success
            - authselect_current_profile is not match("custom/")
            - not result_authselect_custom_profile_present.stat.exists

          - name: Lock Accounts After Failed Password Attempts - Ensure authselect changes
              are applied
            ansible.builtin.command:
              cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
            when:
            - result_authselect_check_cmd is success
            - result_authselect_profile is not skipped
            - authselect_current_profile is not match("custom/")
            - authselect_custom_profile is not match(authselect_current_profile)

          - name: Lock Accounts After Failed Password Attempts - Ensure the authselect
              custom profile is selected
            ansible.builtin.command:
              cmd: authselect select {{ authselect_custom_profile }}
            register: result_pam_authselect_select_profile
            when:
            - result_authselect_check_cmd is success
            - result_authselect_profile is not skipped
            - authselect_current_profile is not match("custom/")
            - authselect_custom_profile is not match(authselect_current_profile)

          - name: Lock Accounts After Failed Password Attempts - Restore the authselect
              features in the custom profile
            ansible.builtin.command:
              cmd: authselect enable-feature {{ item }}
            loop: '{{ result_authselect_features.stdout_lines }}'
            register: result_pam_authselect_restore_features
            when:
            - result_authselect_profile is not skipped
            - result_authselect_features is not skipped
            - result_pam_authselect_select_profile is not skipped

          - name: Lock Accounts After Failed Password Attempts - Ensure authselect changes
              are applied
            ansible.builtin.command:
              cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
            when:
            - result_authselect_check_cmd is success
            - result_authselect_profile is not skipped
            - result_pam_authselect_restore_features is not skipped

          - name: Lock Accounts After Failed Password Attempts - Change the PAM file to
              be edited according to the custom authselect profile
            ansible.builtin.set_fact:
              pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
                | basename }}
          when:
          - result_authselect_present.stat.exists

        - name: Lock Accounts After Failed Password Attempts - Ensure the "deny" option
            from "pam_faillock.so" is not present in {{ pam_file_path }}
          ansible.builtin.replace:
            dest: '{{ pam_file_path }}'
            regexp: (.*auth.*pam_faillock.so.*)\bdeny\b=?[0-9a-zA-Z]*(.*)
            replace: \1\2
          register: result_pam_option_removal

        - name: Lock Accounts After Failed Password Attempts - Ensure authselect changes
            are applied
          ansible.builtin.command:
            cmd: authselect apply-changes -b
          when:
          - result_authselect_present.stat.exists
          - result_pam_option_removal is changed
        when:
        - result_pam_file_present.stat.exists

      - name: Lock Accounts After Failed Password Attempts - Check if /etc/pam.d/password-auth
          file is present
        ansible.builtin.stat:
          path: /etc/pam.d/password-auth
        register: result_pam_file_present

      - name: Lock Accounts After Failed Password Attempts - Check the proper remediation
          for the system
        block:

        - name: Lock Accounts After Failed Password Attempts - Define the PAM file to
            be edited as a local fact
          ansible.builtin.set_fact:
            pam_file_path: /etc/pam.d/password-auth

        - name: Lock Accounts After Failed Password Attempts - Check if system relies
            on authselect tool
          ansible.builtin.stat:
            path: /usr/bin/authselect
          register: result_authselect_present

        - name: Lock Accounts After Failed Password Attempts - Ensure authselect custom
            profile is used if authselect is present
          block:

          - name: Lock Accounts After Failed Password Attempts - Check integrity of authselect
              current profile
            ansible.builtin.command:
              cmd: authselect check
            register: result_authselect_check_cmd
            changed_when: false
            ignore_errors: true

          - name: Lock Accounts After Failed Password Attempts - Informative message based
              on the authselect integrity check result
            ansible.builtin.assert:
              that:
              - result_authselect_check_cmd is success
              fail_msg:
              - authselect integrity check failed. Remediation aborted!
              - This remediation could not be applied because an authselect profile was
                not selected or the selected profile is not intact.
              - It is not recommended to manually edit the PAM files when authselect tool
                is available.
              - In cases where the default authselect profile does not cover a specific
                demand, a custom authselect profile is recommended.
              success_msg:
              - authselect integrity check passed

          - name: Lock Accounts After Failed Password Attempts - Get authselect current
              profile
            ansible.builtin.shell:
              cmd: authselect current -r | awk '{ print $1 }'
            register: result_authselect_profile
            changed_when: false
            when:
            - result_authselect_check_cmd is success

          - name: Lock Accounts After Failed Password Attempts - Define the current authselect
              profile as a local fact
            ansible.builtin.set_fact:
              authselect_current_profile: '{{ result_authselect_profile.stdout }}'
              authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
            when:
            - result_authselect_profile is not skipped
            - result_authselect_profile.stdout is match("custom/")

          - name: Lock Accounts After Failed Password Attempts - Define the new authselect
              custom profile as a local fact
            ansible.builtin.set_fact:
              authselect_current_profile: '{{ result_authselect_profile.stdout }}'
              authselect_custom_profile: custom/hardening
            when:
            - result_authselect_profile is not skipped
            - result_authselect_profile.stdout is not match("custom/")

          - name: Lock Accounts After Failed Password Attempts - Get authselect current
              features to also enable them in the custom profile
            ansible.builtin.shell:
              cmd: authselect current | tail -n+3 | awk '{ print $2 }'
            register: result_authselect_features
            changed_when: false
            when:
            - result_authselect_profile is not skipped
            - authselect_current_profile is not match("custom/")

          - name: Lock Accounts After Failed Password Attempts - Check if any custom profile
              with the same name was already created
            ansible.builtin.stat:
              path: /etc/authselect/{{ authselect_custom_profile }}
            register: result_authselect_custom_profile_present
            changed_when: false
            when:
            - authselect_current_profile is not match("custom/")

          - name: Lock Accounts After Failed Password Attempts - Create an authselect
              custom profile based on the current profile
            ansible.builtin.command:
              cmd: authselect create-profile hardening -b {{ authselect_current_profile
                }}
            when:
            - result_authselect_check_cmd is success
            - authselect_current_profile is not match("custom/")
            - not result_authselect_custom_profile_present.stat.exists

          - name: Lock Accounts After Failed Password Attempts - Ensure authselect changes
              are applied
            ansible.builtin.command:
              cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
            when:
            - result_authselect_check_cmd is success
            - result_authselect_profile is not skipped
            - authselect_current_profile is not match("custom/")
            - authselect_custom_profile is not match(authselect_current_profile)

          - name: Lock Accounts After Failed Password Attempts - Ensure the authselect
              custom profile is selected
            ansible.builtin.command:
              cmd: authselect select {{ authselect_custom_profile }}
            register: result_pam_authselect_select_profile
            when:
            - result_authselect_check_cmd is success
            - result_authselect_profile is not skipped
            - authselect_current_profile is not match("custom/")
            - authselect_custom_profile is not match(authselect_current_profile)

          - name: Lock Accounts After Failed Password Attempts - Restore the authselect
              features in the custom profile
            ansible.builtin.command:
              cmd: authselect enable-feature {{ item }}
            loop: '{{ result_authselect_features.stdout_lines }}'
            register: result_pam_authselect_restore_features
            when:
            - result_authselect_profile is not skipped
            - result_authselect_features is not skipped
            - result_pam_authselect_select_profile is not skipped

          - name: Lock Accounts After Failed Password Attempts - Ensure authselect changes
              are applied
            ansible.builtin.command:
              cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
            when:
            - result_authselect_check_cmd is success
            - result_authselect_profile is not skipped
            - result_pam_authselect_restore_features is not skipped

          - name: Lock Accounts After Failed Password Attempts - Change the PAM file to
              be edited according to the custom authselect profile
            ansible.builtin.set_fact:
              pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
                | basename }}
          when:
          - result_authselect_present.stat.exists

        - name: Lock Accounts After Failed Password Attempts - Ensure the "deny" option
            from "pam_faillock.so" is not present in {{ pam_file_path }}
          ansible.builtin.replace:
            dest: '{{ pam_file_path }}'
            regexp: (.*auth.*pam_faillock.so.*)\bdeny\b=?[0-9a-zA-Z]*(.*)
            replace: \1\2
          register: result_pam_option_removal

        - name: Lock Accounts After Failed Password Attempts - Ensure authselect changes
            are applied
          ansible.builtin.command:
            cmd: authselect apply-changes -b
          when:
          - result_authselect_present.stat.exists
          - result_pam_option_removal is changed
        when:
        - result_pam_file_present.stat.exists
      when:
      - '"pam" in ansible_facts.packages'
      - result_faillock_conf_check.stat.exists
      tags:
      - CCE-83587-6
      - CJIS-5.5.3
      - NIST-800-171-3.1.8
      - NIST-800-53-AC-7(a)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.6
      - accounts_passwords_pam_faillock_deny
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Lock Accounts After Failed Password Attempts - Ensure the pam_faillock.so
        deny parameter in PAM files
      block:

      - name: Lock Accounts After Failed Password Attempts - Check if pam_faillock.so
          deny parameter is already enabled in pam files
        ansible.builtin.lineinfile:
          path: /etc/pam.d/system-auth
          regexp: .*auth.*pam_faillock\.so (preauth|authfail).*deny
          state: absent
        check_mode: true
        changed_when: false
        register: result_pam_faillock_deny_parameter_is_present

      - name: Lock Accounts After Failed Password Attempts - Ensure the inclusion of pam_faillock.so
          preauth deny parameter in auth section
        ansible.builtin.lineinfile:
          path: '{{ item }}'
          backrefs: true
          regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so preauth.*)
          line: \1required\3 deny={{ var_accounts_passwords_pam_faillock_deny }}
          state: present
        loop:
        - /etc/pam.d/system-auth
        - /etc/pam.d/password-auth
        when:
        - result_pam_faillock_deny_parameter_is_present.found == 0

      - name: Lock Accounts After Failed Password Attempts - Ensure the inclusion of pam_faillock.so
          authfail deny parameter in auth section
        ansible.builtin.lineinfile:
          path: '{{ item }}'
          backrefs: true
          regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so authfail.*)
          line: \1required\3 deny={{ var_accounts_passwords_pam_faillock_deny }}
          state: present
        loop:
        - /etc/pam.d/system-auth
        - /etc/pam.d/password-auth
        when:
        - result_pam_faillock_deny_parameter_is_present.found == 0

      - name: Lock Accounts After Failed Password Attempts - Ensure the desired value
          for pam_faillock.so preauth deny parameter in auth section
        ansible.builtin.lineinfile:
          path: '{{ item }}'
          backrefs: true
          regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so preauth.*)(deny)=[0-9]+(.*)
          line: \1required\3\4={{ var_accounts_passwords_pam_faillock_deny }}\5
          state: present
        loop:
        - /etc/pam.d/system-auth
        - /etc/pam.d/password-auth
        when:
        - result_pam_faillock_deny_parameter_is_present.found > 0

      - name: Lock Accounts After Failed Password Attempts - Ensure the desired value
          for pam_faillock.so authfail deny parameter in auth section
        ansible.builtin.lineinfile:
          path: '{{ item }}'
          backrefs: true
          regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so authfail.*)(deny)=[0-9]+(.*)
          line: \1required\3\4={{ var_accounts_passwords_pam_faillock_deny }}\5
          state: present
        loop:
        - /etc/pam.d/system-auth
        - /etc/pam.d/password-auth
        when:
        - result_pam_faillock_deny_parameter_is_present.found > 0
      when:
      - '"pam" in ansible_facts.packages'
      - not result_faillock_conf_check.stat.exists
      tags:
      - CCE-83587-6
      - CJIS-5.5.3
      - NIST-800-171-3.1.8
      - NIST-800-53-AC-7(a)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.6
      - accounts_passwords_pam_faillock_deny
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-accounts_passwords_pam_faillock_deny:def:1

Class:

compliance

Title:

Lock Accounts After Failed Password Attempts

Version:

5

Description:

Lockout account after failed login attempts

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_passwords_pam_faillock_deny:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#package_pam
Set Lockout Time for Failed Password Attempts medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_unlock_time
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83588-4

References:

BP28(R18), 1, 12, 15, 16, 5.5.3, DSS05.04, DSS05.10, DSS06.10, 3.1.8, CCI-000044, CCI-002236, CCI-002237, CCI-002238, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, CM-6(a), AC-7(b), PR.AC-7, FIA_AFL.1, Req-8.1.7, SRG-OS-000329-GPOS-00128, SRG-OS-000021-GPOS-00005, SRG-OS-000329-VMM-001180, 5.5.2
Description:
This rule configures the system to lock out accounts during a specified time period after a number of incorrect login attempts using `pam_faillock.so`. pam_faillock.so module requires multiple entries in pam files. These entries must be carefully defined to work as expected. In order to avoid any errors when manually editing these files, it is recommended to use the appropriate tools, such as `authselect` or `authconfig`, depending on the OS version. If `unlock_time` is set to `0`, manual intervention by an administrator is required to unlock a user. This should be done using the `faillock` tool.
Rationale:

By limiting the number of failed logon attempts the risk of unauthorized system access via user password guessing, otherwise known as brute-forcing, is reduced. Limits are imposed by locking the account.

Warnings:

General warning
If the system supports the new `/etc/security/faillock.conf` file but the pam_faillock.so parameters are defined directly in `/etc/pam.d/system-auth` and `/etc/pam.d/password-auth`, the remediation will migrate the `unlock_time` parameter to `/etc/security/faillock.conf` to ensure compatibility with `authselect` tool. The parameters `deny` and `fail_interval`, if used, also have to be migrated by their respective remediation.

General warning
If the system relies on `authselect` tool to manage PAM settings, the remediation will also use `authselect` tool. However, if any manual modification was made in PAM files, the `authselect` integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will be shown in the remediation report. If the system supports the `/etc/security/faillock.conf` file, the pam_faillock parameters should be defined in `faillock.conf` file.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    System was not configured with authselect.

    authselect integrity check failed. Remediation aborted!
    This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
    It is not recommended to manually edit the PAM files when authselect tool is available.
    In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended.

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q pam; then

    var_accounts_passwords_pam_faillock_unlock_time='900'

    if [ -f /usr/bin/authselect ]; then
        if ! authselect check; then
    echo "
    authselect integrity check failed. Remediation aborted!
    This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
    It is not recommended to manually edit the PAM files when authselect tool is available.
    In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
    exit 1
    fi
    authselect enable-feature with-faillock

    authselect apply-changes -b
    else

    AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth")
    for pam_file in "${AUTH_FILES[@]}"
    do
        if ! grep -qE '^\s*auth\s+required\s+pam_faillock\.so\s+(preauth silent|authfail).*$' "$pam_file" ; then
            sed -i --follow-symlinks '/^auth.*sufficient.*pam_unix\.so.*/i auth        required      pam_faillock.so preauth silent' "$pam_file"
            sed -i --follow-symlinks '/^auth.*required.*pam_deny\.so.*/i auth        required      pam_faillock.so authfail' "$pam_file"
            sed -i --follow-symlinks '/^account.*required.*pam_unix\.so.*/i account     required      pam_faillock.so' "$pam_file"
        fi
        sed -Ei 's/(auth.*)(\[default=die\])(.*pam_faillock\.so)/\1required     \3/g' "$pam_file"
    done

    fi

    AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth")

    FAILLOCK_CONF="/etc/security/faillock.conf"
    if [ -f $FAILLOCK_CONF ]; then
        regex="^\s*unlock_time\s*="
        line="unlock_time = $var_accounts_passwords_pam_faillock_unlock_time"
        if ! grep -q $regex $FAILLOCK_CONF; then
            echo $line >> $FAILLOCK_CONF
        else
            sed -i --follow-symlinks 's|^\s*\(unlock_time\s*=\s*\)\(\S\+\)|\1'"$var_accounts_passwords_pam_faillock_unlock_time"'|g' $FAILLOCK_CONF
        fi
        for pam_file in "${AUTH_FILES[@]}"
        do
            if [ -e "$pam_file" ] ; then
                PAM_FILE_PATH="$pam_file"
                if [ -f /usr/bin/authselect ]; then

                    if ! authselect check; then
                    echo "
                    authselect integrity check failed. Remediation aborted!
                    This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
                    It is not recommended to manually edit the PAM files when authselect tool is available.
                    In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
                    exit 1
                    fi

                    CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
                    # If not already in use, a custom profile is created preserving the enabled features.
                    if [[ ! $CURRENT_PROFILE == custom/* ]]; then
                        ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
                        authselect create-profile hardening -b $CURRENT_PROFILE
                        CURRENT_PROFILE="custom/hardening"

                        authselect apply-changes -b --backup=before-hardening-custom-profile
                        authselect select $CURRENT_PROFILE
                        for feature in $ENABLED_FEATURES; do
                            authselect enable-feature $feature;
                        done

                        authselect apply-changes -b --backup=after-hardening-custom-profile
                    fi
                    PAM_FILE_NAME=$(basename "$pam_file")
                    PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"

                    authselect apply-changes -b
                fi

            if grep -qP '^\s*auth\s.*\bpam_faillock.so\s.*\bunlock_time\b' "$PAM_FILE_PATH"; then
                sed -i -E --follow-symlinks 's/(.*auth.*pam_faillock.so.*)\bunlock_time\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH"
            fi
                if [ -f /usr/bin/authselect ]; then

                    authselect apply-changes -b
                fi
            else
                echo "$pam_file was not found" >&2
            fi
        done
    else
        for pam_file in "${AUTH_FILES[@]}"
        do
            if ! grep -qE '^\s*auth.*pam_faillock\.so (preauth|authfail).*unlock_time' "$pam_file"; then
                sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*silent.*/ s/$/ unlock_time='"$var_accounts_passwords_pam_faillock_unlock_time"'/' "$pam_file"
                sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*authfail.*/ s/$/ unlock_time='"$var_accounts_passwords_pam_faillock_unlock_time"'/' "$pam_file"
            else
                sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*preauth.*silent.*\)\('"unlock_time"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_unlock_time"'\3/' "$pam_file"
                sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*authfail.*\)\('"unlock_time"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_unlock_time"'\3/' "$pam_file"
            fi
        done
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-83588-4
      - CJIS-5.5.3
      - NIST-800-171-3.1.8
      - NIST-800-53-AC-7(b)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.7
      - accounts_passwords_pam_faillock_unlock_time
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Set Lockout Time for Failed Password Attempts - Check if system relies on
        authselect tool
      ansible.builtin.stat:
        path: /usr/bin/authselect
      register: result_authselect_present
      when: '"pam" in ansible_facts.packages'
      tags:
      - CCE-83588-4
      - CJIS-5.5.3
      - NIST-800-171-3.1.8
      - NIST-800-53-AC-7(b)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.7
      - accounts_passwords_pam_faillock_unlock_time
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Set Lockout Time for Failed Password Attempts - Remediation where authselect
        tool is present
      block:

      - name: Set Lockout Time for Failed Password Attempts - Check integrity of authselect
          current profile
        ansible.builtin.command:
          cmd: authselect check
        register: result_authselect_check_cmd
        changed_when: false
        ignore_errors: true

      - name: Set Lockout Time for Failed Password Attempts - Informative message based
          on the authselect integrity check result
        ansible.builtin.assert:
          that:
          - result_authselect_check_cmd is success
          fail_msg:
          - authselect integrity check failed. Remediation aborted!
          - This remediation could not be applied because an authselect profile was not
            selected or the selected profile is not intact.
          - It is not recommended to manually edit the PAM files when authselect tool
            is available.
          - In cases where the default authselect profile does not cover a specific demand,
            a custom authselect profile is recommended.
          success_msg:
          - authselect integrity check passed

      - name: Set Lockout Time for Failed Password Attempts - Get authselect current features
        ansible.builtin.shell:
          cmd: authselect current | tail -n+3 | awk '{ print $2 }'
        register: result_authselect_features
        changed_when: false
        when:
        - result_authselect_check_cmd is success

      - name: Set Lockout Time for Failed Password Attempts - Ensure "with-faillock" feature
          is enabled using authselect tool
        ansible.builtin.command:
          cmd: authselect enable-feature with-faillock
        register: result_authselect_enable_feature_cmd
        when:
        - result_authselect_check_cmd is success
        - result_authselect_features.stdout is not search("with-faillock")

      - name: Set Lockout Time for Failed Password Attempts - Ensure authselect changes
          are applied
        ansible.builtin.command:
          cmd: authselect apply-changes -b
        when:
        - result_authselect_enable_feature_cmd is not skipped
        - result_authselect_enable_feature_cmd is success
      when:
      - '"pam" in ansible_facts.packages'
      - result_authselect_present.stat.exists
      tags:
      - CCE-83588-4
      - CJIS-5.5.3
      - NIST-800-171-3.1.8
      - NIST-800-53-AC-7(b)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.7
      - accounts_passwords_pam_faillock_unlock_time
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Set Lockout Time for Failed Password Attempts - Remediation where authselect
        tool is not present
      block:

      - name: Set Lockout Time for Failed Password Attempts - Check if pam_faillock.so
          is already enabled
        ansible.builtin.lineinfile:
          path: /etc/pam.d/system-auth
          regexp: .*auth.*pam_faillock\.so (preauth|authfail)
          state: absent
        check_mode: true
        changed_when: false
        register: result_pam_faillock_is_enabled

      - name: Set Lockout Time for Failed Password Attempts - Enable pam_faillock.so preauth
          editing PAM files
        ansible.builtin.lineinfile:
          path: '{{ item }}'
          line: auth        required      pam_faillock.so preauth
          insertbefore: ^auth.*sufficient.*pam_unix\.so.*
          state: present
        loop:
        - /etc/pam.d/system-auth
        - /etc/pam.d/password-auth
        when:
        - result_pam_faillock_is_enabled.found == 0

      - name: Set Lockout Time for Failed Password Attempts - Enable pam_faillock.so authfail
          editing PAM files
        ansible.builtin.lineinfile:
          path: '{{ item }}'
          line: auth        required      pam_faillock.so authfail
          insertbefore: ^auth.*required.*pam_deny\.so.*
          state: present
        loop:
        - /etc/pam.d/system-auth
        - /etc/pam.d/password-auth
        when:
        - result_pam_faillock_is_enabled.found == 0

      - name: Set Lockout Time for Failed Password Attempts - Enable pam_faillock.so account
          section editing PAM files
        ansible.builtin.lineinfile:
          path: '{{ item }}'
          line: account     required      pam_faillock.so
          insertbefore: ^account.*required.*pam_unix\.so.*
          state: present
        loop:
        - /etc/pam.d/system-auth
        - /etc/pam.d/password-auth
        when:
        - result_pam_faillock_is_enabled.found == 0
      when:
      - '"pam" in ansible_facts.packages'
      - not result_authselect_present.stat.exists
      tags:
      - CCE-83588-4
      - CJIS-5.5.3
      - NIST-800-171-3.1.8
      - NIST-800-53-AC-7(b)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.7
      - accounts_passwords_pam_faillock_unlock_time
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
    - name: XCCDF Value var_accounts_passwords_pam_faillock_unlock_time # promote to variable
      set_fact:
        var_accounts_passwords_pam_faillock_unlock_time: !!str 900
      tags:
        - always

    - name: Set Lockout Time for Failed Password Attempts - Check the presence of /etc/security/faillock.conf
        file
      ansible.builtin.stat:
        path: /etc/security/faillock.conf
      register: result_faillock_conf_check
      when: '"pam" in ansible_facts.packages'
      tags:
      - CCE-83588-4
      - CJIS-5.5.3
      - NIST-800-171-3.1.8
      - NIST-800-53-AC-7(b)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.7
      - accounts_passwords_pam_faillock_unlock_time
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Set Lockout Time for Failed Password Attempts - Ensure the pam_faillock.so
        unlock_time parameter in /etc/security/faillock.conf
      ansible.builtin.lineinfile:
        path: /etc/security/faillock.conf
        regexp: ^\s*unlock_time\s*=
        line: unlock_time = {{ var_accounts_passwords_pam_faillock_unlock_time }}
        state: present
      when:
      - '"pam" in ansible_facts.packages'
      - result_faillock_conf_check.stat.exists
      tags:
      - CCE-83588-4
      - CJIS-5.5.3
      - NIST-800-171-3.1.8
      - NIST-800-53-AC-7(b)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.7
      - accounts_passwords_pam_faillock_unlock_time
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Set Lockout Time for Failed Password Attempts - Ensure the pam_faillock.so
        unlock_time parameter not in PAM files
      block:

      - name: Set Lockout Time for Failed Password Attempts - Check if /etc/pam.d/system-auth
          file is present
        ansible.builtin.stat:
          path: /etc/pam.d/system-auth
        register: result_pam_file_present

      - name: Set Lockout Time for Failed Password Attempts - Check the proper remediation
          for the system
        block:

        - name: Set Lockout Time for Failed Password Attempts - Define the PAM file to
            be edited as a local fact
          ansible.builtin.set_fact:
            pam_file_path: /etc/pam.d/system-auth

        - name: Set Lockout Time for Failed Password Attempts - Check if system relies
            on authselect tool
          ansible.builtin.stat:
            path: /usr/bin/authselect
          register: result_authselect_present

        - name: Set Lockout Time for Failed Password Attempts - Ensure authselect custom
            profile is used if authselect is present
          block:

          - name: Set Lockout Time for Failed Password Attempts - Check integrity of authselect
              current profile
            ansible.builtin.command:
              cmd: authselect check
            register: result_authselect_check_cmd
            changed_when: false
            ignore_errors: true

          - name: Set Lockout Time for Failed Password Attempts - Informative message
              based on the authselect integrity check result
            ansible.builtin.assert:
              that:
              - result_authselect_check_cmd is success
              fail_msg:
              - authselect integrity check failed. Remediation aborted!
              - This remediation could not be applied because an authselect profile was
                not selected or the selected profile is not intact.
              - It is not recommended to manually edit the PAM files when authselect tool
                is available.
              - In cases where the default authselect profile does not cover a specific
                demand, a custom authselect profile is recommended.
              success_msg:
              - authselect integrity check passed

          - name: Set Lockout Time for Failed Password Attempts - Get authselect current
              profile
            ansible.builtin.shell:
              cmd: authselect current -r | awk '{ print $1 }'
            register: result_authselect_profile
            changed_when: false
            when:
            - result_authselect_check_cmd is success

          - name: Set Lockout Time for Failed Password Attempts - Define the current authselect
              profile as a local fact
            ansible.builtin.set_fact:
              authselect_current_profile: '{{ result_authselect_profile.stdout }}'
              authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
            when:
            - result_authselect_profile is not skipped
            - result_authselect_profile.stdout is match("custom/")

          - name: Set Lockout Time for Failed Password Attempts - Define the new authselect
              custom profile as a local fact
            ansible.builtin.set_fact:
              authselect_current_profile: '{{ result_authselect_profile.stdout }}'
              authselect_custom_profile: custom/hardening
            when:
            - result_authselect_profile is not skipped
            - result_authselect_profile.stdout is not match("custom/")

          - name: Set Lockout Time for Failed Password Attempts - Get authselect current
              features to also enable them in the custom profile
            ansible.builtin.shell:
              cmd: authselect current | tail -n+3 | awk '{ print $2 }'
            register: result_authselect_features
            changed_when: false
            when:
            - result_authselect_profile is not skipped
            - authselect_current_profile is not match("custom/")

          - name: Set Lockout Time for Failed Password Attempts - Check if any custom
              profile with the same name was already created
            ansible.builtin.stat:
              path: /etc/authselect/{{ authselect_custom_profile }}
            register: result_authselect_custom_profile_present
            changed_when: false
            when:
            - authselect_current_profile is not match("custom/")

          - name: Set Lockout Time for Failed Password Attempts - Create an authselect
              custom profile based on the current profile
            ansible.builtin.command:
              cmd: authselect create-profile hardening -b {{ authselect_current_profile
                }}
            when:
            - result_authselect_check_cmd is success
            - authselect_current_profile is not match("custom/")
            - not result_authselect_custom_profile_present.stat.exists

          - name: Set Lockout Time for Failed Password Attempts - Ensure authselect changes
              are applied
            ansible.builtin.command:
              cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
            when:
            - result_authselect_check_cmd is success
            - result_authselect_profile is not skipped
            - authselect_current_profile is not match("custom/")
            - authselect_custom_profile is not match(authselect_current_profile)

          - name: Set Lockout Time for Failed Password Attempts - Ensure the authselect
              custom profile is selected
            ansible.builtin.command:
              cmd: authselect select {{ authselect_custom_profile }}
            register: result_pam_authselect_select_profile
            when:
            - result_authselect_check_cmd is success
            - result_authselect_profile is not skipped
            - authselect_current_profile is not match("custom/")
            - authselect_custom_profile is not match(authselect_current_profile)

          - name: Set Lockout Time for Failed Password Attempts - Restore the authselect
              features in the custom profile
            ansible.builtin.command:
              cmd: authselect enable-feature {{ item }}
            loop: '{{ result_authselect_features.stdout_lines }}'
            register: result_pam_authselect_restore_features
            when:
            - result_authselect_profile is not skipped
            - result_authselect_features is not skipped
            - result_pam_authselect_select_profile is not skipped

          - name: Set Lockout Time for Failed Password Attempts - Ensure authselect changes
              are applied
            ansible.builtin.command:
              cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
            when:
            - result_authselect_check_cmd is success
            - result_authselect_profile is not skipped
            - result_pam_authselect_restore_features is not skipped

          - name: Set Lockout Time for Failed Password Attempts - Change the PAM file
              to be edited according to the custom authselect profile
            ansible.builtin.set_fact:
              pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
                | basename }}
          when:
          - result_authselect_present.stat.exists

        - name: Set Lockout Time for Failed Password Attempts - Ensure the "unlock_time"
            option from "pam_faillock.so" is not present in {{ pam_file_path }}
          ansible.builtin.replace:
            dest: '{{ pam_file_path }}'
            regexp: (.*auth.*pam_faillock.so.*)\bunlock_time\b=?[0-9a-zA-Z]*(.*)
            replace: \1\2
          register: result_pam_option_removal

        - name: Set Lockout Time for Failed Password Attempts - Ensure authselect changes
            are applied
          ansible.builtin.command:
            cmd: authselect apply-changes -b
          when:
          - result_authselect_present.stat.exists
          - result_pam_option_removal is changed
        when:
        - result_pam_file_present.stat.exists

      - name: Set Lockout Time for Failed Password Attempts - Check if /etc/pam.d/password-auth
          file is present
        ansible.builtin.stat:
          path: /etc/pam.d/password-auth
        register: result_pam_file_present

      - name: Set Lockout Time for Failed Password Attempts - Check the proper remediation
          for the system
        block:

        - name: Set Lockout Time for Failed Password Attempts - Define the PAM file to
            be edited as a local fact
          ansible.builtin.set_fact:
            pam_file_path: /etc/pam.d/password-auth

        - name: Set Lockout Time for Failed Password Attempts - Check if system relies
            on authselect tool
          ansible.builtin.stat:
            path: /usr/bin/authselect
          register: result_authselect_present

        - name: Set Lockout Time for Failed Password Attempts - Ensure authselect custom
            profile is used if authselect is present
          block:

          - name: Set Lockout Time for Failed Password Attempts - Check integrity of authselect
              current profile
            ansible.builtin.command:
              cmd: authselect check
            register: result_authselect_check_cmd
            changed_when: false
            ignore_errors: true

          - name: Set Lockout Time for Failed Password Attempts - Informative message
              based on the authselect integrity check result
            ansible.builtin.assert:
              that:
              - result_authselect_check_cmd is success
              fail_msg:
              - authselect integrity check failed. Remediation aborted!
              - This remediation could not be applied because an authselect profile was
                not selected or the selected profile is not intact.
              - It is not recommended to manually edit the PAM files when authselect tool
                is available.
              - In cases where the default authselect profile does not cover a specific
                demand, a custom authselect profile is recommended.
              success_msg:
              - authselect integrity check passed

          - name: Set Lockout Time for Failed Password Attempts - Get authselect current
              profile
            ansible.builtin.shell:
              cmd: authselect current -r | awk '{ print $1 }'
            register: result_authselect_profile
            changed_when: false
            when:
            - result_authselect_check_cmd is success

          - name: Set Lockout Time for Failed Password Attempts - Define the current authselect
              profile as a local fact
            ansible.builtin.set_fact:
              authselect_current_profile: '{{ result_authselect_profile.stdout }}'
              authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
            when:
            - result_authselect_profile is not skipped
            - result_authselect_profile.stdout is match("custom/")

          - name: Set Lockout Time for Failed Password Attempts - Define the new authselect
              custom profile as a local fact
            ansible.builtin.set_fact:
              authselect_current_profile: '{{ result_authselect_profile.stdout }}'
              authselect_custom_profile: custom/hardening
            when:
            - result_authselect_profile is not skipped
            - result_authselect_profile.stdout is not match("custom/")

          - name: Set Lockout Time for Failed Password Attempts - Get authselect current
              features to also enable them in the custom profile
            ansible.builtin.shell:
              cmd: authselect current | tail -n+3 | awk '{ print $2 }'
            register: result_authselect_features
            changed_when: false
            when:
            - result_authselect_profile is not skipped
            - authselect_current_profile is not match("custom/")

          - name: Set Lockout Time for Failed Password Attempts - Check if any custom
              profile with the same name was already created
            ansible.builtin.stat:
              path: /etc/authselect/{{ authselect_custom_profile }}
            register: result_authselect_custom_profile_present
            changed_when: false
            when:
            - authselect_current_profile is not match("custom/")

          - name: Set Lockout Time for Failed Password Attempts - Create an authselect
              custom profile based on the current profile
            ansible.builtin.command:
              cmd: authselect create-profile hardening -b {{ authselect_current_profile
                }}
            when:
            - result_authselect_check_cmd is success
            - authselect_current_profile is not match("custom/")
            - not result_authselect_custom_profile_present.stat.exists

          - name: Set Lockout Time for Failed Password Attempts - Ensure authselect changes
              are applied
            ansible.builtin.command:
              cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
            when:
            - result_authselect_check_cmd is success
            - result_authselect_profile is not skipped
            - authselect_current_profile is not match("custom/")
            - authselect_custom_profile is not match(authselect_current_profile)

          - name: Set Lockout Time for Failed Password Attempts - Ensure the authselect
              custom profile is selected
            ansible.builtin.command:
              cmd: authselect select {{ authselect_custom_profile }}
            register: result_pam_authselect_select_profile
            when:
            - result_authselect_check_cmd is success
            - result_authselect_profile is not skipped
            - authselect_current_profile is not match("custom/")
            - authselect_custom_profile is not match(authselect_current_profile)

          - name: Set Lockout Time for Failed Password Attempts - Restore the authselect
              features in the custom profile
            ansible.builtin.command:
              cmd: authselect enable-feature {{ item }}
            loop: '{{ result_authselect_features.stdout_lines }}'
            register: result_pam_authselect_restore_features
            when:
            - result_authselect_profile is not skipped
            - result_authselect_features is not skipped
            - result_pam_authselect_select_profile is not skipped

          - name: Set Lockout Time for Failed Password Attempts - Ensure authselect changes
              are applied
            ansible.builtin.command:
              cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
            when:
            - result_authselect_check_cmd is success
            - result_authselect_profile is not skipped
            - result_pam_authselect_restore_features is not skipped

          - name: Set Lockout Time for Failed Password Attempts - Change the PAM file
              to be edited according to the custom authselect profile
            ansible.builtin.set_fact:
              pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
                | basename }}
          when:
          - result_authselect_present.stat.exists

        - name: Set Lockout Time for Failed Password Attempts - Ensure the "unlock_time"
            option from "pam_faillock.so" is not present in {{ pam_file_path }}
          ansible.builtin.replace:
            dest: '{{ pam_file_path }}'
            regexp: (.*auth.*pam_faillock.so.*)\bunlock_time\b=?[0-9a-zA-Z]*(.*)
            replace: \1\2
          register: result_pam_option_removal

        - name: Set Lockout Time for Failed Password Attempts - Ensure authselect changes
            are applied
          ansible.builtin.command:
            cmd: authselect apply-changes -b
          when:
          - result_authselect_present.stat.exists
          - result_pam_option_removal is changed
        when:
        - result_pam_file_present.stat.exists
      when:
      - '"pam" in ansible_facts.packages'
      - result_faillock_conf_check.stat.exists
      tags:
      - CCE-83588-4
      - CJIS-5.5.3
      - NIST-800-171-3.1.8
      - NIST-800-53-AC-7(b)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.7
      - accounts_passwords_pam_faillock_unlock_time
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Set Lockout Time for Failed Password Attempts - Ensure the pam_faillock.so
        unlock_time parameter in PAM files
      block:

      - name: Set Lockout Time for Failed Password Attempts - Check if pam_faillock.so
          unlock_time parameter is already enabled in pam files
        ansible.builtin.lineinfile:
          path: /etc/pam.d/system-auth
          regexp: .*auth.*pam_faillock\.so (preauth|authfail).*unlock_time
          state: absent
        check_mode: true
        changed_when: false
        register: result_pam_faillock_unlock_time_parameter_is_present

      - name: Set Lockout Time for Failed Password Attempts - Ensure the inclusion of
          pam_faillock.so preauth unlock_time parameter in auth section
        ansible.builtin.lineinfile:
          path: '{{ item }}'
          backrefs: true
          regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so preauth.*)
          line: \1required\3 unlock_time={{ var_accounts_passwords_pam_faillock_unlock_time
            }}
          state: present
        loop:
        - /etc/pam.d/system-auth
        - /etc/pam.d/password-auth
        when:
        - result_pam_faillock_unlock_time_parameter_is_present.found == 0

      - name: Set Lockout Time for Failed Password Attempts - Ensure the inclusion of
          pam_faillock.so authfail unlock_time parameter in auth section
        ansible.builtin.lineinfile:
          path: '{{ item }}'
          backrefs: true
          regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so authfail.*)
          line: \1required\3 unlock_time={{ var_accounts_passwords_pam_faillock_unlock_time
            }}
          state: present
        loop:
        - /etc/pam.d/system-auth
        - /etc/pam.d/password-auth
        when:
        - result_pam_faillock_unlock_time_parameter_is_present.found == 0

      - name: Set Lockout Time for Failed Password Attempts - Ensure the desired value
          for pam_faillock.so preauth unlock_time parameter in auth section
        ansible.builtin.lineinfile:
          path: '{{ item }}'
          backrefs: true
          regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so preauth.*)(unlock_time)=[0-9]+(.*)
          line: \1required\3\4={{ var_accounts_passwords_pam_faillock_unlock_time }}\5
          state: present
        loop:
        - /etc/pam.d/system-auth
        - /etc/pam.d/password-auth
        when:
        - result_pam_faillock_unlock_time_parameter_is_present.found > 0

      - name: Set Lockout Time for Failed Password Attempts - Ensure the desired value
          for pam_faillock.so authfail unlock_time parameter in auth section
        ansible.builtin.lineinfile:
          path: '{{ item }}'
          backrefs: true
          regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so authfail.*)(unlock_time)=[0-9]+(.*)
          line: \1required\3\4={{ var_accounts_passwords_pam_faillock_unlock_time }}\5
          state: present
        loop:
        - /etc/pam.d/system-auth
        - /etc/pam.d/password-auth
        when:
        - result_pam_faillock_unlock_time_parameter_is_present.found > 0
      when:
      - '"pam" in ansible_facts.packages'
      - not result_faillock_conf_check.stat.exists
      tags:
      - CCE-83588-4
      - CJIS-5.5.3
      - NIST-800-171-3.1.8
      - NIST-800-53-AC-7(b)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.7
      - accounts_passwords_pam_faillock_unlock_time
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-accounts_passwords_pam_faillock_unlock_time:def:1

Class:

compliance

Title:

Set Lockout Time for Failed Password Attempts

Version:

3

Description:

The unlock time after number of failed logins should be set correctly.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_passwords_pam_faillock_unlock_time:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#package_pam
Verify Root Has A Primary GID 0 high pass

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_root_gid_zero
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

high

Identifiers:

CCE-86298-7

References:

Req-8.2.1, 5.6.4
Description:
The `root` user should have a primary group of 0.
Rationale:

To help ensure that root-owned files are not inadvertently exposed to other users.

OVAL definition:

Definition ID:

oval:ssg-accounts_root_gid_zero:def:1

Class:

compliance

Title:

Verify Root Has A Primary GID 0

Version:

1

Description:

The root account should have primary group of 0

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_root_gid_zero:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Ensure that Root's Path Does Not Include World or Group-Writable Directories medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_root_path_dirs_no_write
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:49+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83643-7

References:

11, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, CCI-000366, 4.3.4.3.2, 4.3.4.3.3, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, CM-6(a), CM-6(a), PR.IP-1, 6.2.8
Description:
For each element in root's path, run:

    # ls -ld DIR

and ensure that write permissions are disabled for group and other.
Rationale:

Such entries increase the risk that root could execute code provided by unprivileged users, and potentially malicious code.

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | restrict

    - name: Print error message if user is not root
      fail:
        msg: Root account required to read root $PATH
      when: ansible_env.USER != "root"
      ignore_errors: true
      tags:
      - CCE-83643-7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-6(a)
      - accounts_root_path_dirs_no_write
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Get root paths which are not symbolic links
      stat:
        path: '{{ item }}'
      changed_when: false
      failed_when: false
      register: root_paths
      with_items: '{{ ansible_env.PATH.split('':'') }}'
      when: ansible_env.USER == "root"
      tags:
      - CCE-83643-7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-6(a)
      - accounts_root_path_dirs_no_write
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Disable writability to root directories
      file:
        path: '{{ item.item }}'
        mode: g-w,o-w
      with_items: '{{ root_paths.results }}'
      when:
      - root_paths.results is defined
      - item.stat.exists
      - not item.stat.islnk
      tags:
      - CCE-83643-7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-6(a)
      - accounts_root_path_dirs_no_write
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-accounts_root_path_dirs_no_write:def:1

Class:

compliance

Title:

Ensure that Root's Path Does Not Include World or Group-Writable Directories

Version:

2

Description:

Check each directory in root's path and make use it does not grant write permission to group and other

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_root_path_dirs_no_write:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Set Interactive Session Timeout medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_tmout
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:16+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83633-8

References:

BP28(R29), 1, 12, 15, 16, DSS05.04, DSS05.10, DSS06.10, 3.1.11, CCI-000057, CCI-001133, CCI-002361, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, CIP-004-6 R2.2.3, CIP-007-3 R5.1, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, AC-12, SC-10, AC-2(5), CM-6(a), PR.AC-7, FMT_MOF_EXT.1, Req-8.6.1, SRG-OS-000163-GPOS-00072, SRG-OS-000029-GPOS-00010, SRG-OS-000163-VMM-000700, SRG-OS-000279-VMM-001010, 5.6.3
Description:
Setting the `TMOUT` option in `/etc/profile` ensures that all user sessions will terminate based on inactivity. The value of TMOUT should be exported and read only. The `TMOUT` setting in a file loaded by `/etc/profile`, e.g. `/etc/profile.d/tmout.sh` should read as follows:

    declare -xr TMOUT=900

Rationale:

Terminating an idle session within a short time period reduces the window of opportunity for unauthorized personnel to take control of a management session enabled on the console or console port that has been left unattended.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    /tmp/oscap.Lc9Ciq/fix-XXv1kGJB: line 20: /etc/profile.d/tmout.sh: Permission denied
    /tmp/oscap.Lc9Ciq/fix-XXv1kGJB: line 21: /etc/profile.d/tmout.sh: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    var_accounts_tmout='900'

    # if 0, no occurence of tmout found, if 1, occurence found
    tmout_found=0

    for f in /etc/profile /etc/profile.d/*.sh; do

        if grep --silent '^[^#].*TMOUT' $f; then
            sed -i -E "s/^(.*)TMOUT\s*=\s*(\w|\$)*(.*)$/declare -xr TMOUT=$var_accounts_tmout\3/g" $f
            tmout_found=1
        fi
    done

    if [ $tmout_found -eq 0 ]; then
            echo -e "\n# Set TMOUT to $var_accounts_tmout per security requirements" >> /etc/profile.d/tmout.sh
            echo "declare -xr TMOUT=$var_accounts_tmout" >> /etc/profile.d/tmout.sh
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: XCCDF Value var_accounts_tmout # promote to variable
      set_fact:
        var_accounts_tmout: !!str 900
      tags:
        - always

    - name: Correct any occurrence of TMOUT in /etc/profile
      replace:
        path: /etc/profile
        regexp: ^[^#].*TMOUT=.*
        replace: declare -xr TMOUT={{ var_accounts_tmout }}
      register: profile_replaced
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83633-8
      - NIST-800-171-3.1.11
      - NIST-800-53-AC-12
      - NIST-800-53-AC-2(5)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-SC-10
      - PCI-DSS-Req-8.6.1
      - accounts_tmout
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Set Interactive Session Timeout
      lineinfile:
        path: /etc/profile.d/tmout.sh
        create: true
        regexp: TMOUT=
        line: declare -xr TMOUT={{ var_accounts_tmout }}
        state: present
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83633-8
      - NIST-800-171-3.1.11
      - NIST-800-53-AC-12
      - NIST-800-53-AC-2(5)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-SC-10
      - PCI-DSS-Req-8.6.1
      - accounts_tmout
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-accounts_tmout:def:1

Class:

compliance

Title:

Set Interactive Session Timeout

Version:

3

Description:

Checks interactive shell timeout

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_tmout:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Ensure the Default Bash Umask is Set Correctly medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_umask_etc_bashrc
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:16+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83644-5

References:

BP28(R35), 18, APO13.01, BAI03.01, BAI03.02, BAI03.03, CCI-000366, 4.3.4.3.3, A.14.1.1, A.14.2.1, A.14.2.5, A.6.1.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, AC-6(1), CM-6(a), PR.IP-2, Req-8.6.1, SRG-OS-000480-GPOS-00228, SRG-OS-000480-GPOS-00227, 5.6.5
Description:
To ensure the default umask for users of the Bash shell is set properly, add or correct the `umask` setting in `/etc/bashrc` to read as follows:

    umask 027

Rationale:

The umask value influences the permissions assigned to files when they are created. A misconfigured umask value could result in files with excessive permissions that can be read or written to by unauthorized users.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    sed: couldn't open temporary file /etc/sedt4rn5j: Permission denied
    /tmp/oscap.slTDgi/fix-XXcqRUlD: line 12: /etc/bashrc: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    var_accounts_user_umask='027'

    grep -q "^\s*umask" /etc/bashrc && \
      sed -i -E -e "s/^(\s*umask).*/\1 $var_accounts_user_umask/g" /etc/bashrc
    if ! [ $? -eq 0 ]; then
        echo "umask $var_accounts_user_umask" >> /etc/bashrc
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: XCCDF Value var_accounts_user_umask # promote to variable
      set_fact:
        var_accounts_user_umask: !!str 027
      tags:
        - always

    - name: Check if umask in /etc/bashrc is already set
      ansible.builtin.lineinfile:
        path: /etc/bashrc
        regexp: ^(\s*)umask\s+.*
        state: absent
      check_mode: true
      changed_when: false
      register: umask_replace
      tags:
      - CCE-83644-5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.6.1
      - accounts_umask_etc_bashrc
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Replace user umask in /etc/bashrc
      ansible.builtin.replace:
        path: /etc/bashrc
        regexp: ^(\s*)umask(\s+).*
        replace: \g<1>umask\g<2>{{ var_accounts_user_umask }}
      when: umask_replace.found > 0
      tags:
      - CCE-83644-5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.6.1
      - accounts_umask_etc_bashrc
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Ensure the Default umask is Appended Correctly
      ansible.builtin.lineinfile:
        create: true
        path: /etc/bashrc
        line: umask {{ var_accounts_user_umask }}
      when: umask_replace.found == 0
      tags:
      - CCE-83644-5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.6.1
      - accounts_umask_etc_bashrc
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-accounts_umask_etc_bashrc:def:1

Class:

compliance

Title:

Ensure the Default Bash Umask is Set Correctly

Version:

2

Description:

The default umask for users of the bash shell

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_umask_etc_bashrc:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Ensure the Default Umask is Set Correctly in login.defs medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_umask_etc_login_defs
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:16+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83647-8

References:

BP28(R35), 11, 18, 3, 9, APO13.01, BAI03.01, BAI03.02, BAI03.03, BAI10.01, BAI10.02, BAI10.03, BAI10.05, CCI-000366, 4.3.4.3.2, 4.3.4.3.3, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.1.1, A.14.2.1, A.14.2.2, A.14.2.3, A.14.2.4, A.14.2.5, A.6.1.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, AC-6(1), CM-6(a), PR.IP-1, PR.IP-2, Req-8.6.1, SRG-OS-000480-GPOS-00228, 5.6.5
Description:
To ensure the default umask controlled by `/etc/login.defs` is set properly, add or correct the `UMASK` setting in `/etc/login.defs` to read as follows:

    UMASK 027

Rationale:

The umask value influences the permissions assigned to files when they are created. A misconfigured umask value could result in files with excessive permissions that can be read and written to by unauthorized users.

Messages:

Message: Message:

    Fix execution completed and returned: 4

Message: Message:

    sed: couldn't open temporary file /etc/sedzsFhrR: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q shadow-utils; then

    var_accounts_user_umask='027'

    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/login.defs"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^UMASK")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s %s" "$stripped_key" "$var_accounts_user_umask"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^UMASK\\>" "/etc/login.defs"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^UMASK\\>.*/$escaped_formatted_output/gi" "/etc/login.defs"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-83647-8"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/login.defs" >> "/etc/login.defs"
        printf '%s\n' "$formatted_output" >> "/etc/login.defs"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-83647-8
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.6.1
      - accounts_umask_etc_login_defs
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
    - name: XCCDF Value var_accounts_user_umask # promote to variable
      set_fact:
        var_accounts_user_umask: !!str 027
      tags:
        - always

    - name: Check if UMASK is already set
      ansible.builtin.lineinfile:
        path: /etc/login.defs
        regexp: ^(\s*)UMASK\s+.*
        state: absent
      check_mode: true
      changed_when: false
      register: result_umask_is_set
      when: '"shadow-utils" in ansible_facts.packages'
      tags:
      - CCE-83647-8
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.6.1
      - accounts_umask_etc_login_defs
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Replace user UMASK in /etc/login.defs
      ansible.builtin.replace:
        path: /etc/login.defs
        regexp: ^(\s*)UMASK(\s+).*
        replace: \g<1>UMASK\g<2>{{ var_accounts_user_umask }}
      when:
      - '"shadow-utils" in ansible_facts.packages'
      - result_umask_is_set.found > 0
      tags:
      - CCE-83647-8
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.6.1
      - accounts_umask_etc_login_defs
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Ensure the Default UMASK is Appended Correctly
      ansible.builtin.lineinfile:
        create: true
        path: /etc/login.defs
        line: UMASK {{ var_accounts_user_umask }}
      when:
      - '"shadow-utils" in ansible_facts.packages'
      - result_umask_is_set.found == 0
      tags:
      - CCE-83647-8
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.6.1
      - accounts_umask_etc_login_defs
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-accounts_umask_etc_login_defs:def:1

Class:

compliance

Title:

Ensure the Default Umask is Set Correctly in login.defs

Version:

2

Description:

The default umask for all users specified in /etc/login.defs

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_umask_etc_login_defs:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#login_defs
Ensure the Default Umask is Set Correctly in /etc/profile medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_umask_etc_profile
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:16+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90828-5

References:

BP28(R35), 18, APO13.01, BAI03.01, BAI03.02, BAI03.03, CCI-000366, 4.3.4.3.3, A.14.1.1, A.14.2.1, A.14.2.5, A.6.1.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, AC-6(1), CM-6(a), PR.IP-2, Req-8.6.1, SRG-OS-000480-GPOS-00228, SRG-OS-000480-GPOS-00227, 5.6.5
Description:
To ensure the default umask controlled by `/etc/profile` is set properly, add or correct the `umask` setting in `/etc/profile` to read as follows:

    umask 027

Rationale:

The umask value influences the permissions assigned to files when they are created. A misconfigured umask value could result in files with excessive permissions that can be read or written to by unauthorized users.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    /tmp/oscap.FHOShJ/fix-XXJ3IMI5: line 8: /etc/profile: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    var_accounts_user_umask='027'

    grep -qE '^[^#]*umask' /etc/profile && \
      sed -i "s/umask.*/umask $var_accounts_user_umask/g" /etc/profile
    if ! [ $? -eq 0 ]; then
        echo "umask $var_accounts_user_umask" >> /etc/profile
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: XCCDF Value var_accounts_user_umask # promote to variable
      set_fact:
        var_accounts_user_umask: !!str 027
      tags:
        - always

    - name: Check if umask is already set
      ansible.builtin.lineinfile:
        path: /etc/profile
        regexp: (^[\s]*umask)\s+(\d+)
        state: absent
      check_mode: true
      changed_when: false
      register: result_umask_is_set
      tags:
      - CCE-90828-5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.6.1
      - accounts_umask_etc_profile
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Replace user umask in /etc/profile
      ansible.builtin.replace:
        path: /etc/profile
        regexp: ^(\s*)umask\s+\d+
        replace: \1umask {{ var_accounts_user_umask }}
      tags:
      - CCE-90828-5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.6.1
      - accounts_umask_etc_profile
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Append user umask in /etc/profile
      ansible.builtin.lineinfile:
        create: true
        path: /etc/profile
        line: umask {{ var_accounts_user_umask }}
      when: result_umask_is_set.found == 0
      tags:
      - CCE-90828-5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.6.1
      - accounts_umask_etc_profile
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-accounts_umask_etc_profile:def:1

Class:

compliance

Title:

Ensure the Default Umask is Set Correctly in /etc/profile

Version:

2

Description:

The default umask for all users should be set correctly

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_umask_etc_profile:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
User Initialization Files Must Not Run World-Writable Programs medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_user_dot_no_world_writable_programs
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:49+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-87451-1

References:

CCI-000366, SRG-OS-000480-GPOS-00227, 6.2.16
Description:
Set the mode on files being executed by the user initialization files with the following command:

    $ sudo chmod o-w FILE

Rationale:

If user start-up files execute world-writable programs, especially in unprotected directories, they could be maliciously modified to destroy user files or otherwise compromise the system at the user level. If the system is compromised at the user level, it is easier to elevate privileges to eventually compromise the system at the root and network level.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    readarray -t world_writable_files < <(find / -xdev -type f -perm -0002 2> /dev/null)
    readarray -t interactive_home_dirs < <(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $6 }' /etc/passwd)

    for world_writable in "${world_writable_files[@]}"; do
        for homedir in "${interactive_home_dirs[@]}"; do
            if grep -q -d skip "$world_writable" "$homedir"/.*; then
                chmod o-w $world_writable
                break
            fi
        done
    done

OVAL definition:

Definition ID:

oval:ssg-accounts_user_dot_no_world_writable_programs:def:1

Class:

compliance

Title:

User Initialization Files Must Not Run World-Writable Programs

Version:

1

Description:

User Initialization Files Must Not Execute World-Writable Programs

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_user_dot_no_world_writable_programs:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
All Interactive Users Home Directories Must Exist medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_accounts_user_interactive_home_directory_exists
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:49+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83639-5

References:

CCI-000366, SRG-OS-000480-GPOS-00227, 6.2.10
Description:
Create home directories to all interactive users that currently do not have a home directory assigned. Use the following commands to create the user home directory assigned in `/etc/passwd`:

    $ sudo mkdir /home/USER

Rationale:

If a local interactive user has a home directory defined that does not exist, the user may be given access to the / directory as the current working directory upon logon. This could create a Denial of Service because the user would not be able to access their logon configuration files, and it may give them visibility to system files they normally would not be able to access.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    for user in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $1}' /etc/passwd); do
        mkhomedir_helper $user 0077;
    done

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Get all local users from /etc/passwd
      ansible.builtin.getent:
        database: passwd
        split: ':'
      tags:
      - CCE-83639-5
      - accounts_user_interactive_home_directory_exists
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Create local_users variable from the getent output
      ansible.builtin.set_fact:
        local_users: '{{ ansible_facts.getent_passwd|dict2items }}'
      tags:
      - CCE-83639-5
      - accounts_user_interactive_home_directory_exists
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Ensure interactive users have a home directory exists
      ansible.builtin.user:
        name: '{{ item.key }}'
        create_home: true
      loop: '{{ local_users }}'
      when:
      - item.value[2]|int >= 1000
      - item.value[2]|int != 65534
      tags:
      - CCE-83639-5
      - accounts_user_interactive_home_directory_exists
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-accounts_user_interactive_home_directory_exists:def:1

Class:

compliance

Title:

All Interactive Users Home Directories Must Exist

Version:

1

Description:

All Interactive Users Home Directories Must Exist

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-accounts_user_interactive_home_directory_exists:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Build and Test AIDE Database medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_aide_build_database
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:14+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83438-2

References:

BP28(R51), 1, 11, 12, 13, 14, 15, 16, 2, 3, 5, 7, 8, 9, 5.10.1.3, APO01.06, BAI01.06, BAI02.01, BAI03.05, BAI06.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS03.05, DSS04.07, DSS05.02, DSS05.03, DSS05.05, DSS05.07, DSS06.02, DSS06.06, 4.3.4.3.2, 4.3.4.3.3, 4.3.4.4.4, SR 3.1, SR 3.3, SR 3.4, SR 3.8, SR 4.1, SR 6.2, SR 7.6, A.11.2.4, A.12.1.2, A.12.2.1, A.12.4.1, A.12.5.1, A.12.6.2, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.14.2.7, A.15.2.1, A.8.2.3, CM-6(a), DE.CM-1, DE.CM-7, PR.DS-1, PR.DS-6, PR.DS-8, PR.IP-1, PR.IP-3, Req-11.5, SRG-OS-000445-GPOS-00199, 1.3.1
Description:
Run the following command to generate a new database:

    $ sudo /usr/sbin/aide --init

By default, the database will be written to the file `/var/lib/aide/aide.db.new.gz`. Storing the database, the configuration file `/etc/aide.conf`, and the binary `/usr/sbin/aide` (or hashes of these files), in a secure location (such as on read-only media) provides additional assurance about their integrity. The newly-generated database can be installed as follows:

    $ sudo cp /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz

To initiate a manual check, run the following command:

    $ sudo /usr/sbin/aide --check

If this check produces any unexpected output, investigate.
Rationale:

For AIDE to be effective, an initial database of "known-good" information about files must be captured and it should be able to be verified against the installed files.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    Not root, Subscription Management repositories not updated
    Error: This command has to be run with superuser privileges (under the root user on most systems).
    /tmp/oscap.rmV9OF/fix-XXxhPG6N: line 8: /usr/sbin/aide: No such file or directory
    /bin/cp: cannot stat '/var/lib/aide/aide.db.new.gz': No such file or directory

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    if ! rpm -q --quiet "aide" ; then
        dnf install -y "aide"
    fi

    /usr/sbin/aide --init
    /bin/cp -p /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Ensure AIDE is installed
      package:
        name: '{{ item }}'
        state: present
      with_items:
      - aide
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83438-2
      - CJIS-5.10.1.3
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-11.5
      - aide_build_database
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Build and Test AIDE Database
      command: /usr/sbin/aide --init
      changed_when: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83438-2
      - CJIS-5.10.1.3
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-11.5
      - aide_build_database
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Check whether the stock AIDE Database exists
      stat:
        path: /var/lib/aide/aide.db.new.gz
      register: aide_database_stat
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83438-2
      - CJIS-5.10.1.3
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-11.5
      - aide_build_database
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Stage AIDE Database
      copy:
        src: /var/lib/aide/aide.db.new.gz
        dest: /var/lib/aide/aide.db.gz
        backup: true
        remote_src: true
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - (aide_database_stat.stat.exists is defined and aide_database_stat.stat.exists)
      tags:
      - CCE-83438-2
      - CJIS-5.10.1.3
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-11.5
      - aide_build_database
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-aide_build_database:def:1

Class:

compliance

Title:

Build and Test AIDE Database

Version:

2

Description:

The aide database must be initialized.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-aide_build_database:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Configure Periodic Execution of AIDE medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_aide_periodic_cron_checking
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83437-4

References:

BP28(R51), 1, 11, 12, 13, 14, 15, 16, 2, 3, 5, 7, 8, 9, 5.10.1.3, APO01.06, BAI01.06, BAI02.01, BAI03.05, BAI06.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS03.05, DSS04.07, DSS05.02, DSS05.03, DSS05.05, DSS05.07, DSS06.02, DSS06.06, CCI-001744, CCI-002699, CCI-002702, 4.3.4.3.2, 4.3.4.3.3, 4.3.4.4.4, SR 3.1, SR 3.3, SR 3.4, SR 3.8, SR 4.1, SR 6.2, SR 7.6, A.11.2.4, A.12.1.2, A.12.2.1, A.12.4.1, A.12.5.1, A.12.6.2, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.14.2.7, A.15.2.1, A.8.2.3, SI-7, SI-7(1), CM-6(a), DE.CM-1, DE.CM-7, PR.DS-1, PR.DS-6, PR.DS-8, PR.IP-1, PR.IP-3, Req-11.5, SRG-OS-000363-GPOS-00150, SRG-OS-000446-GPOS-00200, SRG-OS-000447-GPOS-00201, 1.3.2
Description:
At a minimum, AIDE should be configured to run a weekly scan. To implement a daily execution of AIDE at 4:05am using cron, add the following line to `/etc/crontab`:

    05 4 * * * root /usr/sbin/aide --check

To implement a weekly execution of AIDE at 4:05am using cron, add the following line to `/etc/crontab`:

    05 4 * * 0 root /usr/sbin/aide --check

AIDE can be executed periodically through other means; this is merely one example. The usage of cron's special time codes, such as `@daily` and `@weekly` is acceptable.
Rationale:

By default, AIDE does not install itself for periodic execution. Periodically running AIDE is necessary to reveal unexpected changes in installed files.
Unauthorized changes to the baseline configuration could make the system vulnerable to various attacks or allow unauthorized access to the operating system. Changes to operating system configurations can have unintended side effects, some of which may be relevant to security.
Detecting such changes and providing an automated response can help avoid unintended, negative consequences that could ultimately affect the security state of the operating system. The operating system's Information Management Officer (IMO)/Information System Security Officer (ISSO) and System Administrators (SAs) must be notified via email and/or monitoring system trap when there is an unauthorized modification of a configuration item.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    Not root, Subscription Management repositories not updated
    Error: This command has to be run with superuser privileges (under the root user on most systems).
    /tmp/oscap.WLwrHQ/fix-XX3ybefr: line 9: /etc/crontab: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    if ! rpm -q --quiet "aide" ; then
        dnf install -y "aide"
    fi

    if ! grep -q "/usr/sbin/aide --check" /etc/crontab ; then
        echo "05 4 * * * root /usr/sbin/aide --check" >> /etc/crontab
    else
        sed -i '\!^.* --check.*$!d' /etc/crontab
        echo "05 4 * * * root /usr/sbin/aide --check" >> /etc/crontab
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Ensure AIDE is installed
      package:
        name: '{{ item }}'
        state: present
      with_items:
      - aide
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83437-4
      - CJIS-5.10.1.3
      - NIST-800-53-CM-6(a)
      - NIST-800-53-SI-7
      - NIST-800-53-SI-7(1)
      - PCI-DSS-Req-11.5
      - aide_periodic_cron_checking
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Set cron package name - RedHat
      set_fact:
        cron_pkg_name: cronie
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - ansible_os_family == "RedHat" or ansible_os_family == "Suse"
      tags:
      - CCE-83437-4
      - CJIS-5.10.1.3
      - NIST-800-53-CM-6(a)
      - NIST-800-53-SI-7
      - NIST-800-53-SI-7(1)
      - PCI-DSS-Req-11.5
      - aide_periodic_cron_checking
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Set cron package name - Debian
      set_fact:
        cron_pkg_name: cron
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - ansible_os_family == "Debian"
      tags:
      - CCE-83437-4
      - CJIS-5.10.1.3
      - NIST-800-53-CM-6(a)
      - NIST-800-53-SI-7
      - NIST-800-53-SI-7(1)
      - PCI-DSS-Req-11.5
      - aide_periodic_cron_checking
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Install cron
      package:
        name: '{{ cron_pkg_name }}'
        state: present
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83437-4
      - CJIS-5.10.1.3
      - NIST-800-53-CM-6(a)
      - NIST-800-53-SI-7
      - NIST-800-53-SI-7(1)
      - PCI-DSS-Req-11.5
      - aide_periodic_cron_checking
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Configure Periodic Execution of AIDE
      cron:
        name: run AIDE check
        minute: 5
        hour: 4
        weekday: 0
        user: root
        job: /usr/sbin/aide --check
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83437-4
      - CJIS-5.10.1.3
      - NIST-800-53-CM-6(a)
      - NIST-800-53-SI-7
      - NIST-800-53-SI-7(1)
      - PCI-DSS-Req-11.5
      - aide_periodic_cron_checking
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-aide_periodic_cron_checking:def:1

Class:

compliance

Title:

Configure Periodic Execution of AIDE

Version:

3

Description:

By default, AIDE does not install itself for periodic execution. Periodically running AIDE is necessary to reveal unexpected changes in installed files.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-aide_periodic_cron_checking:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Modify the System Login Banner medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_banner_etc_issue
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83557-9

References:

1, 12, 15, 16, DSS05.04, DSS05.10, DSS06.10, 3.1.9, CCI-000048, CCI-000050, CCI-001384, CCI-001385, CCI-001386, CCI-001387, CCI-001388, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, AC-8(a), AC-8(c), PR.AC-7, FMT_MOF_EXT.1, SRG-OS-000023-GPOS-00006, SRG-OS-000228-GPOS-00088, SRG-OS-000023-VMM-000060, SRG-OS-000024-VMM-000070, 1.7.2
Description:
To configure the system login banner edit `/etc/issue`. Replace the default text with a message compliant with the local site policy or a legal disclaimer. The DoD required text is either:
`You are accessing a U.S. Government (USG) Information System (IS) that is provided for USG-authorized use only. By using this IS (which includes any device attached to this IS), you consent to the following conditions:
-The USG routinely intercepts and monitors communications on this IS for purposes including, but not limited to, penetration testing, COMSEC monitoring, network operations and defense, personnel misconduct (PM), law enforcement (LE), and counterintelligence (CI) investigations.
-At any time, the USG may inspect and seize data stored on this IS.
-Communications using, or data stored on, this IS are not private, are subject to routine monitoring, interception, and search, and may be disclosed or used for any USG-authorized purpose.
-This IS includes security measures (e.g., authentication and access controls) to protect USG interests -- not for your personal benefit or privacy.
-Notwithstanding the above, using this IS does not constitute consent to PM, LE or CI investigative searching or monitoring of the content of privileged communications, or work product, related to personal representation or services by attorneys, psychotherapists, or clergy, and their assistants. Such communications and work product are private and confidential. See User Agreement for details.`
OR:
`I've read & consent to terms in IS user agreem't.`
Rationale:

Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance.
System use notifications are required only for access via login interfaces with human users and are not required when such human interfaces do not exist.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    /tmp/oscap.BIzasT/fix-XXorZwQT: line 21: /etc/issue: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    login_banner_text='^(Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.|^(?!.*(\\|fedora|rhel|sle|ubuntu)).*)$'

    # Multiple regexes transform the banner regex into a usable banner
    # 0 - Remove anchors around the banner text
    login_banner_text=$(echo "$login_banner_text" | sed 's/^\^\(.*\)\$$/\1/g')
    # 1 - Keep only the first banners if there are multiple
    #    (dod_banners contains the long and short banner)
    login_banner_text=$(echo "$login_banner_text" | sed 's/^(\(.*\.\)|.*)$/\1/g')
    # 2 - Add spaces ' '. (Transforms regex for "space or newline" into a " ")
    login_banner_text=$(echo "$login_banner_text" | sed 's/\[\\s\\n\]+/ /g')
    # 3 - Adds newlines. (Transforms "(?:\[\\n\]+|(?:\\n)+)" into "\n")
    login_banner_text=$(echo "$login_banner_text" | sed 's/(?:\[\\n\]+|(?:\\\\n)+)/\n/g')
    # 4 - Remove any leftover backslash. (From any parethesis in the banner, for example).
    login_banner_text=$(echo "$login_banner_text" | sed 's/\\//g')
    formatted=$(echo "$login_banner_text" | fold -sw 80)

    cat <<EOF >/etc/issue
    $formatted
    EOF

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | unknown

    - name: XCCDF Value login_banner_text # promote to variable
      set_fact:
        login_banner_text: !!str ^(Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.|^(?!.*(\\|fedora|rhel|sle|ubuntu)).*)$
      tags:
        - always

    - name: Modify the System Login Banner - ensure correct banner
      copy:
        dest: /etc/issue
        content: '{{ login_banner_text | regex_replace("^\^(.*)\$$", "\1") | regex_replace("^\((.*\.)\|.*\)$",
          "\1") | regex_replace("\[\\s\\n\]\+"," ") | regex_replace("\(\?:\[\\n\]\+\|\(\?:\\\\n\)\+\)",
          "\n") | regex_replace("\\", "") | wordwrap() }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83557-9
      - NIST-800-171-3.1.9
      - NIST-800-53-AC-8(a)
      - NIST-800-53-AC-8(c)
      - banner_etc_issue
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

OVAL definition:

Definition ID:

oval:ssg-banner_etc_issue:def:1

Class:

compliance

Title:

Modify the System Login Banner

Version:

2

Description:

The system login banner text should be set correctly.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-banner_etc_issue:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Modify the System Login Banner for Remote Connections medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_banner_etc_issue_net
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86148-4

References:

CCI-000048, CCI-001384, CCI-001385, CCI-001386, CCI-001387, CCI-001388, SRG-OS-000023-GPOS-00006, SRG-OS-000228-GPOS-00088, 1.7.3
Description:
To configure the system login banner edit `/etc/issue.net`. Replace the default text with a message compliant with the local site policy or a legal disclaimer. The DoD required text is either:
`You are accessing a U.S. Government (USG) Information System (IS) that is provided for USG-authorized use only. By using this IS (which includes any device attached to this IS), you consent to the following conditions:
-The USG routinely intercepts and monitors communications on this IS for purposes including, but not limited to, penetration testing, COMSEC monitoring, network operations and defense, personnel misconduct (PM), law enforcement (LE), and counterintelligence (CI) investigations.
-At any time, the USG may inspect and seize data stored on this IS.
-Communications using, or data stored on, this IS are not private, are subject to routine monitoring, interception, and search, and may be disclosed or used for any USG-authorized purpose.
-This IS includes security measures (e.g., authentication and access controls) to protect USG interests -- not for your personal benefit or privacy.
-Notwithstanding the above, using this IS does not constitute consent to PM, LE or CI investigative searching or monitoring of the content of privileged communications, or work product, related to personal representation or services by attorneys, psychotherapists, or clergy, and their assistants. Such communications and work product are private and confidential. See User Agreement for details.`
OR:
`I've read & consent to terms in IS user agreem't.`
Rationale:

Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance.
System use notifications are required only for access via login interfaces with human users and are not required when such human interfaces do not exist.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    /tmp/oscap.WFoMtu/fix-XXbGfTLG: line 21: /etc/issue.net: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    login_banner_text='^(Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.|^(?!.*(\\|fedora|rhel|sle|ubuntu)).*)$'

    # Multiple regexes transform the banner regex into a usable banner
    # 0 - Remove anchors around the banner text
    login_banner_text=$(echo "$login_banner_text" | sed 's/^\^\(.*\)\$$/\1/g')
    # 1 - Keep only the first banners if there are multiple
    #    (dod_banners contains the long and short banner)
    login_banner_text=$(echo "$login_banner_text" | sed 's/^(\(.*\.\)|.*)$/\1/g')
    # 2 - Add spaces ' '. (Transforms regex for "space or newline" into a " ")
    login_banner_text=$(echo "$login_banner_text" | sed 's/\[\\s\\n\]+/ /g')
    # 3 - Adds newlines. (Transforms "(?:\[\\n\]+|(?:\\n)+)" into "\n")
    login_banner_text=$(echo "$login_banner_text" | sed 's/(?:\[\\n\]+|(?:\\\\n)+)/\n/g')
    # 4 - Remove any leftover backslash. (From any parethesis in the banner, for example).
    login_banner_text=$(echo "$login_banner_text" | sed 's/\\//g')
    formatted=$(echo "$login_banner_text" | fold -sw 80)

    cat <<EOF >/etc/issue.net
    $formatted
    EOF

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | unknown

    - name: XCCDF Value login_banner_text # promote to variable
      set_fact:
        login_banner_text: !!str ^(Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.|^(?!.*(\\|fedora|rhel|sle|ubuntu)).*)$
      tags:
        - always

    - name: Modify the System Login Banner for Remote Connections - ensure correct banner
      copy:
        dest: /etc/issue.net
        content: '{{ login_banner_text | regex_replace("^\^(.*)\$$", "\1") | regex_replace("^\((.*\.)\|.*\)$",
          "\1") | regex_replace("\[\\s\\n\]\+"," ") | regex_replace("\(\?:\[\\n\]\+\|\(\?:\\\\n\)\+\)",
          "\n") | regex_replace("\\", "") | wordwrap() }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-86148-4
      - banner_etc_issue_net
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

OVAL definition:

Definition ID:

oval:ssg-banner_etc_issue_net:def:1

Class:

compliance

Title:

Modify the System Login Banner for Remote Connections

Version:

2

Description:

The system login banner text should be set correctly.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-banner_etc_issue_net:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Modify the System Message of the Day Banner medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_banner_etc_motd
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83559-5

References:

1.7.1
Description:
To configure the system message banner edit `/etc/motd`. Replace the default text with a message compliant with the local site policy or a legal disclaimer. The DoD required text is either:
`You are accessing a U.S. Government (USG) Information System (IS) that is provided for USG-authorized use only. By using this IS (which includes any device attached to this IS), you consent to the following conditions:
-The USG routinely intercepts and monitors communications on this IS for purposes including, but not limited to, penetration testing, COMSEC monitoring, network operations and defense, personnel misconduct (PM), law enforcement (LE), and counterintelligence (CI) investigations.
-At any time, the USG may inspect and seize data stored on this IS.
-Communications using, or data stored on, this IS are not private, are subject to routine monitoring, interception, and search, and may be disclosed or used for any USG-authorized purpose.
-This IS includes security measures (e.g., authentication and access controls) to protect USG interests -- not for your personal benefit or privacy.
-Notwithstanding the above, using this IS does not constitute consent to PM, LE or CI investigative searching or monitoring of the content of privileged communications, or work product, related to personal representation or services by attorneys, psychotherapists, or clergy, and their assistants. Such communications and work product are private and confidential. See User Agreement for details.`
OR:
`I've read & consent to terms in IS user agreem't.`
Rationale:

Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance.
System use notifications are required only for access via login interfaces with human users and are not required when such human interfaces do not exist.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    login_banner_text='^(Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.|^(?!.*(\\|fedora|rhel|sle|ubuntu)).*)$'

    # Multiple regexes transform the banner regex into a usable banner
    # 0 - Remove anchors around the banner text
    login_banner_text=$(echo "$login_banner_text" | sed 's/^\^\(.*\)\$$/\1/g')
    # 1 - Keep only the first banners if there are multiple
    #    (dod_banners contains the long and short banner)
    login_banner_text=$(echo "$login_banner_text" | sed 's/^(\(.*\.\)|.*)$/\1/g')
    # 2 - Add spaces ' '. (Transforms regex for "space or newline" into a " ")
    login_banner_text=$(echo "$login_banner_text" | sed 's/\[\\s\\n\]+/ /g')
    # 3 - Adds newlines. (Transforms "(?:\[\\n\]+|(?:\\n)+)" into "\n")
    login_banner_text=$(echo "$login_banner_text" | sed 's/(?:\[\\n\]+|(?:\\\\n)+)/\n/g')
    # 4 - Remove any leftover backslash. (From any parethesis in the banner, for example).
    login_banner_text=$(echo "$login_banner_text" | sed 's/\\//g')
    formatted=$(echo "$login_banner_text" | fold -sw 80)

    cat <<EOF >/etc/motd
    $formatted
    EOF

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | unknown

    - name: XCCDF Value login_banner_text # promote to variable
      set_fact:
        login_banner_text: !!str ^(Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.|^(?!.*(\\|fedora|rhel|sle|ubuntu)).*)$
      tags:
        - always

    - name: Modify the System Message of the Day Banner - ensure correct banner
      copy:
        dest: /etc/motd
        content: '{{ login_banner_text | regex_replace("^\^(.*)\$$", "\1") | regex_replace("^\((.*\.)\|.*\)$",
          "\1") | regex_replace("\[\\s\\n\]\+"," ") | regex_replace("\(\?:\[\\n\]\+\|\(\?:\\\\n\)\+\)",
          "\n") | regex_replace("\\", "") | wordwrap() }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83559-5
      - banner_etc_motd
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

OVAL definition:

Definition ID:

oval:ssg-banner_etc_motd:def:1

Class:

compliance

Title:

Modify the System Message of the Day Banner

Version:

2

Description:

The system login banner text should be set correctly.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-banner_etc_motd:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Ensure that chronyd is running under chrony user account medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_chronyd_run_as_chrony_user
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84108-0

References:

2.1.2
Description:
chrony is a daemon which implements the Network Time Protocol (NTP). It is designed to synchronize system clocks across a variety of systems and use a source that is highly accurate. More information on chrony can be found at http://chrony.tuxfamily.org/. Chrony can be configured to be a client and/or a server. To ensure that chronyd is running under chrony user account, remove any `-u ...` option from `OPTIONS` other than `-u chrony`, as chrony is run under its own user by default. This recommendation only applies if chrony is in use on the system.
Rationale:

If chrony is in use on the system proper configuration is vital to ensuring time synchronization is working properly.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q chrony; }; then

    if grep -q 'OPTIONS=.*' /etc/sysconfig/chronyd; then
    	# trying to solve cases where the parameter after OPTIONS
    	#may or may not be enclosed in quotes
    	sed -i -E -e 's/\s*-u\s*\w+\s*/ /' -e 's/^([\s]*OPTIONS=["]?[^"]*)("?)/\1\2/' /etc/sysconfig/chronyd
    fi

    if grep -q 'OPTIONS=.*' /etc/sysconfig/chronyd; then
    	# trying to solve cases where the parameter after OPTIONS
    	#may or may not be enclosed in quotes
    	sed -i -E -e 's/\s*-u\s*\w+\s*/ /' -e 's/^([\s]*OPTIONS=["]?[^"]*)("?)/\1 -u chrony\2/' /etc/sysconfig/chronyd
    else
    	echo 'OPTIONS="-u chrony"' >> /etc/sysconfig/chronyd
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

OVAL definition:

Definition ID:

oval:ssg-chronyd_run_as_chrony_user:def:1

Class:

compliance

Title:

Ensure that chronyd is running under chrony user account

Version:

1

Description:

Ensure that no other user than chrony is configured to run the chrony service

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-chronyd_run_as_chrony_user:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#package_chrony
A remote time server for Chrony is configured medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_chronyd_specify_remote_server
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84218-7

References:

BP28(R43), CCI-000160, CCI-001891, 0988, 1405, CM-6(a), AU-8(1)(a), Req-10.4.3, 2.1.2
Description:
`Chrony` is a daemon which implements the Network Time Protocol (NTP). It is designed to synchronize system clocks across a variety of systems and use a source that is highly accurate. More information on `chrony` can be found at http://chrony.tuxfamily.org/. `Chrony` can be configured to be a client and/or a server. Add or edit server or pool lines to `/etc/chrony.conf` as appropriate:

    server <remote-server>

Multiple servers may be configured.
Rationale:

If `chrony` is in use on the system proper configuration is vital to ensuring time synchronization is working properly.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q chrony; }; then

    var_multiple_time_servers='0.rhel.pool.ntp.org,1.rhel.pool.ntp.org,2.rhel.pool.ntp.org,3.rhel.pool.ntp.org'

    config_file="/etc/chrony.conf"

    if ! grep -q '^[\s]*(?:server|pool)[\s]+[\w]+' "$config_file" ; then
      if ! grep -q '#[[:space:]]*server' "$config_file" ; then
        for server in $(echo "$var_multiple_time_servers" | tr ',' '\n') ; do
          printf '\nserver %s' "$server" >> "$config_file"
        done
      else
        sed -i 's/#[ \t]*server/server/g' "$config_file"
      fi
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-84218-7
      - NIST-800-53-AU-8(1)(a)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-10.4.3
      - chronyd_specify_remote_server
      - configure_strategy
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
    - name: XCCDF Value var_multiple_time_servers # promote to variable
      set_fact:
        var_multiple_time_servers: !!str 0.rhel.pool.ntp.org,1.rhel.pool.ntp.org,2.rhel.pool.ntp.org,3.rhel.pool.ntp.org
      tags:
        - always

    - name: Detect if chrony is already configured with pools or servers
      find:
        path: /etc
        patterns: chrony.conf
        contains: ^[\s]*(?:server|pool)[\s]+[\w]+
      register: chrony_servers
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - '"chrony" in ansible_facts.packages'
      tags:
      - CCE-84218-7
      - NIST-800-53-AU-8(1)(a)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-10.4.3
      - chronyd_specify_remote_server
      - configure_strategy
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Configure remote time servers
      lineinfile:
        path: /etc/chrony.conf
        line: server {{ item }}
        state: present
        create: true
      loop: '{{ var_multiple_time_servers.split(",") }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - '"chrony" in ansible_facts.packages'
      - chrony_servers.matched == 0
      tags:
      - CCE-84218-7
      - NIST-800-53-AU-8(1)(a)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-10.4.3
      - chronyd_specify_remote_server
      - configure_strategy
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-chronyd_specify_remote_server:def:1

Class:

compliance

Title:

A remote time server for Chrony is configured

Version:

1

Description:

A remote NTP Server for time synchronization should be specified (and dependencies are met)

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-chronyd_specify_remote_server:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#package_chrony
Configure System Cryptography Policy high pass

Rule ID: | xccdf_org.ssgproject.content_rule_configure_crypto_policy
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

high

Identifiers:

CCE-83450-7

References:

164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.312(e)(1), 164.312(e)(2)(ii), 1446, CIP-003-8 R4.2, CIP-007-3 R5.1, CIP-007-3 R7.1, AC-17(a), AC-17(2), CM-6(a), MA-4(6), SC-13, SC-12(2), SC-12(3), FCS_COP.1(1), FCS_COP.1(2), FCS_COP.1(3), FCS_COP.1(4), FCS_CKM.1, FCS_CKM.2, FCS_TLSC_EXT.1, SRG-OS-000396-GPOS-00176, SRG-OS-000393-GPOS-00173, SRG-OS-000394-GPOS-00174, 1.10
Description:
To configure the system cryptography policy to use ciphers only from the `DEFAULT` policy, run the following command:

    $ sudo update-crypto-policies --set DEFAULT

The rule checks if settings for selected crypto policy are configured as expected. Configuration files in the `/etc/crypto-policies/back-ends` are either symlinks to correct files provided by Crypto-policies package or they are regular files in case crypto policy customizations are applied. Crypto policies may be customized by crypto policy modules, in which case it is delimited from the base policy using a colon.
Rationale:

Centralized cryptographic policies simplify applying secure ciphers across an operating system and the applications that run on that operating system. Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to protect data.

Warnings:

General warning
The system needs to be rebooted for these changes to take effect.

Regulatory warning
System Crypto Modules must be provided by a vendor that undergoes FIPS-140 certifications. FIPS-140 is applicable to all Federal agencies that use cryptographic-based security systems to protect sensitive information in computer and telecommunication systems (including voice systems) as defined in Section 5131 of the Information Technology Management Reform Act of 1996, Public Law 104-106. This standard shall be used in designing and implementing cryptographic modules that Federal departments and agencies operate or are operated for them under contract. See https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.140-2.pdf To meet this, the system has to have cryptographic software provided by a vendor that has undergone this certification. This means providing documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process.
Remediation Shell script

    var_system_crypto_policy='DEFAULT'

    stderr_of_call=$(update-crypto-policies --set ${var_system_crypto_policy} 2>&1 > /dev/null)
    rc=$?

    if test "$rc" = 127; then
    	echo "$stderr_of_call" >&2
    	echo "Make sure that the script is installed on the remediated system." >&2
    	echo "See output of the 'dnf provides update-crypto-policies' command" >&2
    	echo "to see what package to (re)install" >&2

    	false  # end with an error code
    elif test "$rc" != 0; then
    	echo "Error invoking the update-crypto-policies script: $stderr_of_call" >&2
    	false  # end with an error code
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: XCCDF Value var_system_crypto_policy # promote to variable
      set_fact:
        var_system_crypto_policy: !!str DEFAULT
      tags:
        - always

    - name: Configure System Cryptography Policy
      lineinfile:
        path: /etc/crypto-policies/config
        regexp: ^(?!#)(\S+)$
        line: '{{ var_system_crypto_policy }}'
        create: true
      tags:
      - CCE-83450-7
      - NIST-800-53-AC-17(2)
      - NIST-800-53-AC-17(a)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-MA-4(6)
      - NIST-800-53-SC-12(2)
      - NIST-800-53-SC-12(3)
      - NIST-800-53-SC-13
      - configure_crypto_policy
      - high_severity
      - low_complexity
      - low_disruption
      - no_reboot_needed
      - restrict_strategy

    - name: Verify that Crypto Policy is Set (runtime)
      command: /usr/bin/update-crypto-policies --set {{ var_system_crypto_policy }}
      tags:
      - CCE-83450-7
      - NIST-800-53-AC-17(2)
      - NIST-800-53-AC-17(a)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-MA-4(6)
      - NIST-800-53-SC-12(2)
      - NIST-800-53-SC-12(3)
      - NIST-800-53-SC-13
      - configure_crypto_policy
      - high_severity
      - low_complexity
      - low_disruption
      - no_reboot_needed
      - restrict_strategy

Remediation Kubernetes snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        systemd:
          units:
            - name: configure-crypto-policy.service
              enabled: true
              contents: |
                [Unit]
                Before=kubelet.service
                [Service]
                Type=oneshot
                ExecStart=update-crypto-policies --set {{.var_system_crypto_policy}}
                RemainAfterExit=yes
                [Install]
                WantedBy=multi-user.target

OVAL definition:

Definition ID:

oval:ssg-configure_crypto_policy:def:1

Class:

compliance

Title:

Configure System Cryptography Policy

Version:

1

Description:

Ensure crypto policy is correctly configured in /etc/crypto-policies/config, and the policy is current.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-configure_crypto_policy:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Configure SSH to use System Crypto Policy medium error

Rule ID: | xccdf_org.ssgproject.content_rule_configure_ssh_crypto_policy
Result: | error
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83445-7

References:

CCI-001453, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.312(e)(1), 164.312(e)(2)(ii), CIP-003-8 R4.2, CIP-007-3 R5.1, CIP-007-3 R7.1, AC-17(a), AC-17(2), CM-6(a), MA-4(6), SC-13, FCS_SSH_EXT.1, FCS_SSHS_EXT.1, FCS_SSHC_EXT.1, Req-2.2, SRG-OS-000250-GPOS-00093, 5.2.14
Description:
Crypto Policies provide a centralized control over crypto algorithms usage of many packages. SSH is supported by crypto policy, but the SSH configuration may be set up to ignore it. To check that Crypto Policies settings are configured correctly, ensure that the `CRYPTO_POLICY` variable is either commented or not set at all in the `/etc/sysconfig/sshd`.
Rationale:

Overriding the system crypto policy makes the behavior of the SSH service violate expectations, and makes system configuration more fragmented.

Remediation Shell script

    SSH_CONF="/etc/sysconfig/sshd"

    sed -i "/^\s*CRYPTO_POLICY.*$/Id" $SSH_CONF

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: Configure SSH to use System Crypto Policy
      lineinfile:
        dest: /etc/sysconfig/sshd
        state: absent
        regexp: ^\s*(?i)CRYPTO_POLICY.*$
      tags:
      - CCE-83445-7
      - NIST-800-53-AC-17(2)
      - NIST-800-53-AC-17(a)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-MA-4(6)
      - NIST-800-53-SC-13
      - PCI-DSS-Req-2.2
      - configure_ssh_crypto_policy
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required

OVAL definition:

Definition ID:

oval:ssg-configure_ssh_crypto_policy:def:1

Class:

compliance

Title:

Configure SSH to use System Crypto Policy

Version:

1

Description:

SSH should be configured to use the system-wide crypto policy setting.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-configure_ssh_crypto_policy:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Disable core dump backtraces medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_coredump_disable_backtraces
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83984-5

References:

CCI-000366, CM-6, FMT_SMF_EXT.1, SRG-OS-000480-GPOS-00227, 1.5.2
Description:
The `ProcessSizeMax` option in `[Coredump]` section of `/etc/systemd/coredump.conf` specifies the maximum size in bytes of a core which will be processed. Core dumps exceeding this size may be stored, but the backtrace will not be generated.
Rationale:

A core dump includes a memory image taken at the time the operating system terminates an application. The memory image could contain sensitive data and is generally useful only for developers or system operators trying to debug problems. Enabling core dumps on production systems is not recommended, however there may be overriding operational requirements to enable advanced debuging. Permitting temporary enablement of core dumps during such situations should be reviewed through local needs and policy.

Warnings:

General warning
If the `/etc/systemd/coredump.conf` file does not already contain the `[Coredump]` section, the value will not be configured correctly.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    sed: couldn't open temporary file /etc/systemd/sedoJS29p: Permission denied
    sed: couldn't open temporary file /etc/systemd/sedhmgQIO: Permission denied
    cp: cannot create regular file '/etc/systemd/coredump.conf.bak': Permission denied
    /tmp/oscap.y6fYh1/fix-XXGavJZr: line 12: /etc/systemd/coredump.conf: Permission denied
    rm: cannot remove '/etc/systemd/coredump.conf.bak': No such file or directory

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    if [ -e "/etc/systemd/coredump.conf" ] ; then

        LC_ALL=C sed -i "/^\s*ProcessSizeMax\s*=\s*/Id" "/etc/systemd/coredump.conf"
    else
        touch "/etc/systemd/coredump.conf"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/systemd/coredump.conf"

    cp "/etc/systemd/coredump.conf" "/etc/systemd/coredump.conf.bak"
    # Insert at the end of the file
    printf '%s\n' "ProcessSizeMax=0" >> "/etc/systemd/coredump.conf"
    # Clean up after ourselves.
    rm "/etc/systemd/coredump.conf.bak"

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Disable core dump backtraces
      block:

      - name: Check for duplicate values
        lineinfile:
          path: /etc/systemd/coredump.conf
          create: false
          regexp: ^\s*ProcessSizeMax\s*=\s*
          state: absent
        check_mode: true
        changed_when: false
        register: dupes

      - name: Deduplicate values from /etc/systemd/coredump.conf
        lineinfile:
          path: /etc/systemd/coredump.conf
          create: false
          regexp: ^\s*ProcessSizeMax\s*=\s*
          state: absent
        when: dupes.found is defined and dupes.found > 1

      - name: Insert correct line to /etc/systemd/coredump.conf
        lineinfile:
          path: /etc/systemd/coredump.conf
          create: false
          regexp: ^\s*ProcessSizeMax\s*=\s*
          line: ProcessSizeMax=0
          state: present
      tags:
      - CCE-83984-5
      - NIST-800-53-CM-6
      - coredump_disable_backtraces
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,%23%20%20This%20file%20is%20part%20of%20systemd.%0A%23%0A%23%20%20systemd%20is%20free%20software%3B%20you%20can%20redistribute%20it%20and/or%20modify%20it%0A%23%20%20under%20the%20terms%20of%20the%20GNU%20Lesser%20General%20Public%20License%20as%20published%20by%0A%23%20%20the%20Free%20Software%20Foundation%3B%20either%20version%202.1%20of%20the%20License%2C%20or%0A%23%20%20%28at%20your%20option%29%20any%20later%20version.%0A%23%0A%23%20Entries%20in%20this%20file%20show%20the%20compile%20time%20defaults.%0A%23%20You%20can%20change%20settings%20by%20editing%20this%20file.%0A%23%20Defaults%20can%20be%20restored%20by%20simply%20deleting%20this%20file.%0A%23%0A%23%20See%20coredump.conf%285%29%20for%20details.%0A%0A%5BCoredump%5D%0A%23Storage%3Dexternal%0A%23Compress%3Dyes%0A%23ProcessSizeMax%3D2G%0A%23ExternalSizeMax%3D2G%0A%23JournalSizeMax%3D767M%0A%23MaxUse%3D%0A%23KeepFree%3D%0AStorage%3Dnone%0AProcessSizeMax%3D0%0A
            mode: 0644
            path: /etc/systemd/coredump.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-coredump_disable_backtraces:def:1

Class:

compliance

Title:

Disable core dump backtraces

Version:

1

Description:

Ensure 'ProcessSizeMax' is configured with value '0 in section 'Coredump' in /etc/systemd/coredump.conf

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-coredump_disable_backtraces:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Disable storing core dump medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_coredump_disable_storage
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83979-5

References:

CCI-000366, CM-6, FMT_SMF_EXT.1, SRG-OS-000480-GPOS-00227, 1.5.1
Description:
The `Storage` option in `[Coredump]` section of `/etc/systemd/coredump.conf` can be set to `none` to disable storing core dumps permanently.
Rationale:

A core dump includes a memory image taken at the time the operating system terminates an application. The memory image could contain sensitive data and is generally useful only for developers or system operators trying to debug problems. Enabling core dumps on production systems is not recommended, however there may be overriding operational requirements to enable advanced debuging. Permitting temporary enablement of core dumps during such situations should be reviewed through local needs and policy.

Warnings:

General warning
If the `/etc/systemd/coredump.conf` file does not already contain the `[Coredump]` section, the value will not be configured correctly.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    sed: couldn't open temporary file /etc/systemd/sedAZ6tsb: Permission denied
    sed: couldn't open temporary file /etc/systemd/sedLwygaL: Permission denied
    cp: cannot create regular file '/etc/systemd/coredump.conf.bak': Permission denied
    /tmp/oscap.T0Y6xm/fix-XX7g79k1: line 12: /etc/systemd/coredump.conf: Permission denied
    rm: cannot remove '/etc/systemd/coredump.conf.bak': No such file or directory

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    if [ -e "/etc/systemd/coredump.conf" ] ; then

        LC_ALL=C sed -i "/^\s*Storage\s*=\s*/Id" "/etc/systemd/coredump.conf"
    else
        touch "/etc/systemd/coredump.conf"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/systemd/coredump.conf"

    cp "/etc/systemd/coredump.conf" "/etc/systemd/coredump.conf.bak"
    # Insert at the end of the file
    printf '%s\n' "Storage=none" >> "/etc/systemd/coredump.conf"
    # Clean up after ourselves.
    rm "/etc/systemd/coredump.conf.bak"

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Disable storing core dump
      block:

      - name: Check for duplicate values
        lineinfile:
          path: /etc/systemd/coredump.conf
          create: false
          regexp: ^\s*Storage\s*=\s*
          state: absent
        check_mode: true
        changed_when: false
        register: dupes

      - name: Deduplicate values from /etc/systemd/coredump.conf
        lineinfile:
          path: /etc/systemd/coredump.conf
          create: false
          regexp: ^\s*Storage\s*=\s*
          state: absent
        when: dupes.found is defined and dupes.found > 1

      - name: Insert correct line to /etc/systemd/coredump.conf
        lineinfile:
          path: /etc/systemd/coredump.conf
          create: false
          regexp: ^\s*Storage\s*=\s*
          line: Storage=none
          state: present
      tags:
      - CCE-83979-5
      - NIST-800-53-CM-6
      - coredump_disable_storage
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,%23%20%20This%20file%20is%20part%20of%20systemd.%0A%23%0A%23%20%20systemd%20is%20free%20software%3B%20you%20can%20redistribute%20it%20and/or%20modify%20it%0A%23%20%20under%20the%20terms%20of%20the%20GNU%20Lesser%20General%20Public%20License%20as%20published%20by%0A%23%20%20the%20Free%20Software%20Foundation%3B%20either%20version%202.1%20of%20the%20License%2C%20or%0A%23%20%20%28at%20your%20option%29%20any%20later%20version.%0A%23%0A%23%20Entries%20in%20this%20file%20show%20the%20compile%20time%20defaults.%0A%23%20You%20can%20change%20settings%20by%20editing%20this%20file.%0A%23%20Defaults%20can%20be%20restored%20by%20simply%20deleting%20this%20file.%0A%23%0A%23%20See%20coredump.conf%285%29%20for%20details.%0A%0A%5BCoredump%5D%0A%23Storage%3Dexternal%0A%23Compress%3Dyes%0A%23ProcessSizeMax%3D2G%0A%23ExternalSizeMax%3D2G%0A%23JournalSizeMax%3D767M%0A%23MaxUse%3D%0A%23KeepFree%3D%0AStorage%3Dnone%0AProcessSizeMax%3D0%0A
            mode: 0644
            path: /etc/systemd/coredump.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-coredump_disable_storage:def:1

Class:

compliance

Title:

Disable storing core dump

Version:

1

Description:

Ensure 'Storage' is configured with value 'none in section 'Coredump' in /etc/systemd/coredump.conf

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-coredump_disable_storage:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Make sure that the dconf databases are up-to-date with regards to respective keyfiles high pass

Rule ID: | xccdf_org.ssgproject.content_rule_dconf_db_up_to_date
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

high

Identifiers:

CCE-87295-2

References:

164.308(a)(1)(ii)(B), 164.308(a)(5)(ii)(A), Req-6.2, SRG-OS-000480-GPOS-00227, 1.8.2
Description:
By default, DConf uses a binary database as a data backend. The system-level database is compiled from keyfiles in the /etc/dconf/db/ directory by the

    dconf update

command. More specifically, content present in the following directories:

    /etc/dconf/db/distro.d

    /etc/dconf/db/local.d

Rationale:

Unlike text-based keyfiles, the binary database is impossible to check by OVAL. Therefore, in order to evaluate dconf configuration, both have to be true at the same time - configuration files have to be compliant, and the database needs to be more recent than those keyfiles, which gives confidence that it reflects them.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then

    dconf update

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

OVAL definition:

Definition ID:

oval:ssg-dconf_db_up_to_date:def:1

Class:

compliance

Title:

Make sure that the dconf databases are up-to-date with regards to respective keyfiles

Version:

2

Description:

Make sure that the dconf databases are up-to-date with regards to respective keyfiles.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-dconf_db_up_to_date:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#package_gdm
CPE platform required by rule:
#machine
Enable GNOME3 Login Warning Banner medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_dconf_gnome_banner_enabled
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-87599-7

References:

1, 12, 15, 16, DSS05.04, DSS05.10, DSS06.10, 3.1.9, CCI-000048, CCI-000050, CCI-001384, CCI-001385, CCI-001386, CCI-001387, CCI-001388, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, AC-8(a), AC-8(b), AC-8(c), PR.AC-7, FMT_MOF_EXT.1, SRG-OS-000023-GPOS-00006, SRG-OS-000228-GPOS-00088, 1.8.2
Description:
In the default graphical environment, displaying a login warning banner in the GNOME Display Manager's login screen can be enabled on the login screen by setting `banner-message-enable` to `true`.
To enable, add or edit `banner-message-enable` to `/etc/dconf/db/distro.d/00-security-settings`. For example:

    [org/gnome/login-screen]
    banner-message-enable=true

Once the setting has been added, add a lock to `/etc/dconf/db/distro.d/locks/00-security-settings-lock` to prevent user modification. For example:

    /org/gnome/login-screen/banner-message-enable

After the settings have been set, run `dconf update`. The banner text must also be set.
Rationale:

Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance.
For U.S. Government systems, system use notifications are required only for access via login interfaces with human users and are not required when such human interfaces do not exist.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    /tmp/oscap.clHglG/fix-XX6HsiWu: line 25: /etc/dconf/db/distro.d/00-security-settings: Permission denied
    grep: /etc/dconf/db/distro.d/00-security-settings: No such file or directory
    /tmp/oscap.clHglG/fix-XX6HsiWu: line 28: /etc/dconf/db/distro.d/00-security-settings: Permission denied
    grep: /etc/dconf/db/distro.d/00-security-settings: No such file or directory
    sed: can't read /etc/dconf/db/distro.d/00-security-settings: No such file or directory
    warning: Failed to open '/etc/dconf/db/distro': for replacement: Permission denied
    /etc/dconf/db/distro.d: Failed to create file “/etc/dconf/db/distro.0YR311”: Permission denied
    warning: Failed to open '/etc/dconf/db/local': for replacement: Permission denied
    /etc/dconf/db/local.d: Failed to create file “/etc/dconf/db/local.5TS311”: Permission denied
    warning: Failed to open '/etc/dconf/db/site': for replacement: Permission denied
    /etc/dconf/db/site.d: Failed to create file “/etc/dconf/db/site.QUS311”: Permission denied
    warning: Failed to open '/etc/dconf/db/ibus': for replacement: Permission denied
    /etc/dconf/db/ibus.d: Failed to create file “/etc/dconf/db/ibus.10S311”: Permission denied
    warning: Failed to open '/etc/dconf/db/gdm': for replacement: Permission denied
    /etc/dconf/db/gdm.d: Failed to create file “/etc/dconf/db/gdm.R0S311”: Permission denied
    error: failed to update at least one of the databases
    /tmp/oscap.clHglG/fix-XX6HsiWu: line 55: /etc/dconf/db/distro.d/locks/00-security-settings-lock: Permission denied
    warning: Failed to open '/etc/dconf/db/distro': for replacement: Permission denied
    /etc/dconf/db/distro.d: Failed to create file “/etc/dconf/db/distro.EA3311”: Permission denied
    warning: Failed to open '/etc/dconf/db/local': for replacement: Permission denied
    /etc/dconf/db/local.d: Failed to create file “/etc/dconf/db/local.OB3311”: Permission denied
    warning: Failed to open '/etc/dconf/db/site': for replacement: Permission denied
    /etc/dconf/db/site.d: Failed to create file “/etc/dconf/db/site.EE3311”: Permission denied
    warning: Failed to open '/etc/dconf/db/ibus': for replacement: Permission denied
    /etc/dconf/db/ibus.d: Failed to create file “/etc/dconf/db/ibus.QS2311”: Permission denied
    warning: Failed to open '/etc/dconf/db/gdm': for replacement: Permission denied
    /etc/dconf/db/gdm.d: Failed to create file “/etc/dconf/db/gdm.GU2311”: Permission denied
    error: failed to update at least one of the databases

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q gdm; then

    # Check for setting in any of the DConf db directories
    # If files contain ibus or distro, ignore them.
    # The assignment assumes that individual filenames don't contain :
    readarray -t SETTINGSFILES < <(grep -r "\\[org/gnome/login-screen\\]" "/etc/dconf/db/" \
                                    | grep -v 'distro\|ibus\|distro.d' | cut -d":" -f1)
    DCONFFILE="/etc/dconf/db/distro.d/00-security-settings"
    DBDIR="/etc/dconf/db/distro.d"

    mkdir -p "${DBDIR}"

    # Comment out the configurations in databases different from the target one
    if [ "${#SETTINGSFILES[@]}" -ne 0 ]
    then
        if grep -q "^\\s*banner-message-enable\\s*=" "${SETTINGSFILES[@]}"
        then

            sed -Ei "s/(^\s*)banner-message-enable(\s*=)/#\1banner-message-enable\2/g" "${SETTINGSFILES[@]}"
        fi
    fi

    [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}"
    if ! grep -q "\\[org/gnome/login-screen\\]" "${DCONFFILE}"
    then
        printf '%s\n' "[org/gnome/login-screen]" >> ${DCONFFILE}
    fi

    escaped_value="$(sed -e 's/\\/\\\\/g' <<< "true")"
    if grep -q "^\\s*banner-message-enable\\s*=" "${DCONFFILE}"
    then
            sed -i "s/\\s*banner-message-enable\\s*=\\s*.*/banner-message-enable=${escaped_value}/g" "${DCONFFILE}"
        else
            sed -i "\\|\\[org/gnome/login-screen\\]|a\\banner-message-enable=${escaped_value}" "${DCONFFILE}"
    fi

    dconf update
    # Check for setting in any of the DConf db directories
    LOCKFILES=$(grep -r "^/org/gnome/login-screen/banner-message-enable$" "/etc/dconf/db/" \
                | grep -v 'distro\|ibus\|distro.d' | grep ":" | cut -d":" -f1)
    LOCKSFOLDER="/etc/dconf/db/distro.d/locks"

    mkdir -p "${LOCKSFOLDER}"

    # Comment out the configurations in databases different from the target one
    if [[ ! -z "${LOCKFILES}" ]]
    then
        sed -i -E "s|^/org/gnome/login-screen/banner-message-enable$|#&|" "${LOCKFILES[@]}"
    fi

    if ! grep -qr "^/org/gnome/login-screen/banner-message-enable$" /etc/dconf/db/distro.d/
    then
        echo "/org/gnome/login-screen/banner-message-enable" >> "/etc/dconf/db/distro.d/locks/00-security-settings-lock"
    fi

    dconf update

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | unknown

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-87599-7
      - NIST-800-171-3.1.9
      - NIST-800-53-AC-8(a)
      - NIST-800-53-AC-8(b)
      - NIST-800-53-AC-8(c)
      - dconf_gnome_banner_enabled
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Enable GNOME3 Login Warning Banner
      ini_file:
        dest: /etc/dconf/db/distro.d/00-security-settings
        section: org/gnome/login-screen
        option: banner-message-enable
        value: 'true'
        create: true
        no_extra_spaces: true
      when: '"gdm" in ansible_facts.packages'
      tags:
      - CCE-87599-7
      - NIST-800-171-3.1.9
      - NIST-800-53-AC-8(a)
      - NIST-800-53-AC-8(b)
      - NIST-800-53-AC-8(c)
      - dconf_gnome_banner_enabled
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Prevent user modification of GNOME banner-message-enabled
      lineinfile:
        path: /etc/dconf/db/distro.d/locks/00-security-settings-lock
        regexp: ^/org/gnome/login-screen/banner-message-enable$
        line: /org/gnome/login-screen/banner-message-enable
        create: true
      when: '"gdm" in ansible_facts.packages'
      tags:
      - CCE-87599-7
      - NIST-800-171-3.1.9
      - NIST-800-53-AC-8(a)
      - NIST-800-53-AC-8(b)
      - NIST-800-53-AC-8(c)
      - dconf_gnome_banner_enabled
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Dconf Update
      command: dconf update
      when: '"gdm" in ansible_facts.packages'
      tags:
      - CCE-87599-7
      - NIST-800-171-3.1.9
      - NIST-800-53-AC-8(a)
      - NIST-800-53-AC-8(b)
      - NIST-800-53-AC-8(c)
      - dconf_gnome_banner_enabled
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

OVAL definition:

Definition ID:

oval:ssg-dconf_gnome_banner_enabled:def:1

Class:

compliance

Title:

Enable GNOME3 Login Warning Banner

Version:

1

Description:

Enable the GNOME3 Login warning banner.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-dconf_gnome_banner_enabled:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#package_gdm
Disable GNOME3 Automounting medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_dconf_gnome_disable_automount
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-87734-0

References:

12, 16, APO13.01, DSS01.04, DSS05.03, DSS05.04, DSS05.05, DSS05.07, DSS06.03, 3.1.7, CCI-000366, CCI-000778, CCI-001958, 4.3.3.2.2, 4.3.3.5.2, 4.3.3.6.6, 4.3.3.7.2, 4.3.3.7.4, SR 1.1, SR 1.13, SR 1.2, SR 1.4, SR 1.5, SR 1.9, SR 2.1, SR 2.6, A.11.2.6, A.13.1.1, A.13.2.1, A.6.2.1, A.6.2.2, A.7.1.1, A.9.2.1, CM-7(a), CM-7(b), CM-6(a), PR.AC-3, PR.AC-6, SRG-OS-000114-GPOS-00059, SRG-OS-000378-GPOS-00163, SRG-OS-000480-GPOS-00227, 1.8.6, 1.8.7
Description:
The system's default desktop environment, GNOME3, will mount devices and removable media (such as DVDs, CDs and USB flash drives) whenever they are inserted into the system. To disable automount within GNOME3, add or set `automount` to `false` in `/etc/dconf/db/local.d/00-security-settings`. For example:

    [org/gnome/desktop/media-handling]
    automount=false

Once the settings have been added, add a lock to `/etc/dconf/db/local.d/locks/00-security-settings-lock` to prevent user modification. For example:

    /org/gnome/desktop/media-handling/automount

After the settings have been set, run `dconf update`.
Rationale:

Disabling automatic mounting in GNOME3 can prevent the introduction of malware via removable media. It will, however, also prevent desktop users from legitimate use of removable media.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    /tmp/oscap.ivFPDt/fix-XXLoZBed: line 25: /etc/dconf/db/local.d/00-security-settings: Permission denied
    grep: /etc/dconf/db/local.d/00-security-settings: No such file or directory
    /tmp/oscap.ivFPDt/fix-XXLoZBed: line 28: /etc/dconf/db/local.d/00-security-settings: Permission denied
    grep: /etc/dconf/db/local.d/00-security-settings: No such file or directory
    sed: can't read /etc/dconf/db/local.d/00-security-settings: No such file or directory
    warning: Failed to open '/etc/dconf/db/distro': for replacement: Permission denied
    /etc/dconf/db/distro.d: Failed to create file “/etc/dconf/db/distro.9OK211”: Permission denied
    warning: Failed to open '/etc/dconf/db/local': for replacement: Permission denied
    /etc/dconf/db/local.d: Failed to create file “/etc/dconf/db/local.SNK211”: Permission denied
    warning: Failed to open '/etc/dconf/db/site': for replacement: Permission denied
    /etc/dconf/db/site.d: Failed to create file “/etc/dconf/db/site.LQK211”: Permission denied
    warning: Failed to open '/etc/dconf/db/ibus': for replacement: Permission denied
    /etc/dconf/db/ibus.d: Failed to create file “/etc/dconf/db/ibus.UUK211”: Permission denied
    warning: Failed to open '/etc/dconf/db/gdm': for replacement: Permission denied
    /etc/dconf/db/gdm.d: Failed to create file “/etc/dconf/db/gdm.BYK211”: Permission denied
    error: failed to update at least one of the databases
    /tmp/oscap.ivFPDt/fix-XXLoZBed: line 55: /etc/dconf/db/local.d/locks/00-security-settings-lock: Permission denied
    warning: Failed to open '/etc/dconf/db/distro': for replacement: Permission denied
    /etc/dconf/db/distro.d: Failed to create file “/etc/dconf/db/distro.7WO211”: Permission denied
    warning: Failed to open '/etc/dconf/db/local': for replacement: Permission denied
    /etc/dconf/db/local.d: Failed to create file “/etc/dconf/db/local.M0O211”: Permission denied
    warning: Failed to open '/etc/dconf/db/site': for replacement: Permission denied
    /etc/dconf/db/site.d: Failed to create file “/etc/dconf/db/site.03O211”: Permission denied
    warning: Failed to open '/etc/dconf/db/ibus': for replacement: Permission denied
    /etc/dconf/db/ibus.d: Failed to create file “/etc/dconf/db/ibus.P9P211”: Permission denied
    warning: Failed to open '/etc/dconf/db/gdm': for replacement: Permission denied
    /etc/dconf/db/gdm.d: Failed to create file “/etc/dconf/db/gdm.EDQ211”: Permission denied
    error: failed to update at least one of the databases

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then

    # Check for setting in any of the DConf db directories
    # If files contain ibus or distro, ignore them.
    # The assignment assumes that individual filenames don't contain :
    readarray -t SETTINGSFILES < <(grep -r "\\[org/gnome/desktop/media-handling\\]" "/etc/dconf/db/" \
                                    | grep -v 'distro\|ibus\|local.d' | cut -d":" -f1)
    DCONFFILE="/etc/dconf/db/local.d/00-security-settings"
    DBDIR="/etc/dconf/db/local.d"

    mkdir -p "${DBDIR}"

    # Comment out the configurations in databases different from the target one
    if [ "${#SETTINGSFILES[@]}" -ne 0 ]
    then
        if grep -q "^\\s*automount\\s*=" "${SETTINGSFILES[@]}"
        then

            sed -Ei "s/(^\s*)automount(\s*=)/#\1automount\2/g" "${SETTINGSFILES[@]}"
        fi
    fi

    [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}"
    if ! grep -q "\\[org/gnome/desktop/media-handling\\]" "${DCONFFILE}"
    then
        printf '%s\n' "[org/gnome/desktop/media-handling]" >> ${DCONFFILE}
    fi

    escaped_value="$(sed -e 's/\\/\\\\/g' <<< "false")"
    if grep -q "^\\s*automount\\s*=" "${DCONFFILE}"
    then
            sed -i "s/\\s*automount\\s*=\\s*.*/automount=${escaped_value}/g" "${DCONFFILE}"
        else
            sed -i "\\|\\[org/gnome/desktop/media-handling\\]|a\\automount=${escaped_value}" "${DCONFFILE}"
    fi

    dconf update
    # Check for setting in any of the DConf db directories
    LOCKFILES=$(grep -r "^/org/gnome/desktop/media-handling/automount$" "/etc/dconf/db/" \
                | grep -v 'distro\|ibus\|local.d' | grep ":" | cut -d":" -f1)
    LOCKSFOLDER="/etc/dconf/db/local.d/locks"

    mkdir -p "${LOCKSFOLDER}"

    # Comment out the configurations in databases different from the target one
    if [[ ! -z "${LOCKFILES}" ]]
    then
        sed -i -E "s|^/org/gnome/desktop/media-handling/automount$|#&|" "${LOCKFILES[@]}"
    fi

    if ! grep -qr "^/org/gnome/desktop/media-handling/automount$" /etc/dconf/db/local.d/
    then
        echo "/org/gnome/desktop/media-handling/automount" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock"
    fi

    dconf update

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | unknown

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-87734-0
      - NIST-800-171-3.1.7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - dconf_gnome_disable_automount
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Disable GNOME3 Automounting - automount
      ini_file:
        dest: /etc/dconf/db/local.d/00-security-settings
        section: org/gnome/desktop/media-handling
        option: automount
        value: 'false'
        create: true
        no_extra_spaces: true
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-87734-0
      - NIST-800-171-3.1.7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - dconf_gnome_disable_automount
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Prevent user modification of GNOME3 Automounting - automount
      lineinfile:
        path: /etc/dconf/db/local.d/locks/00-security-settings-lock
        regexp: ^/org/gnome/desktop/media-handling/automount$
        line: /org/gnome/desktop/media-handling/automount
        create: true
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-87734-0
      - NIST-800-171-3.1.7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - dconf_gnome_disable_automount
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Dconf Update
      command: dconf update
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-87734-0
      - NIST-800-171-3.1.7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - dconf_gnome_disable_automount
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

OVAL definition:

Definition ID:

oval:ssg-dconf_gnome_disable_automount:def:1

Class:

compliance

Title:

Disable GNOME3 automount

Version:

2

Description:

The system's default desktop environment, GNOME3, will mount devices and removable media (such as DVDs, CDs and USB flash drives) whenever they are inserted into the system. Disable automount within GNOME3.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-dconf_gnome_disable_automount:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#package_gdm
CPE platform required by rule:
#machine
Disable GNOME3 Automount Opening medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_dconf_gnome_disable_automount_open
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90128-0

References:

12, 16, APO13.01, DSS01.04, DSS05.03, DSS05.04, DSS05.05, DSS05.07, DSS06.03, 3.1.7, CCI-000366, CCI-000778, CCI-001958, 4.3.3.2.2, 4.3.3.5.2, 4.3.3.6.6, 4.3.3.7.2, 4.3.3.7.4, SR 1.1, SR 1.13, SR 1.2, SR 1.4, SR 1.5, SR 1.9, SR 2.1, SR 2.6, A.11.2.6, A.13.1.1, A.13.2.1, A.6.2.1, A.6.2.2, A.7.1.1, A.9.2.1, CM-7(a), CM-7(b), CM-6(a), PR.AC-3, PR.AC-6, SRG-OS-000114-GPOS-00059, SRG-OS-000378-GPOS-00163, SRG-OS-000480-GPOS-00227, 1.8.6, 1.8.7
Description:
The system's default desktop environment, GNOME3, will mount devices and removable media (such as DVDs, CDs and USB flash drives) whenever they are inserted into the system. To disable automount-open within GNOME3, add or set `automount-open` to `false` in `/etc/dconf/db/local.d/00-security-settings`. For example:

    [org/gnome/desktop/media-handling]
    automount-open=false

Once the settings have been added, add a lock to `/etc/dconf/db/local.d/locks/00-security-settings-lock` to prevent user modification. For example:

    /org/gnome/desktop/media-handling/automount-open

After the settings have been set, run `dconf update`.
Rationale:

Automatically mounting file systems permits easy introduction of unknown devices, thereby facilitating malicious activity. Disabling automatic mounting in GNOME3 can prevent the introduction of malware via removable media. It will, however, also prevent desktop users from legitimate use of removable media.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    /tmp/oscap.Bz31OB/fix-XXn8d1Bb: line 25: /etc/dconf/db/local.d/00-security-settings: Permission denied
    grep: /etc/dconf/db/local.d/00-security-settings: No such file or directory
    /tmp/oscap.Bz31OB/fix-XXn8d1Bb: line 28: /etc/dconf/db/local.d/00-security-settings: Permission denied
    grep: /etc/dconf/db/local.d/00-security-settings: No such file or directory
    sed: can't read /etc/dconf/db/local.d/00-security-settings: No such file or directory
    warning: Failed to open '/etc/dconf/db/distro': for replacement: Permission denied
    /etc/dconf/db/distro.d: Failed to create file “/etc/dconf/db/distro.U24011”: Permission denied
    warning: Failed to open '/etc/dconf/db/local': for replacement: Permission denied
    /etc/dconf/db/local.d: Failed to create file “/etc/dconf/db/local.M24011”: Permission denied
    warning: Failed to open '/etc/dconf/db/site': for replacement: Permission denied
    /etc/dconf/db/site.d: Failed to create file “/etc/dconf/db/site.Z44011”: Permission denied
    warning: Failed to open '/etc/dconf/db/ibus': for replacement: Permission denied
    /etc/dconf/db/ibus.d: Failed to create file “/etc/dconf/db/ibus.615011”: Permission denied
    warning: Failed to open '/etc/dconf/db/gdm': for replacement: Permission denied
    /etc/dconf/db/gdm.d: Failed to create file “/etc/dconf/db/gdm.T45011”: Permission denied
    error: failed to update at least one of the databases
    /tmp/oscap.Bz31OB/fix-XXn8d1Bb: line 55: /etc/dconf/db/local.d/locks/00-security-settings-lock: Permission denied
    warning: Failed to open '/etc/dconf/db/distro': for replacement: Permission denied
    /etc/dconf/db/distro.d: Failed to create file “/etc/dconf/db/distro.0EG111”: Permission denied
    warning: Failed to open '/etc/dconf/db/local': for replacement: Permission denied
    /etc/dconf/db/local.d: Failed to create file “/etc/dconf/db/local.QHG111”: Permission denied
    warning: Failed to open '/etc/dconf/db/site': for replacement: Permission denied
    /etc/dconf/db/site.d: Failed to create file “/etc/dconf/db/site.4HG111”: Permission denied
    warning: Failed to open '/etc/dconf/db/ibus': for replacement: Permission denied
    /etc/dconf/db/ibus.d: Failed to create file “/etc/dconf/db/ibus.FMG111”: Permission denied
    warning: Failed to open '/etc/dconf/db/gdm': for replacement: Permission denied
    /etc/dconf/db/gdm.d: Failed to create file “/etc/dconf/db/gdm.OVF111”: Permission denied
    error: failed to update at least one of the databases

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then

    # Check for setting in any of the DConf db directories
    # If files contain ibus or distro, ignore them.
    # The assignment assumes that individual filenames don't contain :
    readarray -t SETTINGSFILES < <(grep -r "\\[org/gnome/desktop/media-handling\\]" "/etc/dconf/db/" \
                                    | grep -v 'distro\|ibus\|local.d' | cut -d":" -f1)
    DCONFFILE="/etc/dconf/db/local.d/00-security-settings"
    DBDIR="/etc/dconf/db/local.d"

    mkdir -p "${DBDIR}"

    # Comment out the configurations in databases different from the target one
    if [ "${#SETTINGSFILES[@]}" -ne 0 ]
    then
        if grep -q "^\\s*automount-open\\s*=" "${SETTINGSFILES[@]}"
        then

            sed -Ei "s/(^\s*)automount-open(\s*=)/#\1automount-open\2/g" "${SETTINGSFILES[@]}"
        fi
    fi

    [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}"
    if ! grep -q "\\[org/gnome/desktop/media-handling\\]" "${DCONFFILE}"
    then
        printf '%s\n' "[org/gnome/desktop/media-handling]" >> ${DCONFFILE}
    fi

    escaped_value="$(sed -e 's/\\/\\\\/g' <<< "false")"
    if grep -q "^\\s*automount-open\\s*=" "${DCONFFILE}"
    then
            sed -i "s/\\s*automount-open\\s*=\\s*.*/automount-open=${escaped_value}/g" "${DCONFFILE}"
        else
            sed -i "\\|\\[org/gnome/desktop/media-handling\\]|a\\automount-open=${escaped_value}" "${DCONFFILE}"
    fi

    dconf update
    # Check for setting in any of the DConf db directories
    LOCKFILES=$(grep -r "^/org/gnome/desktop/media-handling/automount-open$" "/etc/dconf/db/" \
                | grep -v 'distro\|ibus\|local.d' | grep ":" | cut -d":" -f1)
    LOCKSFOLDER="/etc/dconf/db/local.d/locks"

    mkdir -p "${LOCKSFOLDER}"

    # Comment out the configurations in databases different from the target one
    if [[ ! -z "${LOCKFILES}" ]]
    then
        sed -i -E "s|^/org/gnome/desktop/media-handling/automount-open$|#&|" "${LOCKFILES[@]}"
    fi

    if ! grep -qr "^/org/gnome/desktop/media-handling/automount-open$" /etc/dconf/db/local.d/
    then
        echo "/org/gnome/desktop/media-handling/automount-open" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock"
    fi

    dconf update

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | unknown

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-90128-0
      - NIST-800-171-3.1.7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - dconf_gnome_disable_automount_open
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Disable GNOME3 Automounting - automount-open
      ini_file:
        dest: /etc/dconf/db/local.d/00-security-settings
        section: org/gnome/desktop/media-handling
        option: automount-open
        value: 'false'
        create: true
        no_extra_spaces: true
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90128-0
      - NIST-800-171-3.1.7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - dconf_gnome_disable_automount_open
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Prevent user modification of GNOME3 Automounting - automount-open
      lineinfile:
        path: /etc/dconf/db/local.d/locks/00-security-settings-lock
        regexp: ^/org/gnome/desktop/media-handling/automount-open$
        line: /org/gnome/desktop/media-handling/automount-open
        create: true
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90128-0
      - NIST-800-171-3.1.7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - dconf_gnome_disable_automount_open
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Dconf Update
      command: dconf update
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90128-0
      - NIST-800-171-3.1.7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - dconf_gnome_disable_automount_open
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

OVAL definition:

Definition ID:

oval:ssg-dconf_gnome_disable_automount_open:def:1

Class:

compliance

Title:

Disable GNOME3 automount-open

Version:

1

Description:

The system's default desktop environment, GNOME3, will mount devices and removable media (such as DVDs, CDs and USB flash drives) whenever they are inserted into the system. Disable automount-open within GNOME3.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-dconf_gnome_disable_automount_open:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#package_gdm
CPE platform required by rule:
#machine
Disable GNOME3 Automount running low fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_dconf_gnome_disable_autorun
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

low

Identifiers:

CCE-90257-7

References:

12, 16, APO13.01, DSS01.04, DSS05.03, DSS05.04, DSS05.05, DSS05.07, DSS06.03, 3.1.7, CCI-000366, CCI-000778, CCI-001958, 4.3.3.2.2, 4.3.3.5.2, 4.3.3.6.6, 4.3.3.7.2, 4.3.3.7.4, SR 1.1, SR 1.13, SR 1.2, SR 1.4, SR 1.5, SR 1.9, SR 2.1, SR 2.6, A.11.2.6, A.13.1.1, A.13.2.1, A.6.2.1, A.6.2.2, A.7.1.1, A.9.2.1, CM-7(a), CM-7(b), CM-6(a), PR.AC-3, PR.AC-6, SRG-OS-000114-GPOS-00059, SRG-OS-000378-GPOS-00163, SRG-OS-000480-GPOS-00227, 1.8.8, 1.8.9
Description:
The system's default desktop environment, GNOME3, will mount devices and removable media (such as DVDs, CDs and USB flash drives) whenever they are inserted into the system. To disable autorun-never within GNOME3, add or set `autorun-never` to `true` in `/etc/dconf/db/local.d/00-security-settings`. For example:

    [org/gnome/desktop/media-handling]
    autorun-never=true

Once the settings have been added, add a lock to `/etc/dconf/db/local.d/locks/00-security-settings-lock` to prevent user modification. For example:

    /org/gnome/desktop/media-handling/autorun-never

After the settings have been set, run `dconf update`.
Rationale:

Automatically mounting file systems permits easy introduction of unknown devices, thereby facilitating malicious activity. Disabling automatic mount running in GNOME3 can prevent the introduction of malware via removable media. It will, however, also prevent desktop users from legitimate use of removable media.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    /tmp/oscap.6KuAEc/fix-XXHkGX4a: line 25: /etc/dconf/db/local.d/00-security-settings: Permission denied
    grep: /etc/dconf/db/local.d/00-security-settings: No such file or directory
    /tmp/oscap.6KuAEc/fix-XXHkGX4a: line 28: /etc/dconf/db/local.d/00-security-settings: Permission denied
    grep: /etc/dconf/db/local.d/00-security-settings: No such file or directory
    sed: can't read /etc/dconf/db/local.d/00-security-settings: No such file or directory
    warning: Failed to open '/etc/dconf/db/distro': for replacement: Permission denied
    /etc/dconf/db/distro.d: Failed to create file “/etc/dconf/db/distro.E5V111”: Permission denied
    warning: Failed to open '/etc/dconf/db/local': for replacement: Permission denied
    /etc/dconf/db/local.d: Failed to create file “/etc/dconf/db/local.X7V111”: Permission denied
    warning: Failed to open '/etc/dconf/db/site': for replacement: Permission denied
    /etc/dconf/db/site.d: Failed to create file “/etc/dconf/db/site.UCW111”: Permission denied
    warning: Failed to open '/etc/dconf/db/ibus': for replacement: Permission denied
    /etc/dconf/db/ibus.d: Failed to create file “/etc/dconf/db/ibus.YTV111”: Permission denied
    warning: Failed to open '/etc/dconf/db/gdm': for replacement: Permission denied
    /etc/dconf/db/gdm.d: Failed to create file “/etc/dconf/db/gdm.0ZV111”: Permission denied
    error: failed to update at least one of the databases
    /tmp/oscap.6KuAEc/fix-XXHkGX4a: line 55: /etc/dconf/db/local.d/locks/00-security-settings-lock: Permission denied
    warning: Failed to open '/etc/dconf/db/distro': for replacement: Permission denied
    /etc/dconf/db/distro.d: Failed to create file “/etc/dconf/db/distro.7B9Y11”: Permission denied
    warning: Failed to open '/etc/dconf/db/local': for replacement: Permission denied
    /etc/dconf/db/local.d: Failed to create file “/etc/dconf/db/local.LD9Y11”: Permission denied
    warning: Failed to open '/etc/dconf/db/site': for replacement: Permission denied
    /etc/dconf/db/site.d: Failed to create file “/etc/dconf/db/site.QC9Y11”: Permission denied
    warning: Failed to open '/etc/dconf/db/ibus': for replacement: Permission denied
    /etc/dconf/db/ibus.d: Failed to create file “/etc/dconf/db/ibus.LL9Y11”: Permission denied
    warning: Failed to open '/etc/dconf/db/gdm': for replacement: Permission denied
    /etc/dconf/db/gdm.d: Failed to create file “/etc/dconf/db/gdm.UU8Y11”: Permission denied
    error: failed to update at least one of the databases

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then

    # Check for setting in any of the DConf db directories
    # If files contain ibus or distro, ignore them.
    # The assignment assumes that individual filenames don't contain :
    readarray -t SETTINGSFILES < <(grep -r "\\[org/gnome/desktop/media-handling\\]" "/etc/dconf/db/" \
                                    | grep -v 'distro\|ibus\|local.d' | cut -d":" -f1)
    DCONFFILE="/etc/dconf/db/local.d/00-security-settings"
    DBDIR="/etc/dconf/db/local.d"

    mkdir -p "${DBDIR}"

    # Comment out the configurations in databases different from the target one
    if [ "${#SETTINGSFILES[@]}" -ne 0 ]
    then
        if grep -q "^\\s*autorun-never\\s*=" "${SETTINGSFILES[@]}"
        then

            sed -Ei "s/(^\s*)autorun-never(\s*=)/#\1autorun-never\2/g" "${SETTINGSFILES[@]}"
        fi
    fi

    [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}"
    if ! grep -q "\\[org/gnome/desktop/media-handling\\]" "${DCONFFILE}"
    then
        printf '%s\n' "[org/gnome/desktop/media-handling]" >> ${DCONFFILE}
    fi

    escaped_value="$(sed -e 's/\\/\\\\/g' <<< "true")"
    if grep -q "^\\s*autorun-never\\s*=" "${DCONFFILE}"
    then
            sed -i "s/\\s*autorun-never\\s*=\\s*.*/autorun-never=${escaped_value}/g" "${DCONFFILE}"
        else
            sed -i "\\|\\[org/gnome/desktop/media-handling\\]|a\\autorun-never=${escaped_value}" "${DCONFFILE}"
    fi

    dconf update
    # Check for setting in any of the DConf db directories
    LOCKFILES=$(grep -r "^/org/gnome/desktop/media-handling/autorun-never$" "/etc/dconf/db/" \
                | grep -v 'distro\|ibus\|local.d' | grep ":" | cut -d":" -f1)
    LOCKSFOLDER="/etc/dconf/db/local.d/locks"

    mkdir -p "${LOCKSFOLDER}"

    # Comment out the configurations in databases different from the target one
    if [[ ! -z "${LOCKFILES}" ]]
    then
        sed -i -E "s|^/org/gnome/desktop/media-handling/autorun-never$|#&|" "${LOCKFILES[@]}"
    fi

    if ! grep -qr "^/org/gnome/desktop/media-handling/autorun-never$" /etc/dconf/db/local.d/
    then
        echo "/org/gnome/desktop/media-handling/autorun-never" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock"
    fi

    dconf update

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | unknown

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-90257-7
      - NIST-800-171-3.1.7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - dconf_gnome_disable_autorun
      - low_complexity
      - low_severity
      - medium_disruption
      - no_reboot_needed
      - unknown_strategy

    - name: Disable GNOME3 Automounting - autorun-never
      ini_file:
        dest: /etc/dconf/db/local.d/00-security-settings
        section: org/gnome/desktop/media-handling
        option: autorun-never
        value: 'true'
        create: true
        no_extra_spaces: true
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90257-7
      - NIST-800-171-3.1.7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - dconf_gnome_disable_autorun
      - low_complexity
      - low_severity
      - medium_disruption
      - no_reboot_needed
      - unknown_strategy

    - name: Prevent user modification of GNOME3 Automounting - autorun-never
      lineinfile:
        path: /etc/dconf/db/local.d/locks/00-security-settings-lock
        regexp: ^/org/gnome/desktop/media-handling/autorun-never$
        line: /org/gnome/desktop/media-handling/autorun-never
        create: true
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90257-7
      - NIST-800-171-3.1.7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - dconf_gnome_disable_autorun
      - low_complexity
      - low_severity
      - medium_disruption
      - no_reboot_needed
      - unknown_strategy

    - name: Dconf Update
      command: dconf update
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90257-7
      - NIST-800-171-3.1.7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - dconf_gnome_disable_autorun
      - low_complexity
      - low_severity
      - medium_disruption
      - no_reboot_needed
      - unknown_strategy

OVAL definition:

Definition ID:

oval:ssg-dconf_gnome_disable_autorun:def:1

Class:

compliance

Title:

Disable GNOME3 autorun

Version:

1

Description:

The system's default desktop environment, GNOME3, will mount devices and removable media (such as DVDs, CDs and USB flash drives) whenever they are inserted into the system. Disable autorun within GNOME3.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-dconf_gnome_disable_autorun:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#package_gdm
CPE platform required by rule:
#machine
Disable the GNOME3 Login User List medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_dconf_gnome_disable_user_list
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-88285-2

References:

CM-6(a), AC-23, SRG-OS-000480-GPOS-00227, 1.8.3
Description:
In the default graphical environment, users logging directly into the system are greeted with a login screen that displays all known users. This functionality should be disabled by setting `disable-user-list` to `true`.
To disable, add or edit `disable-user-list` to `/etc/dconf/db/distro.d/00-security-settings`. For example:

    [org/gnome/login-screen]
    disable-user-list=true

Once the setting has been added, add a lock to `/etc/dconf/db/distro.d/locks/00-security-settings-lock` to prevent user modification. For example:

    /org/gnome/login-screen/disable-user-list

After the settings have been set, run `dconf update`.
Rationale:

Leaving the user list enabled is a security risk since it allows anyone with physical access to the system to quickly enumerate known user accounts without logging in.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    /tmp/oscap.XzwYi4/fix-XXEgX2MO: line 25: /etc/dconf/db/distro.d/00-security-settings: Permission denied
    grep: /etc/dconf/db/distro.d/00-security-settings: No such file or directory
    /tmp/oscap.XzwYi4/fix-XXEgX2MO: line 28: /etc/dconf/db/distro.d/00-security-settings: Permission denied
    grep: /etc/dconf/db/distro.d/00-security-settings: No such file or directory
    sed: can't read /etc/dconf/db/distro.d/00-security-settings: No such file or directory
    warning: Failed to open '/etc/dconf/db/distro': for replacement: Permission denied
    /etc/dconf/db/distro.d: Failed to create file “/etc/dconf/db/distro.9SPS11”: Permission denied
    warning: Failed to open '/etc/dconf/db/local': for replacement: Permission denied
    /etc/dconf/db/local.d: Failed to create file “/etc/dconf/db/local.3UPS11”: Permission denied
    warning: Failed to open '/etc/dconf/db/site': for replacement: Permission denied
    /etc/dconf/db/site.d: Failed to create file “/etc/dconf/db/site.MXPS11”: Permission denied
    warning: Failed to open '/etc/dconf/db/ibus': for replacement: Permission denied
    /etc/dconf/db/ibus.d: Failed to create file “/etc/dconf/db/ibus.6EPS11”: Permission denied
    warning: Failed to open '/etc/dconf/db/gdm': for replacement: Permission denied
    /etc/dconf/db/gdm.d: Failed to create file “/etc/dconf/db/gdm.QGPS11”: Permission denied
    error: failed to update at least one of the databases
    /tmp/oscap.XzwYi4/fix-XXEgX2MO: line 55: /etc/dconf/db/distro.d/locks/00-security-settings-lock: Permission denied
    warning: Failed to open '/etc/dconf/db/distro': for replacement: Permission denied
    /etc/dconf/db/distro.d: Failed to create file “/etc/dconf/db/distro.13US11”: Permission denied
    warning: Failed to open '/etc/dconf/db/local': for replacement: Permission denied
    /etc/dconf/db/local.d: Failed to create file “/etc/dconf/db/local.E7US11”: Permission denied
    warning: Failed to open '/etc/dconf/db/site': for replacement: Permission denied
    /etc/dconf/db/site.d: Failed to create file “/etc/dconf/db/site.GBVS11”: Permission denied
    warning: Failed to open '/etc/dconf/db/ibus': for replacement: Permission denied
    /etc/dconf/db/ibus.d: Failed to create file “/etc/dconf/db/ibus.IFWS11”: Permission denied
    warning: Failed to open '/etc/dconf/db/gdm': for replacement: Permission denied
    /etc/dconf/db/gdm.d: Failed to create file “/etc/dconf/db/gdm.TSVS11”: Permission denied
    error: failed to update at least one of the databases

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then

    # Check for setting in any of the DConf db directories
    # If files contain ibus or distro, ignore them.
    # The assignment assumes that individual filenames don't contain :
    readarray -t SETTINGSFILES < <(grep -r "\\[org/gnome/login-screen\\]" "/etc/dconf/db/" \
                                    | grep -v 'distro\|ibus\|distro.d' | cut -d":" -f1)
    DCONFFILE="/etc/dconf/db/distro.d/00-security-settings"
    DBDIR="/etc/dconf/db/distro.d"

    mkdir -p "${DBDIR}"

    # Comment out the configurations in databases different from the target one
    if [ "${#SETTINGSFILES[@]}" -ne 0 ]
    then
        if grep -q "^\\s*disable-user-list\\s*=" "${SETTINGSFILES[@]}"
        then

            sed -Ei "s/(^\s*)disable-user-list(\s*=)/#\1disable-user-list\2/g" "${SETTINGSFILES[@]}"
        fi
    fi

    [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}"
    if ! grep -q "\\[org/gnome/login-screen\\]" "${DCONFFILE}"
    then
        printf '%s\n' "[org/gnome/login-screen]" >> ${DCONFFILE}
    fi

    escaped_value="$(sed -e 's/\\/\\\\/g' <<< "true")"
    if grep -q "^\\s*disable-user-list\\s*=" "${DCONFFILE}"
    then
            sed -i "s/\\s*disable-user-list\\s*=\\s*.*/disable-user-list=${escaped_value}/g" "${DCONFFILE}"
        else
            sed -i "\\|\\[org/gnome/login-screen\\]|a\\disable-user-list=${escaped_value}" "${DCONFFILE}"
    fi

    dconf update
    # Check for setting in any of the DConf db directories
    LOCKFILES=$(grep -r "^/org/gnome/login-screen/disable-user-list$" "/etc/dconf/db/" \
                | grep -v 'distro\|ibus\|distro.d' | grep ":" | cut -d":" -f1)
    LOCKSFOLDER="/etc/dconf/db/distro.d/locks"

    mkdir -p "${LOCKSFOLDER}"

    # Comment out the configurations in databases different from the target one
    if [[ ! -z "${LOCKFILES}" ]]
    then
        sed -i -E "s|^/org/gnome/login-screen/disable-user-list$|#&|" "${LOCKFILES[@]}"
    fi

    if ! grep -qr "^/org/gnome/login-screen/disable-user-list$" /etc/dconf/db/distro.d/
    then
        echo "/org/gnome/login-screen/disable-user-list" >> "/etc/dconf/db/distro.d/locks/00-security-settings-lock"
    fi

    dconf update

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | unknown

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-88285-2
      - NIST-800-53-AC-23
      - NIST-800-53-CM-6(a)
      - dconf_gnome_disable_user_list
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Disable the GNOME3 Login User List
      ini_file:
        dest: /etc/dconf/db/distro.d/00-security-settings
        section: org/gnome/login-screen
        option: disable-user-list
        value: 'true'
        no_extra_spaces: true
        create: true
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-88285-2
      - NIST-800-53-AC-23
      - NIST-800-53-CM-6(a)
      - dconf_gnome_disable_user_list
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Prevent user modification of GNOME3 disablement of Login User List
      lineinfile:
        path: /etc/dconf/db/distro.d/locks/00-security-settings-lock
        regexp: ^/org/gnome/login-screen/disable-user-list$
        line: /org/gnome/login-screen/disable-user-list
        create: true
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-88285-2
      - NIST-800-53-AC-23
      - NIST-800-53-CM-6(a)
      - dconf_gnome_disable_user_list
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Dconf Update
      command: dconf update
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-88285-2
      - NIST-800-53-AC-23
      - NIST-800-53-CM-6(a)
      - dconf_gnome_disable_user_list
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

OVAL definition:

Definition ID:

oval:ssg-dconf_gnome_disable_user_list:def:1

Class:

compliance

Title:

Disable the GNOME3 Login User List

Version:

1

Description:

Disable the GNOME3 GUI listing of all known users on the login screen.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-dconf_gnome_disable_user_list:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#package_gdm
CPE platform required by rule:
#machine
Set the GNOME3 Login Warning Banner Text medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_dconf_gnome_login_banner_text
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86529-5

References:

1, 12, 15, 16, DSS05.04, DSS05.10, DSS06.10, 3.1.9, CCI-000048, CCI-001384, CCI-001385, CCI-001386, CCI-001387, CCI-001388, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, AC-8(a), AC-8(c), PR.AC-7, FMT_MOF_EXT.1, SRG-OS-000023-GPOS-00006, SRG-OS-000228-GPOS-00088, 1.8.2
Description:
In the default graphical environment, configuring the login warning banner text in the GNOME Display Manager's login screen can be configured on the login screen by setting `banner-message-text` to `'APPROVED_BANNER'` where APPROVED_BANNER is the approved banner for your environment.
To enable, add or edit `banner-message-text` to `/etc/dconf/db/distro.d/00-security-settings`. For example:

    [org/gnome/login-screen]
    banner-message-text='APPROVED_BANNER'

Once the setting has been added, add a lock to `/etc/dconf/db/distro.d/locks/00-security-settings-lock` to prevent user modification. For example:

    /org/gnome/login-screen/banner-message-text

After the settings have been set, run `dconf update`. When entering a warning banner that spans several lines, remember to begin and end the string with `'` and use `\n` for new lines.
Rationale:

An appropriate warning message reinforces policy awareness during the logon process and facilitates possible legal action against attackers.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    /tmp/oscap.QYCA3s/fix-XXxD5YtJ: line 44: /etc/dconf/db/distro.d/00-security-settings: Permission denied
    grep: /etc/dconf/db/distro.d/00-security-settings: No such file or directory
    /tmp/oscap.QYCA3s/fix-XXxD5YtJ: line 47: /etc/dconf/db/distro.d/00-security-settings: Permission denied
    grep: /etc/dconf/db/distro.d/00-security-settings: No such file or directory
    sed: can't read /etc/dconf/db/distro.d/00-security-settings: No such file or directory
    warning: Failed to open '/etc/dconf/db/distro': for replacement: Permission denied
    /etc/dconf/db/distro.d: Failed to create file “/etc/dconf/db/distro.038C21”: Permission denied
    warning: Failed to open '/etc/dconf/db/local': for replacement: Permission denied
    /etc/dconf/db/local.d: Failed to create file “/etc/dconf/db/local.P68C21”: Permission denied
    warning: Failed to open '/etc/dconf/db/site': for replacement: Permission denied
    /etc/dconf/db/site.d: Failed to create file “/etc/dconf/db/site.T68C21”: Permission denied
    warning: Failed to open '/etc/dconf/db/ibus': for replacement: Permission denied
    /etc/dconf/db/ibus.d: Failed to create file “/etc/dconf/db/ibus.R69C21”: Permission denied
    warning: Failed to open '/etc/dconf/db/gdm': for replacement: Permission denied
    /etc/dconf/db/gdm.d: Failed to create file “/etc/dconf/db/gdm.V79C21”: Permission denied
    error: failed to update at least one of the databases
    /tmp/oscap.QYCA3s/fix-XXxD5YtJ: line 74: /etc/dconf/db/distro.d/locks/00-security-settings-lock: Permission denied
    warning: Failed to open '/etc/dconf/db/distro': for replacement: Permission denied
    /etc/dconf/db/distro.d: Failed to create file “/etc/dconf/db/distro.F8ND21”: Permission denied
    warning: Failed to open '/etc/dconf/db/local': for replacement: Permission denied
    /etc/dconf/db/local.d: Failed to create file “/etc/dconf/db/local.O9ND21”: Permission denied
    warning: Failed to open '/etc/dconf/db/site': for replacement: Permission denied
    /etc/dconf/db/site.d: Failed to create file “/etc/dconf/db/site.X9ND21”: Permission denied
    warning: Failed to open '/etc/dconf/db/ibus': for replacement: Permission denied
    /etc/dconf/db/ibus.d: Failed to create file “/etc/dconf/db/ibus.W9OD21”: Permission denied
    warning: Failed to open '/etc/dconf/db/gdm': for replacement: Permission denied
    /etc/dconf/db/gdm.d: Failed to create file “/etc/dconf/db/gdm.BCPD21”: Permission denied
    error: failed to update at least one of the databases

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q gdm; then

    login_banner_text='^(Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.|^(?!.*(\\|fedora|rhel|sle|ubuntu)).*)$'

    # Multiple regexes transform the banner regex into a usable banner
    # 0 - Remove anchors around the banner text
    login_banner_text=$(echo "$login_banner_text" | sed 's/^\^\(.*\)\$$/\1/g')
    # 1 - Keep only the first banners if there are multiple
    #    (dod_banners contains the long and short banner)
    login_banner_text=$(echo "$login_banner_text" | sed 's/^(\(.*\.\)|.*)$/\1/g')
    # 2 - Add spaces ' '. (Transforms regex for "space or newline" into a " ")
    login_banner_text=$(echo "$login_banner_text" | sed 's/\[\\s\\n\]+/ /g')
    # 3 - Adds newline "tokens". (Transforms "(?:\[\\n\]+|(?:\\n)+)" into "(n)*")
    login_banner_text=$(echo "$login_banner_text" | sed 's/(?:\[\\n\]+|(?:\\\\n)+)/(n)*/g')
    # 4 - Remove any leftover backslash. (From any parethesis in the banner, for example).
    login_banner_text=$(echo "$login_banner_text" | sed 's/\\//g')
    # 5 - Removes the newline "token." (Transforms them into newline escape sequences "\n").
    #    ( Needs to be done after 4, otherwise the escapce sequence will become just "n".
    login_banner_text=$(echo "$login_banner_text" | sed 's/(n)\*/\\n/g')

    # Check for setting in any of the DConf db directories
    # If files contain ibus or distro, ignore them.
    # The assignment assumes that individual filenames don't contain :
    readarray -t SETTINGSFILES < <(grep -r "\\[org/gnome/login-screen\\]" "/etc/dconf/db/" \
                                    | grep -v 'distro\|ibus\|distro.d' | cut -d":" -f1)
    DCONFFILE="/etc/dconf/db/distro.d/00-security-settings"
    DBDIR="/etc/dconf/db/distro.d"

    mkdir -p "${DBDIR}"

    # Comment out the configurations in databases different from the target one
    if [ "${#SETTINGSFILES[@]}" -ne 0 ]
    then
        if grep -q "^\\s*banner-message-text\\s*=" "${SETTINGSFILES[@]}"
        then

            sed -Ei "s/(^\s*)banner-message-text(\s*=)/#\1banner-message-text\2/g" "${SETTINGSFILES[@]}"
        fi
    fi

    [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}"
    if ! grep -q "\\[org/gnome/login-screen\\]" "${DCONFFILE}"
    then
        printf '%s\n' "[org/gnome/login-screen]" >> ${DCONFFILE}
    fi

    escaped_value="$(sed -e 's/\\/\\\\/g' <<< "'${login_banner_text}'")"
    if grep -q "^\\s*banner-message-text\\s*=" "${DCONFFILE}"
    then
            sed -i "s/\\s*banner-message-text\\s*=\\s*.*/banner-message-text=${escaped_value}/g" "${DCONFFILE}"
        else
            sed -i "\\|\\[org/gnome/login-screen\\]|a\\banner-message-text=${escaped_value}" "${DCONFFILE}"
    fi

    dconf update
    # Check for setting in any of the DConf db directories
    LOCKFILES=$(grep -r "^/org/gnome/login-screen/banner-message-text$" "/etc/dconf/db/" \
                | grep -v 'distro\|ibus\|distro.d' | grep ":" | cut -d":" -f1)
    LOCKSFOLDER="/etc/dconf/db/distro.d/locks"

    mkdir -p "${LOCKSFOLDER}"

    # Comment out the configurations in databases different from the target one
    if [[ ! -z "${LOCKFILES}" ]]
    then
        sed -i -E "s|^/org/gnome/login-screen/banner-message-text$|#&|" "${LOCKFILES[@]}"
    fi

    if ! grep -qr "^/org/gnome/login-screen/banner-message-text$" /etc/dconf/db/distro.d/
    then
        echo "/org/gnome/login-screen/banner-message-text" >> "/etc/dconf/db/distro.d/locks/00-security-settings-lock"
    fi

    dconf update

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | unknown

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-86529-5
      - NIST-800-171-3.1.9
      - NIST-800-53-AC-8(a)
      - NIST-800-53-AC-8(c)
      - dconf_gnome_login_banner_text
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy
    - name: XCCDF Value login_banner_text # promote to variable
      set_fact:
        login_banner_text: !!str ^(Authorized[\s\n]+uses[\s\n]+only\.[\s\n]+All[\s\n]+activity[\s\n]+may[\s\n]+be[\s\n]+monitored[\s\n]+and[\s\n]+reported\.|^(?!.*(\\|fedora|rhel|sle|ubuntu)).*)$
      tags:
        - always

    - name: Set the GNOME3 Login Warning Banner Text
      file:
        path: /etc/dconf/db/{{ item }}
        owner: root
        group: root
        mode: 493
        state: directory
      with_items:
      - distro.d
      - distro.d/locks
      when: '"gdm" in ansible_facts.packages'
      tags:
      - CCE-86529-5
      - NIST-800-171-3.1.9
      - NIST-800-53-AC-8(a)
      - NIST-800-53-AC-8(c)
      - dconf_gnome_login_banner_text
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Set the GNOME3 Login Warning Banner Text
      file:
        path: /etc/dconf/db/distro.d/{{ item }}
        owner: root
        group: root
        mode: 420
        state: touch
      with_items:
      - 00-security-settings
      - locks/00-security-settings-lock
      when: '"gdm" in ansible_facts.packages'
      tags:
      - CCE-86529-5
      - NIST-800-171-3.1.9
      - NIST-800-53-AC-8(a)
      - NIST-800-53-AC-8(c)
      - dconf_gnome_login_banner_text
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Set the GNOME3 Login Warning Banner Text
      ini_file:
        dest: /etc/dconf/db/distro.d/00-security-settings
        section: org/gnome/login-screen
        option: banner-message-text
        value: '''{{ login_banner_text | regex_replace("^\^(.*)\$$", "\1") | regex_replace("^\((.*\.)\|.*\)$",
          "\1") | regex_replace("\[\\s\\n\]\+"," ") | regex_replace("\(\?:\[\\n\]\+\|\(\?:\\\\n\)\+\)",
          "(n)*") | regex_replace("\\", "") | regex_replace("\(n\)\*", "\\n") }}'''
        create: true
        no_extra_spaces: true
      when: '"gdm" in ansible_facts.packages'
      tags:
      - CCE-86529-5
      - NIST-800-171-3.1.9
      - NIST-800-53-AC-8(a)
      - NIST-800-53-AC-8(c)
      - dconf_gnome_login_banner_text
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Prevent user modification of the GNOME3 Login Warning Banner Text
      lineinfile:
        path: /etc/dconf/db/distro.d/locks/00-security-settings-lock
        regexp: ^/org/gnome/login-screen/banner-message-text$
        line: /org/gnome/login-screen/banner-message-text
        create: true
        state: present
      when: '"gdm" in ansible_facts.packages'
      tags:
      - CCE-86529-5
      - NIST-800-171-3.1.9
      - NIST-800-53-AC-8(a)
      - NIST-800-53-AC-8(c)
      - dconf_gnome_login_banner_text
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Dconf Update
      command: dconf update
      when: '"gdm" in ansible_facts.packages'
      tags:
      - CCE-86529-5
      - NIST-800-171-3.1.9
      - NIST-800-53-AC-8(a)
      - NIST-800-53-AC-8(c)
      - dconf_gnome_login_banner_text
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

OVAL definition:

Definition ID:

oval:ssg-dconf_gnome_login_banner_text:def:1

Class:

compliance

Title:

Set the GNOME3 Login Warning Banner Text

Version:

1

Description:

Enable the GUI warning banner.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-dconf_gnome_login_banner_text:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#package_gdm
Set GNOME3 Screensaver Inactivity Timeout medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_dconf_gnome_screensaver_idle_delay
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86510-5

References:

1, 12, 15, 16, 5.5.5, DSS05.04, DSS05.10, DSS06.10, 3.1.10, CCI-000057, CCI-000060, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, AC-11(a), CM-6(a), PR.AC-7, FMT_MOF_EXT.1, Req-8.1.8, SRG-OS-000029-GPOS-00010, SRG-OS-000031-GPOS-00012, 1.8.4
Description:
The idle time-out value for inactivity in the GNOME3 desktop is configured via the `idle-delay` setting must be set under an appropriate configuration file(s) in the `/etc/dconf/db/local.d` directory and locked in `/etc/dconf/db/local.d/locks` directory to prevent user modification.
For example, to configure the system for a 15 minute delay, add the following to `/etc/dconf/db/local.d/00-security-settings`:

    [org/gnome/desktop/session]
    idle-delay=uint32 900

Rationale:

A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity of the information system but does not logout because of the temporary nature of the absence. Rather than relying on the user to manually lock their operating system session prior to vacating the vicinity, GNOME3 can be configured to identify when a user's session has idled and take action to initiate a session lock.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    /tmp/oscap.g2SWuc/fix-XXY26jCo: line 28: /etc/dconf/db/local.d/00-security-settings: Permission denied
    grep: /etc/dconf/db/local.d/00-security-settings: No such file or directory
    /tmp/oscap.g2SWuc/fix-XXY26jCo: line 31: /etc/dconf/db/local.d/00-security-settings: Permission denied
    grep: /etc/dconf/db/local.d/00-security-settings: No such file or directory
    sed: can't read /etc/dconf/db/local.d/00-security-settings: No such file or directory
    warning: Failed to open '/etc/dconf/db/distro': for replacement: Permission denied
    /etc/dconf/db/distro.d: Failed to create file “/etc/dconf/db/distro.FS5Z11”: Permission denied
    warning: Failed to open '/etc/dconf/db/local': for replacement: Permission denied
    /etc/dconf/db/local.d: Failed to create file “/etc/dconf/db/local.LU5Z11”: Permission denied
    warning: Failed to open '/etc/dconf/db/site': for replacement: Permission denied
    /etc/dconf/db/site.d: Failed to create file “/etc/dconf/db/site.NZ5Z11”: Permission denied
    warning: Failed to open '/etc/dconf/db/ibus': for replacement: Permission denied
    /etc/dconf/db/ibus.d: Failed to create file “/etc/dconf/db/ibus.0G5Z11”: Permission denied
    warning: Failed to open '/etc/dconf/db/gdm': for replacement: Permission denied
    /etc/dconf/db/gdm.d: Failed to create file “/etc/dconf/db/gdm.BK5Z11”: Permission denied
    error: failed to update at least one of the databases

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then

    inactivity_timeout_value='900'

    # Check for setting in any of the DConf db directories
    # If files contain ibus or distro, ignore them.
    # The assignment assumes that individual filenames don't contain :
    readarray -t SETTINGSFILES < <(grep -r "\\[org/gnome/desktop/session\\]" "/etc/dconf/db/" \
                                    | grep -v 'distro\|ibus\|local.d' | cut -d":" -f1)
    DCONFFILE="/etc/dconf/db/local.d/00-security-settings"
    DBDIR="/etc/dconf/db/local.d"

    mkdir -p "${DBDIR}"

    # Comment out the configurations in databases different from the target one
    if [ "${#SETTINGSFILES[@]}" -ne 0 ]
    then
        if grep -q "^\\s*idle-delay\\s*=" "${SETTINGSFILES[@]}"
        then

            sed -Ei "s/(^\s*)idle-delay(\s*=)/#\1idle-delay\2/g" "${SETTINGSFILES[@]}"
        fi
    fi

    [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}"
    if ! grep -q "\\[org/gnome/desktop/session\\]" "${DCONFFILE}"
    then
        printf '%s\n' "[org/gnome/desktop/session]" >> ${DCONFFILE}
    fi

    escaped_value="$(sed -e 's/\\/\\\\/g' <<< "uint32 ${inactivity_timeout_value}")"
    if grep -q "^\\s*idle-delay\\s*=" "${DCONFFILE}"
    then
            sed -i "s/\\s*idle-delay\\s*=\\s*.*/idle-delay=${escaped_value}/g" "${DCONFFILE}"
        else
            sed -i "\\|\\[org/gnome/desktop/session\\]|a\\idle-delay=${escaped_value}" "${DCONFFILE}"
    fi

    dconf update

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | unknown

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-86510-5
      - CJIS-5.5.5
      - NIST-800-171-3.1.10
      - NIST-800-53-AC-11(a)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.8
      - dconf_gnome_screensaver_idle_delay
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy
    - name: XCCDF Value inactivity_timeout_value # promote to variable
      set_fact:
        inactivity_timeout_value: !!str 900
      tags:
        - always

    - name: Set GNOME3 Screensaver Inactivity Timeout
      ini_file:
        dest: /etc/dconf/db/local.d/00-security-settings
        section: org/gnome/desktop/session
        option: idle-delay
        value: uint32 {{ inactivity_timeout_value }}
        create: true
        no_extra_spaces: true
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-86510-5
      - CJIS-5.5.5
      - NIST-800-171-3.1.10
      - NIST-800-53-AC-11(a)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.8
      - dconf_gnome_screensaver_idle_delay
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Dconf Update
      command: dconf update
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-86510-5
      - CJIS-5.5.5
      - NIST-800-171-3.1.10
      - NIST-800-53-AC-11(a)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.8
      - dconf_gnome_screensaver_idle_delay
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

OVAL definition:

Definition ID:

oval:ssg-dconf_gnome_screensaver_idle_delay:def:1

Class:

compliance

Title:

Set GNOME3 Screensaver Inactivity Timeout

Version:

2

Description:

The allowed period of inactivity before the screensaver is activated.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-dconf_gnome_screensaver_idle_delay:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#package_gdm
CPE platform required by rule:
#machine
Set GNOME3 Screensaver Lock Delay After Activation Period medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_dconf_gnome_screensaver_lock_delay
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86954-5

References:

1, 12, 15, 16, DSS05.04, DSS05.10, DSS06.10, 3.1.10, CCI-000056, CCI-000057, CCI-000060, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, AC-11(a), CM-6(a), PR.AC-7, FMT_MOF_EXT.1, Req-8.1.8, SRG-OS-000029-GPOS-00010, SRG-OS-000031-GPOS-00012, 1.8.4
Description:
To activate the locking delay of the screensaver in the GNOME3 desktop when the screensaver is activated, add or set `lock-delay` to `uint32 5` in `/etc/dconf/db/local.d/00-security-settings`. For example:

    [org/gnome/desktop/screensaver]
    lock-delay=uint32 5

After the settings have been set, run `dconf update`.
Rationale:

A session lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity of the information system but does not want to logout because of the temporary nature of the absense.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    /tmp/oscap.YHOePG/fix-XXEmZXn0: line 28: /etc/dconf/db/local.d/00-security-settings: Permission denied
    grep: /etc/dconf/db/local.d/00-security-settings: No such file or directory
    /tmp/oscap.YHOePG/fix-XXEmZXn0: line 31: /etc/dconf/db/local.d/00-security-settings: Permission denied
    grep: /etc/dconf/db/local.d/00-security-settings: No such file or directory
    sed: can't read /etc/dconf/db/local.d/00-security-settings: No such file or directory
    warning: Failed to open '/etc/dconf/db/distro': for replacement: Permission denied
    /etc/dconf/db/distro.d: Failed to create file “/etc/dconf/db/distro.Q8BY11”: Permission denied
    warning: Failed to open '/etc/dconf/db/local': for replacement: Permission denied
    /etc/dconf/db/local.d: Failed to create file “/etc/dconf/db/local.1ACY11”: Permission denied
    warning: Failed to open '/etc/dconf/db/site': for replacement: Permission denied
    /etc/dconf/db/site.d: Failed to create file “/etc/dconf/db/site.09BY11”: Permission denied
    warning: Failed to open '/etc/dconf/db/ibus': for replacement: Permission denied
    /etc/dconf/db/ibus.d: Failed to create file “/etc/dconf/db/ibus.BUBY11”: Permission denied
    warning: Failed to open '/etc/dconf/db/gdm': for replacement: Permission denied
    /etc/dconf/db/gdm.d: Failed to create file “/etc/dconf/db/gdm.0XBY11”: Permission denied
    error: failed to update at least one of the databases

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then

    var_screensaver_lock_delay='5'

    # Check for setting in any of the DConf db directories
    # If files contain ibus or distro, ignore them.
    # The assignment assumes that individual filenames don't contain :
    readarray -t SETTINGSFILES < <(grep -r "\\[org/gnome/desktop/screensaver\\]" "/etc/dconf/db/" \
                                    | grep -v 'distro\|ibus\|local.d' | cut -d":" -f1)
    DCONFFILE="/etc/dconf/db/local.d/00-security-settings"
    DBDIR="/etc/dconf/db/local.d"

    mkdir -p "${DBDIR}"

    # Comment out the configurations in databases different from the target one
    if [ "${#SETTINGSFILES[@]}" -ne 0 ]
    then
        if grep -q "^\\s*lock-delay\\s*=" "${SETTINGSFILES[@]}"
        then

            sed -Ei "s/(^\s*)lock-delay(\s*=)/#\1lock-delay\2/g" "${SETTINGSFILES[@]}"
        fi
    fi

    [ ! -z "${DCONFFILE}" ] && echo "" >> "${DCONFFILE}"
    if ! grep -q "\\[org/gnome/desktop/screensaver\\]" "${DCONFFILE}"
    then
        printf '%s\n' "[org/gnome/desktop/screensaver]" >> ${DCONFFILE}
    fi

    escaped_value="$(sed -e 's/\\/\\\\/g' <<< "uint32 ${var_screensaver_lock_delay}")"
    if grep -q "^\\s*lock-delay\\s*=" "${DCONFFILE}"
    then
            sed -i "s/\\s*lock-delay\\s*=\\s*.*/lock-delay=${escaped_value}/g" "${DCONFFILE}"
        else
            sed -i "\\|\\[org/gnome/desktop/screensaver\\]|a\\lock-delay=${escaped_value}" "${DCONFFILE}"
    fi

    dconf update

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | unknown

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-86954-5
      - NIST-800-171-3.1.10
      - NIST-800-53-AC-11(a)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.8
      - dconf_gnome_screensaver_lock_delay
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy
    - name: XCCDF Value var_screensaver_lock_delay # promote to variable
      set_fact:
        var_screensaver_lock_delay: !!str 5
      tags:
        - always

    - name: Set GNOME3 Screensaver Lock Delay After Activation Period
      ini_file:
        dest: /etc/dconf/db/local.d/00-security-settings
        section: org/gnome/desktop/screensaver
        option: lock-delay
        value: uint32 {{ var_screensaver_lock_delay }}
        create: true
        no_extra_spaces: true
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-86954-5
      - NIST-800-171-3.1.10
      - NIST-800-53-AC-11(a)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.8
      - dconf_gnome_screensaver_lock_delay
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Dconf Update
      command: dconf update
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-86954-5
      - NIST-800-171-3.1.10
      - NIST-800-53-AC-11(a)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.8
      - dconf_gnome_screensaver_lock_delay
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

OVAL definition:

Definition ID:

oval:ssg-dconf_gnome_screensaver_lock_delay:def:1

Class:

compliance

Title:

Set GNOME3 Screensaver Lock Delay After Activation Period

Version:

2

Description:

Idle activation of the screen lock should be enabled immediately or after a delay.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-dconf_gnome_screensaver_lock_delay:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#package_gdm
CPE platform required by rule:
#machine
Ensure Users Cannot Change GNOME3 Screensaver Settings medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_dconf_gnome_screensaver_user_locks
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-87491-7

References:

1, 12, 15, 16, DSS05.04, DSS05.10, DSS06.10, 3.1.10, CCI-000057, CCI-000060, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, CM-6(a), PR.AC-7, FMT_MOF_EXT.1, SRG-OS-000029-GPOS-00010, SRG-OS-000031-GPOS-00012, 1.8.5
Description:
If not already configured, ensure that users cannot change GNOME3 screensaver lock settings by adding `/org/gnome/desktop/screensaver/lock-delay` to `/etc/dconf/db/local.d/locks/00-security-settings-lock` to prevent user modification. For example:

    /org/gnome/desktop/screensaver/lock-delay

After the settings have been set, run `dconf update`.
Rationale:

A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity of the information system but does not logout because of the temporary nature of the absence. Rather than relying on the user to manually lock their operating system session prior to vacating the vicinity, GNOME desktops can be configured to identify when a user's session has idled and take action to initiate the session lock. As such, users should not be allowed to change session settings.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    /tmp/oscap.Q4HH8I/fix-XXWpRska: line 19: /etc/dconf/db/local.d/locks/00-security-settings-lock: Permission denied
    warning: Failed to open '/etc/dconf/db/distro': for replacement: Permission denied
    /etc/dconf/db/distro.d: Failed to create file “/etc/dconf/db/distro.N50Y11”: Permission denied
    warning: Failed to open '/etc/dconf/db/local': for replacement: Permission denied
    /etc/dconf/db/local.d: Failed to create file “/etc/dconf/db/local.X80Y11”: Permission denied
    warning: Failed to open '/etc/dconf/db/site': for replacement: Permission denied
    /etc/dconf/db/site.d: Failed to create file “/etc/dconf/db/site.R70Y11”: Permission denied
    warning: Failed to open '/etc/dconf/db/ibus': for replacement: Permission denied
    /etc/dconf/db/ibus.d: Failed to create file “/etc/dconf/db/ibus.7A2Y11”: Permission denied
    warning: Failed to open '/etc/dconf/db/gdm': for replacement: Permission denied
    /etc/dconf/db/gdm.d: Failed to create file “/etc/dconf/db/gdm.SC2Y11”: Permission denied
    error: failed to update at least one of the databases

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then

    # Check for setting in any of the DConf db directories
    LOCKFILES=$(grep -r "^/org/gnome/desktop/screensaver/lock-delay$" "/etc/dconf/db/" \
                | grep -v 'distro\|ibus\|local.d' | grep ":" | cut -d":" -f1)
    LOCKSFOLDER="/etc/dconf/db/local.d/locks"

    mkdir -p "${LOCKSFOLDER}"

    # Comment out the configurations in databases different from the target one
    if [[ ! -z "${LOCKFILES}" ]]
    then
        sed -i -E "s|^/org/gnome/desktop/screensaver/lock-delay$|#&|" "${LOCKFILES[@]}"
    fi

    if ! grep -qr "^/org/gnome/desktop/screensaver/lock-delay$" /etc/dconf/db/local.d/
    then
        echo "/org/gnome/desktop/screensaver/lock-delay" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock"
    fi

    dconf update

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | unknown

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-87491-7
      - NIST-800-171-3.1.10
      - NIST-800-53-CM-6(a)
      - dconf_gnome_screensaver_user_locks
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Prevent user modification of GNOME lock-delay
      lineinfile:
        path: /etc/dconf/db/local.d/locks/00-security-settings-lock
        regexp: ^/org/gnome/desktop/screensaver/lock-delay$
        line: /org/gnome/desktop/screensaver/lock-delay
        create: true
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-87491-7
      - NIST-800-171-3.1.10
      - NIST-800-53-CM-6(a)
      - dconf_gnome_screensaver_user_locks
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Dconf Update
      command: dconf update
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-87491-7
      - NIST-800-171-3.1.10
      - NIST-800-53-CM-6(a)
      - dconf_gnome_screensaver_user_locks
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

OVAL definition:

Definition ID:

oval:ssg-dconf_gnome_screensaver_user_locks:def:1

Class:

compliance

Title:

Ensure Users Cannot Change GNOME3 Screensaver Settings

Version:

1

Description:

Ensure that users cannot change GNOME3 screensaver idle and lock settings.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-dconf_gnome_screensaver_user_locks:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#package_gdm
CPE platform required by rule:
#machine
Ensure Users Cannot Change GNOME3 Session Idle Settings medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_dconf_gnome_session_idle_user_locks
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-85971-0

References:

1, 12, 15, 16, DSS05.04, DSS05.10, DSS06.10, 3.1.10, CCI-000057, CCI-000060, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, CM-6(a), PR.AC-7, FMT_MOF_EXT.1, Req-8.1.8, SRG-OS-000029-GPOS-00010, SRG-OS-000031-GPOS-00012, 1.8.5
Description:
If not already configured, ensure that users cannot change GNOME3 session idle settings by adding `/org/gnome/desktop/session/idle-delay` to `/etc/dconf/db/local.d/locks/00-security-settings-lock` to prevent user modification. For example:

    /org/gnome/desktop/session/idle-delay

After the settings have been set, run `dconf update`.
Rationale:

A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity of the information system but does not logout because of the temporary nature of the absence. Rather than relying on the user to manually lock their operating system session prior to vacating the vicinity, GNOME desktops can be configured to identify when a user's session has idled and take action to initiate the session lock. As such, users should not be allowed to change session settings.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    /tmp/oscap.fvc7SW/fix-XXUQ1dEx: line 19: /etc/dconf/db/local.d/locks/00-security-settings-lock: Permission denied
    warning: Failed to open '/etc/dconf/db/distro': for replacement: Permission denied
    /etc/dconf/db/distro.d: Failed to create file “/etc/dconf/db/distro.D2G811”: Permission denied
    warning: Failed to open '/etc/dconf/db/local': for replacement: Permission denied
    /etc/dconf/db/local.d: Failed to create file “/etc/dconf/db/local.SKB811”: Permission denied
    warning: Failed to open '/etc/dconf/db/site': for replacement: Permission denied
    /etc/dconf/db/site.d: Failed to create file “/etc/dconf/db/site.KNB811”: Permission denied
    warning: Failed to open '/etc/dconf/db/ibus': for replacement: Permission denied
    /etc/dconf/db/ibus.d: Failed to create file “/etc/dconf/db/ibus.YUB811”: Permission denied
    warning: Failed to open '/etc/dconf/db/gdm': for replacement: Permission denied
    /etc/dconf/db/gdm.d: Failed to create file “/etc/dconf/db/gdm.UWB811”: Permission denied
    error: failed to update at least one of the databases

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then

    # Check for setting in any of the DConf db directories
    LOCKFILES=$(grep -r "^/org/gnome/desktop/session/idle-delay$" "/etc/dconf/db/" \
                | grep -v 'distro\|ibus\|local.d' | grep ":" | cut -d":" -f1)
    LOCKSFOLDER="/etc/dconf/db/local.d/locks"

    mkdir -p "${LOCKSFOLDER}"

    # Comment out the configurations in databases different from the target one
    if [[ ! -z "${LOCKFILES}" ]]
    then
        sed -i -E "s|^/org/gnome/desktop/session/idle-delay$|#&|" "${LOCKFILES[@]}"
    fi

    if ! grep -qr "^/org/gnome/desktop/session/idle-delay$" /etc/dconf/db/local.d/
    then
        echo "/org/gnome/desktop/session/idle-delay" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock"
    fi

    dconf update

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | unknown

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-85971-0
      - NIST-800-171-3.1.10
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.8
      - dconf_gnome_session_idle_user_locks
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Prevent user modification of GNOME Session idle-delay
      lineinfile:
        path: /etc/dconf/db/local.d/locks/00-security-settings-lock
        regexp: ^/org/gnome/desktop/session/idle-delay$
        line: /org/gnome/desktop/session/idle-delay
        create: true
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-85971-0
      - NIST-800-171-3.1.10
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.8
      - dconf_gnome_session_idle_user_locks
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

    - name: Dconf Update
      command: dconf update
      when:
      - '"gdm" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-85971-0
      - NIST-800-171-3.1.10
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.1.8
      - dconf_gnome_session_idle_user_locks
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - unknown_strategy

OVAL definition:

Definition ID:

oval:ssg-dconf_gnome_session_idle_user_locks:def:1

Class:

compliance

Title:

Ensure Users Cannot Change GNOME3 Session Idle Settings

Version:

1

Description:

Ensure that users cannot change GNOME3 session idle settings.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-dconf_gnome_session_idle_user_locks:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#package_gdm
CPE platform required by rule:
#machine
Verify that All World-Writable Directories Have Sticky Bits Set medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_dir_perms_world_writable_sticky_bits
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:50+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83895-3

References:

BP28(R40), 12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-001090, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000138-GPOS-00069, 6.1.12
Description:
When the so-called 'sticky bit' is set on a directory, only the owner of a given file may remove that file from the directory. Without the sticky bit, any user with write access to a directory may remove any file in the directory. Setting the sticky bit prevents users from removing each other's files. In cases where there is no reason for a directory to be world-writable, a better solution is to remove that permission rather than to set the sticky bit. However, if a directory is used by a particular application, consult that application's documentation instead of blindly changing modes.
To set the sticky bit on a world-writable directory DIR, run the following command:

    $ sudo chmod +t DIR

Rationale:

Failing to set the sticky bit on public directories allows unauthorized users to delete files in the directory structure.
The only authorized public directories are those temporary directories supplied with the system, or those designed to be temporary file repositories. The setting is normally reserved for directories used by the system, by users for temporary file storage (such as `/tmp`), and for directories requiring global read/write access.

Remediation Shell script

    df --local -P | awk '{if (NR!=1) print $6}' \
    | xargs -I '$6' find '$6' -xdev -type d \
    \( -perm -0002 -a ! -perm -1000 \) 2>/dev/null \
    -exec chmod a+t {} +

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Get all world-writable directories with no sticky bits set
      shell: |
        set -o pipefail
        df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type d \( -perm -0002 -a ! -perm -1000 \) 2>/dev/null
      register: dir_output
      tags:
      - CCE-83895-3
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - dir_perms_world_writable_sticky_bits
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: ensure sticky bit is set
      file:
        path: '{{ item }}'
        mode: a+t
      with_items:
      - '{{ dir_output.stdout_lines }}'
      tags:
      - CCE-83895-3
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - dir_perms_world_writable_sticky_bits
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-dir_perms_world_writable_sticky_bits:def:1

Class:

compliance

Title:

Verify that All World-Writable Directories Have Sticky Bits Set

Version:

1

Description:

The sticky bit should be set for all world-writable directories.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-dir_perms_world_writable_sticky_bits:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Disable Host-Based Authentication medium error

Rule ID: | xccdf_org.ssgproject.content_rule_disable_host_auth
Result: | error
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90816-0

References:

11, 12, 14, 15, 16, 18, 3, 5, 9, 5.5.6, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.03, DSS06.06, 3.1.12, CCI-000366, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.6.1.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.2.3, CIP-004-6 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.2, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, AC-3, AC-17(a), CM-7(a), CM-7(b), CM-6(a), PR.AC-4, PR.AC-6, PR.IP-1, PR.PT-3, FIA_UAU.1, SRG-OS-000480-GPOS-00229, SRG-OS-000480-VMM-002000, 5.2.8
Description:
SSH's cryptographic host-based authentication is more secure than `.rhosts` authentication. However, it is not recommended that hosts unilaterally trust one another, even within an organization.
The default SSH configuration disables host-based authentication. The appropriate configuration is used if no value is set for `HostbasedAuthentication`.
To explicitly disable host-based authentication, add or correct the following line in `/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf`:

    HostbasedAuthentication no

Rationale:

SSH trust relationships mean a compromise on one host can allow an attacker to move trivially to other hosts.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    mkdir -p /etc/ssh/sshd_config.d
    touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf

    LC_ALL=C sed -i "/^\s*HostbasedAuthentication\s\+/Id" "/etc/ssh/sshd_config"
    LC_ALL=C sed -i "/^\s*HostbasedAuthentication\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf
    if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then

        LC_ALL=C sed -i "/^\s*HostbasedAuthentication\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    else
        touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"

    cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak"
    # Insert before the line matching the regex '^Match'.
    line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" | LC_ALL=C sed 's/:.*//g')"
    if [ -z "$line_number" ]; then
        # There was no match of '^Match', insert at
        # the end of the file.
        printf '%s\n' "HostbasedAuthentication no" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    else
        head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
        printf '%s\n' "HostbasedAuthentication no" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
        tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    fi
    # Clean up after ourselves.
    rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak"

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Disable Host-Based Authentication
      block:

      - name: Deduplicate values from /etc/ssh/sshd_config
        lineinfile:
          path: /etc/ssh/sshd_config
          create: false
          regexp: (?i)^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+
          state: absent

      - name: Check if /etc/ssh/sshd_config.d exists
        stat:
          path: /etc/ssh/sshd_config.d
        register: _etc_ssh_sshd_config_d_exists

      - name: Check if the parameter HostbasedAuthentication is present in /etc/ssh/sshd_config.d
        find:
          paths: /etc/ssh/sshd_config.d
          recurse: 'yes'
          follow: 'no'
          contains: (?i)^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+
        register: _etc_ssh_sshd_config_d_has_parameter
        when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir

      - name: Remove parameter from files in /etc/ssh/sshd_config.d
        lineinfile:
          path: '{{ item.path }}'
          create: false
          regexp: (?i)^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+
          state: absent
        with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}'
        when: _etc_ssh_sshd_config_d_has_parameter.matched

      - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf
        lineinfile:
          path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf
          create: true
          regexp: (?i)^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+
          line: HostbasedAuthentication no
          state: present
          insertbefore: ^[#\s]*Match
          validate: /usr/sbin/sshd -t -f %s
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90816-0
      - CJIS-5.5.6
      - NIST-800-171-3.1.12
      - NIST-800-53-AC-17(a)
      - NIST-800-53-AC-3
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_host_auth
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,%23%09%24OpenBSD%3A%20sshd_config%2Cv%201.103%202018%2F04%2F09%2020%3A41%3A22%20tj%20Exp%20%24%0A%0A%23%20This%20is%20the%20sshd%20server%20system-wide%20configuration%20file.%20%20See%0A%23%20sshd_config%285%29%20for%20more%20information.%0A%0A%23%20This%20sshd%20was%20compiled%20with%20PATH%3D%2Fusr%2Flocal%2Fbin%3A%2Fusr%2Fbin%3A%2Fusr%2Flocal%2Fsbin%3A%2Fusr%2Fsbin%0A%0A%23%20The%20strategy%20used%20for%20options%20in%20the%20default%20sshd_config%20shipped%20with%0A%23%20OpenSSH%20is%20to%20specify%20options%20with%20their%20default%20value%20where%0A%23%20possible%2C%20but%20leave%20them%20commented.%20%20Uncommented%20options%20override%20the%0A%23%20default%20value.%0A%0A%23%20If%20you%20want%20to%20change%20the%20port%20on%20a%20SELinux%20system%2C%20you%20have%20to%20tell%0A%23%20SELinux%20about%20this%20change.%0A%23%20semanage%20port%20-a%20-t%20ssh_port_t%20-p%20tcp%20%23PORTNUMBER%0A%23%0A%23Port%2022%0A%23AddressFamily%20any%0A%23ListenAddress%200.0.0.0%0A%23ListenAddress%20%3A%3A%0A%0AHostKey%20%2Fetc%2Fssh%2Fssh_host_rsa_key%0AHostKey%20%2Fetc%2Fssh%2Fssh_host_ecdsa_key%0AHostKey%20%2Fetc%2Fssh%2Fssh_host_ed25519_key%0A%0A%23%20Ciphers%20and%20keying%0ARekeyLimit%20512M%201h%0A%0A%23%20System-wide%20Crypto%20policy%3A%0A%23%20This%20system%20is%20following%20system-wide%20crypto%20policy.%20The%20changes%20to%0A%23%20Ciphers%2C%20MACs%2C%20KexAlgoritms%20and%20GSSAPIKexAlgorithsm%20will%20not%20have%20any%0A%23%20effect%20here.%20They%20will%20be%20overridden%20by%20command-line%20options%20passed%20on%0A%23%20the%20server%20start%20up.%0A%23%20To%20opt%20out%2C%20uncomment%20a%20line%20with%20redefinition%20of%20%20CRYPTO_POLICY%3D%0A%23%20variable%20in%20%20%2Fetc%2Fsysconfig%2Fsshd%20%20to%20overwrite%20the%20policy.%0A%23%20For%20more%20information%2C%20see%20manual%20page%20for%20update-crypto-policies%288%29.%0A%0A%23%20Logging%0A%23SyslogFacility%20AUTH%0ASyslogFacility%20AUTHPRIV%0A%23LogLevel%20INFO%0A%0A%23%20Authentication%3A%0A%0A%23LoginGraceTime%202m%0APermitRootLogin%20no%0AStrictModes%20yes%0A%23MaxAuthTries%206%0A%23MaxSessions%2010%0A%0APubkeyAuthentication%20yes%0A%0A%23%20The%20default%20is%20to%20check%20both%20.ssh%2Fauthorized_keys%20and%20.ssh%2Fauthorized_keys2%0A%23%20but%20this%20is%20overridden%20so%20installations%20will%20only%20check%20.ssh%2Fauthorized_keys%0AAuthorizedKeysFile%09.ssh%2Fauthorized_keys%0A%0A%23AuthorizedPrincipalsFile%20none%0A%0A%23AuthorizedKeysCommand%20none%0A%23AuthorizedKeysCommandUser%20nobody%0A%0A%23%20For%20this%20to%20work%20you%20will%20also%20need%20host%20keys%20in%20%2Fetc%2Fssh%2Fssh_known_hosts%0AHostbasedAuthentication%20no%0A%23%20Change%20to%20yes%20if%20you%20don%27t%20trust%20~%2F.ssh%2Fknown_hosts%20for%0A%23%20HostbasedAuthentication%0AIgnoreUserKnownHosts%20yes%0A%23%20Don%27t%20read%20the%20user%27s%20~%2F.rhosts%20and%20~%2F.shosts%20files%0AIgnoreRhosts%20yes%0A%0A%23%20To%20disable%20tunneled%20clear%20text%20passwords%2C%20change%20to%20no%20here%21%0A%23PasswordAuthentication%20yes%0APermitEmptyPasswords%20no%0APasswordAuthentication%20no%0A%0A%23%20Change%20to%20no%20to%20disable%20s%2Fkey%20passwords%0A%23ChallengeResponseAuthentication%20yes%0AChallengeResponseAuthentication%20no%0A%0A%23%20Kerberos%20options%0AKerberosAuthentication%20no%0A%23KerberosOrLocalPasswd%20yes%0A%23KerberosTicketCleanup%20yes%0A%23KerberosGetAFSToken%20no%0A%23KerberosUseKuserok%20yes%0A%0A%23%20GSSAPI%20options%0AGSSAPIAuthentication%20no%0AGSSAPICleanupCredentials%20no%0A%23GSSAPIStrictAcceptorCheck%20yes%0A%23GSSAPIKeyExchange%20no%0A%23GSSAPIEnablek5users%20no%0A%0A%23%20Set%20this%20to%20%27yes%27%20to%20enable%20PAM%20authentication%2C%20account%20processing%2C%0A%23%20and%20session%20processing.%20If%20this%20is%20enabled%2C%20PAM%20authentication%20will%0A%23%20be%20allowed%20through%20the%20ChallengeResponseAuthentication%20and%0A%23%20PasswordAuthentication.%20%20Depending%20on%20your%20PAM%20configuration%2C%0A%23%20PAM%20authentication%20via%20ChallengeResponseAuthentication%20may%20bypass%0A%23%20the%20setting%20of%20%22PermitRootLogin%20without-password%22.%0A%23%20If%20you%20just%20want%20the%20PAM%20account%20and%20session%20checks%20to%20run%20without%0A%23%20PAM%20authentication%2C%20then%20enable%20this%20but%20set%20PasswordAuthentication%0A%23%20and%20ChallengeResponseAuthentication%20to%20%27no%27.%0A%23%20WARNING%3A%20%27UsePAM%20no%27%20is%20not%20supported%20in%20Fedora%20and%20may%20cause%20several%0A%23%20problems.%0AUsePAM%20yes%0A%0A%23AllowAgentForwarding%20yes%0A%23AllowTcpForwarding%20yes%0A%23GatewayPorts%20no%0AX11Forwarding%20yes%0A%23X11DisplayOffset%2010%0A%23X11UseLocalhost%20yes%0A%23PermitTTY%20yes%0A%0A%23%20It%20is%20recommended%20to%20use%20pam_motd%20in%20%2Fetc%2Fpam.d%2Fsshd%20instead%20of%20PrintMotd%2C%0A%23%20as%20it%20is%20more%20configurable%20and%20versatile%20than%20the%20built-in%20version.%0APrintMotd%20no%0A%0APrintLastLog%20yes%0A%23TCPKeepAlive%20yes%0APermitUserEnvironment%20no%0ACompression%20no%0AClientAliveInterval%20600%0AClientAliveCountMax%200%0A%23UseDNS%20no%0A%23PidFile%20%2Fvar%2Frun%2Fsshd.pid%0A%23MaxStartups%2010%3A30%3A100%0A%23PermitTunnel%20no%0A%23ChrootDirectory%20none%0A%23VersionAddendum%20none%0A%0A%23%20no%20default%20banner%20path%0ABanner%20%2Fetc%2Fissue%0A%0A%23%20Accept%20locale-related%20environment%20variables%0AAcceptEnv%20LANG%20LC_CTYPE%20LC_NUMERIC%20LC_TIME%20LC_COLLATE%20LC_MONETARY%20LC_MESSAGES%0AAcceptEnv%20LC_PAPER%20LC_NAME%20LC_ADDRESS%20LC_TELEPHONE%20LC_MEASUREMENT%0AAcceptEnv%20LC_IDENTIFICATION%20LC_ALL%20LANGUAGE%0AAcceptEnv%20XMODIFIERS%0A%0A%23%20override%20default%20of%20no%20subsystems%0ASubsystem%09sftp%09%2Fusr%2Flibexec%2Fopenssh%2Fsftp-server%0A%0A%23%20Example%20of%20overriding%20settings%20on%20a%20per-user%20basis%0A%23Match%20User%20anoncvs%0A%23%09X11Forwarding%20no%0A%23%09AllowTcpForwarding%20no%0A%23%09PermitTTY%20no%0A%23%09ForceCommand%20cvs%20server%0A%0AUsePrivilegeSeparation%20sandbox
            mode: 0600
            path: /etc/ssh/sshd_config
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-disable_host_auth:def:1

Class:

compliance

Title:

Disable Host-Based Authentication

Version:

1

Description:

Ensure 'HostbasedAuthentication' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-disable_host_auth:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Enable authselect medium fix unsuccessful

Rule ID: | xccdf_org.ssgproject.content_rule_enable_authselect
Result: | fix unsuccessful
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-89732-2

References:

BP28(R5), CCI-000213, 164.308(a)(1)(ii)(B), 164.308(a)(7)(i), 164.308(a)(7)(ii)(A), 164.310(a)(1), 164.310(a)(2)(i), 164.310(a)(2)(ii), 164.310(a)(2)(iii), 164.310(b), 164.310(c), 164.310(d)(1), 164.310(d)(2)(iii), AC-3, FIA_UAU.1, FIA_AFL.1, SRG-OS-000480-GPOS-00227, 5.4.1
Description:
Configure user authentication setup to use the `authselect` tool. If authselect profile is selected, the rule will enable the sssd profile.
Rationale:

Authselect is a successor to authconfig. It is a tool to select system authentication and identity sources from a list of supported profiles instead of letting the administrator manually build the PAM stack. That way, it avoids potential breakage of configuration, as it ships several tested profiles that are well tested and supported to solve different use-cases.

Warnings:

General warning
If the `sudo authselect select` command returns an error informing that the chosen profile cannot be selected, it is probably because PAM files have already been modified by the administrator. If this is the case, in order to not overwrite the desired changes made by the administrator, the current PAM settings should be investigated before forcing the selection of the chosen authselect profile.

Messages:

Message: Message:

    Fix execution completed and returned: 0

Message: Message:

    Authselect command 'select' can only be run as root!
    Files in the 'pam' package have been altered, so the authselect configuration won't be forced

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    var_authselect_profile='sssd'

    authselect select "$var_authselect_profile"

    if test "$?" -ne 0; then
        if rpm --quiet --verify pam; then
            authselect select --force "$var_authselect_profile"
        else
    	echo "Files in the 'pam' package have been altered, so the authselect configuration won't be forced" >&2
        fi
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | configure

    - name: XCCDF Value var_authselect_profile # promote to variable
      set_fact:
        var_authselect_profile: !!str sssd
      tags:
        - always

    - name: Select authselect profile
      ansible.builtin.command:
        cmd: authselect select "{{ var_authselect_profile }}"
      ignore_errors: true
      register: result_authselect_select
      tags:
      - CCE-89732-2
      - NIST-800-53-AC-3
      - configure_strategy
      - enable_authselect
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

    - name: Verify if PAM has been altered
      ansible.builtin.command:
        cmd: rpm -qV pam
      register: result_altered_authselect
      ignore_errors: true
      when: result_authselect_select is failed
      tags:
      - CCE-89732-2
      - NIST-800-53-AC-3
      - configure_strategy
      - enable_authselect
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

    - name: Informative message based on the authselect integrity check
      ansible.builtin.assert:
        that:
        - result_altered_authselect is success
        fail_msg:
        - Files in the 'pam' package have been altered, so the authselect configuration
          won't be forced.
      tags:
      - CCE-89732-2
      - NIST-800-53-AC-3
      - configure_strategy
      - enable_authselect
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

    - name: Force authselect profile select
      ansible.builtin.command:
        cmd: authselect select --force "{{ var_authselect_profile }}"
      when:
      - result_altered_authselect is success
      - result_authselect_select is failed
      tags:
      - CCE-89732-2
      - NIST-800-53-AC-3
      - configure_strategy
      - enable_authselect
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-enable_authselect:def:1

Class:

compliance

Title:

Enable authselect

Version:

1

Description:

Check that authselect is enabled

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-enable_authselect:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Ensure gpgcheck Enabled In Main dnf Configuration high pass

Rule ID: | xccdf_org.ssgproject.content_rule_ensure_gpgcheck_globally_activated
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

high

Identifiers:

CCE-83457-2

References:

BP28(R15), 11, 2, 3, 9, 5.10.4.1, APO01.06, BAI03.05, BAI06.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS06.02, 3.4.8, CCI-001749, 164.308(a)(1)(ii)(D), 164.312(b), 164.312(c)(1), 164.312(c)(2), 164.312(e)(2)(i), 4.3.4.3.2, 4.3.4.3.3, 4.3.4.4.4, SR 3.1, SR 3.3, SR 3.4, SR 3.8, SR 7.6, A.11.2.4, A.12.1.2, A.12.2.1, A.12.5.1, A.12.6.2, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, CM-5(3), SI-7, SC-12, SC-12(3), CM-6(a), SA-12, SA-12(10), CM-11(a), CM-11(b), PR.DS-6, PR.DS-8, PR.IP-1, FPT_TUD_EXT.1, FPT_TUD_EXT.2, Req-6.2, SRG-OS-000366-GPOS-00153, SRG-OS-000366-VMM-001430, SRG-OS-000370-VMM-001460, SRG-OS-000404-VMM-001650, 1.2.2
Description:
The `gpgcheck` option controls whether RPM packages' signatures are always checked prior to installation. To configure dnf to check package signatures before installing them, ensure the following line appears in `/etc/dnf/dnf.conf` in the `[main]` section:

    gpgcheck=1

Rationale:

Changes to any software components can have significant effects on the overall security of the operating system. This requirement ensures the software has not been tampered with and that it has been provided by a trusted vendor.
Accordingly, patches, service packs, device drivers, or operating system components must be signed with a certificate recognized and approved by the organization.
Verifying the authenticity of the software prior to installation validates the integrity of the patch or upgrade received from a vendor. This ensures the software has not been tampered with and that it has been provided by a trusted vendor. Self-signed certificates are disallowed by this requirement. Certificates used to verify the software must be from an approved Certificate Authority (CA).

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q yum; then

    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/dnf/dnf.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^gpgcheck")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "1"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^gpgcheck\\>" "/etc/dnf/dnf.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^gpgcheck\\>.*/$escaped_formatted_output/gi" "/etc/dnf/dnf.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-83457-2"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/dnf/dnf.conf" >> "/etc/dnf/dnf.conf"
        printf '%s\n' "$formatted_output" >> "/etc/dnf/dnf.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | configure

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-83457-2
      - CJIS-5.10.4.1
      - NIST-800-171-3.4.8
      - NIST-800-53-CM-11(a)
      - NIST-800-53-CM-11(b)
      - NIST-800-53-CM-5(3)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-SA-12
      - NIST-800-53-SA-12(10)
      - NIST-800-53-SC-12
      - NIST-800-53-SC-12(3)
      - NIST-800-53-SI-7
      - PCI-DSS-Req-6.2
      - configure_strategy
      - ensure_gpgcheck_globally_activated
      - high_severity
      - low_complexity
      - medium_disruption
      - no_reboot_needed

    - name: Ensure GPG check is globally activated
      ini_file:
        dest: /etc/dnf/dnf.conf
        section: main
        option: gpgcheck
        value: 1
        no_extra_spaces: true
        create: false
      when: '"yum" in ansible_facts.packages'
      tags:
      - CCE-83457-2
      - CJIS-5.10.4.1
      - NIST-800-171-3.4.8
      - NIST-800-53-CM-11(a)
      - NIST-800-53-CM-11(b)
      - NIST-800-53-CM-5(3)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-SA-12
      - NIST-800-53-SA-12(10)
      - NIST-800-53-SC-12
      - NIST-800-53-SC-12(3)
      - NIST-800-53-SI-7
      - PCI-DSS-Req-6.2
      - configure_strategy
      - ensure_gpgcheck_globally_activated
      - high_severity
      - low_complexity
      - medium_disruption
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-ensure_gpgcheck_globally_activated:def:1

Class:

compliance

Title:

Ensure gpgcheck Enabled In Main dnf Configuration

Version:

1

Description:

The gpgcheck option should be used to ensure that checking of an RPM package's signature always occurs prior to its installation.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-ensure_gpgcheck_globally_activated:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#package_yum
Ensure that /etc/at.deny does not exist medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_at_deny_not_exist
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86946-1

References:

5.1.9
Description:
The file `/etc/at.deny` should not exist. Use `/etc/at.allow` instead.
Rationale:

Access to `at` should be restricted. It is easier to manage an allow list than a deny list.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    #!/bin/bash

        if [[ -f  /etc/at.deny ]]; then
            rm /etc/at.deny
        fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    - name: Remove /etc/at.deny
      file:
        path: /etc/at.deny
        state: absent
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-86946-1
      - disable_strategy
      - file_at_deny_not_exist
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_at_deny_not_exist:def:1

Class:

compliance

Title:

Ensure that /etc/at.deny does not exist

Version:

1

Description:

This test makes sure that/etc/at.deny does not exist.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_at_deny_not_exist:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Ensure that /etc/cron.deny does not exist medium fix unsuccessful

Rule ID: | xccdf_org.ssgproject.content_rule_file_cron_deny_not_exist
Result: | fix unsuccessful
Multi-check rule: | no
Time: | 2023-03-16T15:33:34+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86850-5

References:

5.1.8
Description:
The file `/etc/cron.deny` should not exist. Use `/etc/cron.allow` instead.
Rationale:

Access to `cron` should be restricted. It is easier to manage an allow list than a deny list.

Messages:

Message: Message:

    Fix execution completed and returned: 0

Message: Message:

    rm: remove write-protected regular empty file '/etc/cron.deny'?

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    #!/bin/bash

        if [[ -f  /etc/cron.deny ]]; then
            rm /etc/cron.deny
        fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    - name: Remove /etc/cron.deny
      file:
        path: /etc/cron.deny
        state: absent
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-86850-5
      - disable_strategy
      - file_cron_deny_not_exist
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_cron_deny_not_exist:def:1

Class:

compliance

Title:

Ensure that /etc/cron.deny does not exist

Version:

1

Description:

This test makes sure that/etc/cron.deny does not exist.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_cron_deny_not_exist:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Verify Group Who Owns /etc/at.allow file medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_at_allow
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-87103-8

References:

5.1.9
Description:
If `/etc/at.allow` exists, it must be group-owned by `root`. To properly set the group owner of `/etc/at.allow`, run the command:

    $ sudo chgrp root /etc/at.allow

Rationale:

If the owner of the at.allow file is not set to root, the possibility exists for an unauthorized user to view or edit sensitive information.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    chgrp 0 /etc/at.allow

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/at.allow
      stat:
        path: /etc/at.allow
      register: file_exists
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-87103-8
      - configure_strategy
      - file_groupowner_at_allow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure group owner 0 on /etc/at.allow
      file:
        path: /etc/at.allow
        group: '0'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-87103-8
      - configure_strategy
      - file_groupowner_at_allow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_at_allow:def:1

Class:

compliance

Title:

Verify Group Who Owns /etc/at.allow file

Version:

1

Description:

This test makes sure that /etc/at.allow is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_at_allow:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Verify Group Who Owns Backup group File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_backup_etc_group
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83928-2

References:

CCI-002223, AC-6 (1), SRG-OS-000480-GPOS-00227, 6.1.4
Description:
To properly set the group owner of `/etc/group-`, run the command:

    $ sudo chgrp root /etc/group-

Rationale:

The `/etc/group-` file is a backup file of `/etc/group`, and as such, it contains information regarding groups that are configured on the system. Protection of this file is important for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chgrp 0 /etc/group-

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/group-
      stat:
        path: /etc/group-
      register: file_exists
      tags:
      - CCE-83928-2
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_groupowner_backup_etc_group
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure group owner 0 on /etc/group-
      file:
        path: /etc/group-
        group: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83928-2
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_groupowner_backup_etc_group
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_backup_etc_group:def:1

Class:

compliance

Title:

Verify Group Who Owns Backup group File

Version:

1

Description:

This test makes sure that /etc/group- is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_backup_etc_group:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Group Who Owns Backup gshadow File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_backup_etc_gshadow
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83951-4

References:

CCI-002223, AC-6 (1), SRG-OS-000480-GPOS-00227, 6.1.8
Description:
To properly set the group owner of `/etc/gshadow-`, run the command:

    $ sudo chgrp root /etc/gshadow-

Rationale:

The `/etc/gshadow-` file is a backup of `/etc/gshadow`, and as such, it contains group password hashes. Protection of this file is critical for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chgrp 0 /etc/gshadow-

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/gshadow-
      stat:
        path: /etc/gshadow-
      register: file_exists
      tags:
      - CCE-83951-4
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_groupowner_backup_etc_gshadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure group owner 0 on /etc/gshadow-
      file:
        path: /etc/gshadow-
        group: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83951-4
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_groupowner_backup_etc_gshadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_backup_etc_gshadow:def:1

Class:

compliance

Title:

Verify Group Who Owns Backup gshadow File

Version:

1

Description:

This test makes sure that /etc/gshadow- is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_backup_etc_gshadow:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Group Who Owns Backup passwd File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_backup_etc_passwd
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83933-2

References:

CCI-002223, AC-6 (1), SRG-OS-000480-GPOS-00227, 6.1.2
Description:
To properly set the group owner of `/etc/passwd-`, run the command:

    $ sudo chgrp root /etc/passwd-

Rationale:

The `/etc/passwd-` file is a backup file of `/etc/passwd`, and as such, it contains information about the users that are configured on the system. Protection of this file is critical for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chgrp 0 /etc/passwd-

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/passwd-
      stat:
        path: /etc/passwd-
      register: file_exists
      tags:
      - CCE-83933-2
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_groupowner_backup_etc_passwd
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure group owner 0 on /etc/passwd-
      file:
        path: /etc/passwd-
        group: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83933-2
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_groupowner_backup_etc_passwd
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_backup_etc_passwd:def:1

Class:

compliance

Title:

Verify Group Who Owns Backup passwd File

Version:

1

Description:

This test makes sure that /etc/passwd- is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_backup_etc_passwd:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify User Who Owns Backup shadow File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_backup_etc_shadow
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83938-1

References:

SRG-OS-000480-GPOS-00227, 6.1.6
Description:
To properly set the group owner of `/etc/shadow-`, run the command:

    $ sudo chgrp root /etc/shadow-

Rationale:

The `/etc/shadow-` file is a backup file of `/etc/shadow`, and as such, it contains the list of local system accounts and password hashes. Protection of this file is critical for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chgrp 0 /etc/shadow-

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/shadow-
      stat:
        path: /etc/shadow-
      register: file_exists
      tags:
      - CCE-83938-1
      - configure_strategy
      - file_groupowner_backup_etc_shadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure group owner 0 on /etc/shadow-
      file:
        path: /etc/shadow-
        group: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83938-1
      - configure_strategy
      - file_groupowner_backup_etc_shadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_backup_etc_shadow:def:1

Class:

compliance

Title:

Verify User Who Owns Backup shadow File

Version:

1

Description:

This test makes sure that /etc/shadow- is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_backup_etc_shadow:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Group Who Owns /etc/cron.allow file medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_cron_allow
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86830-7

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-000366, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.8
Description:
If `/etc/cron.allow` exists, it must be group-owned by `root`. To properly set the group owner of `/etc/cron.allow`, run the command:

    $ sudo chgrp root /etc/cron.allow

Rationale:

If the owner of the cron.allow file is not set to root, the possibility exists for an unauthorized user to view or edit sensitive information.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    chgrp 0 /etc/cron.allow

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/cron.allow
      stat:
        path: /etc/cron.allow
      register: file_exists
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-86830-7
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_groupowner_cron_allow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure group owner 0 on /etc/cron.allow
      file:
        path: /etc/cron.allow
        group: '0'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-86830-7
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_groupowner_cron_allow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_cron_allow:def:1

Class:

compliance

Title:

Verify Group Who Owns /etc/cron.allow file

Version:

1

Description:

This test makes sure that /etc/cron.allow is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_cron_allow:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Verify Group Who Owns cron.d medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_cron_d
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84177-5

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.7
Description:
To properly set the group owner of `/etc/cron.d`, run the command:

    $ sudo chgrp root /etc/cron.d

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    find -H /etc/cron.d/ -maxdepth 1 -type d -exec chgrp 0 {} \;

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Ensure group owner on /etc/cron.d/
      file:
        path: /etc/cron.d/
        state: directory
        group: '0'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84177-5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_groupowner_cron_d
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_cron_d:def:1

Class:

compliance

Title:

Verify Group Who Owns cron.d

Version:

1

Description:

This test makes sure that /etc/cron.d/ is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_cron_d:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Group Who Owns cron.daily medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_cron_daily
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84170-0

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.4
Description:
To properly set the group owner of `/etc/cron.daily`, run the command:

    $ sudo chgrp root /etc/cron.daily

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    find -H /etc/cron.daily/ -maxdepth 1 -type d -exec chgrp 0 {} \;

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Ensure group owner on /etc/cron.daily/
      file:
        path: /etc/cron.daily/
        state: directory
        group: '0'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84170-0
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_groupowner_cron_daily
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_cron_daily:def:1

Class:

compliance

Title:

Verify Group Who Owns cron.daily

Version:

1

Description:

This test makes sure that /etc/cron.daily/ is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_cron_daily:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Group Who Owns cron.hourly medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_cron_hourly
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84186-6

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.3
Description:
To properly set the group owner of `/etc/cron.hourly`, run the command:

    $ sudo chgrp root /etc/cron.hourly

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    find -H /etc/cron.hourly/ -maxdepth 1 -type d -exec chgrp 0 {} \;

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Ensure group owner on /etc/cron.hourly/
      file:
        path: /etc/cron.hourly/
        state: directory
        group: '0'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84186-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_groupowner_cron_hourly
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_cron_hourly:def:1

Class:

compliance

Title:

Verify Group Who Owns cron.hourly

Version:

1

Description:

This test makes sure that /etc/cron.hourly/ is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_cron_hourly:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Group Who Owns cron.monthly medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_cron_monthly
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84189-0

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.6
Description:
To properly set the group owner of `/etc/cron.monthly`, run the command:

    $ sudo chgrp root /etc/cron.monthly

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    find -H /etc/cron.monthly/ -maxdepth 1 -type d -exec chgrp 0 {} \;

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Ensure group owner on /etc/cron.monthly/
      file:
        path: /etc/cron.monthly/
        state: directory
        group: '0'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84189-0
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_groupowner_cron_monthly
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_cron_monthly:def:1

Class:

compliance

Title:

Verify Group Who Owns cron.monthly

Version:

1

Description:

This test makes sure that /etc/cron.monthly/ is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_cron_monthly:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Group Who Owns cron.weekly medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_cron_weekly
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84174-2

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.5
Description:
To properly set the group owner of `/etc/cron.weekly`, run the command:

    $ sudo chgrp root /etc/cron.weekly

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    find -H /etc/cron.weekly/ -maxdepth 1 -type d -exec chgrp 0 {} \;

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Ensure group owner on /etc/cron.weekly/
      file:
        path: /etc/cron.weekly/
        state: directory
        group: '0'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84174-2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_groupowner_cron_weekly
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_cron_weekly:def:1

Class:

compliance

Title:

Verify Group Who Owns cron.weekly

Version:

1

Description:

This test makes sure that /etc/cron.weekly/ is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_cron_weekly:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Group Who Owns Crontab medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_crontab
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84171-8

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.2
Description:
To properly set the group owner of `/etc/crontab`, run the command:

    $ sudo chgrp root /etc/crontab

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    chgrp 0 /etc/crontab

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/crontab
      stat:
        path: /etc/crontab
      register: file_exists
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84171-8
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_groupowner_crontab
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure group owner 0 on /etc/crontab
      file:
        path: /etc/crontab
        group: '0'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-84171-8
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_groupowner_crontab
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_crontab:def:1

Class:

compliance

Title:

Verify Group Who Owns Crontab

Version:

1

Description:

This test makes sure that /etc/crontab is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_crontab:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Group Who Owns group File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_etc_group
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83945-6

References:

12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-8.7.c, SRG-OS-000480-GPOS-00227, 6.1.3
Description:
To properly set the group owner of `/etc/group`, run the command:

    $ sudo chgrp root /etc/group

Rationale:

The `/etc/group` file contains information regarding groups that are configured on the system. Protection of this file is important for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chgrp 0 /etc/group

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/group
      stat:
        path: /etc/group
      register: file_exists
      tags:
      - CCE-83945-6
      - CJIS-5.5.2.2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.7.c
      - configure_strategy
      - file_groupowner_etc_group
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure group owner 0 on /etc/group
      file:
        path: /etc/group
        group: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83945-6
      - CJIS-5.5.2.2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.7.c
      - configure_strategy
      - file_groupowner_etc_group
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_etc_group:def:1

Class:

compliance

Title:

Verify Group Who Owns group File

Version:

1

Description:

This test makes sure that /etc/group is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_etc_group:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Group Who Owns gshadow File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_etc_gshadow
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83948-0

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 6.1.7
Description:
To properly set the group owner of `/etc/gshadow`, run the command:

    $ sudo chgrp root /etc/gshadow

Rationale:

The `/etc/gshadow` file contains group password hashes. Protection of this file is critical for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chgrp 0 /etc/gshadow

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/gshadow
      stat:
        path: /etc/gshadow
      register: file_exists
      tags:
      - CCE-83948-0
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_groupowner_etc_gshadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure group owner 0 on /etc/gshadow
      file:
        path: /etc/gshadow
        group: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83948-0
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_groupowner_etc_gshadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_etc_gshadow:def:1

Class:

compliance

Title:

Verify Group Who Owns gshadow File

Version:

1

Description:

This test makes sure that /etc/gshadow is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_etc_gshadow:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Group Ownership of System Login Banner medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_etc_issue
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86699-6

References:

1.7.5
Description:
To properly set the group owner of `/etc/issue`, run the command:

    $ sudo chgrp root /etc/issue

Rationale:

Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance.
Proper group ownership will ensure that only root user can modify the banner.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chgrp 0 /etc/issue

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/issue
      stat:
        path: /etc/issue
      register: file_exists
      tags:
      - CCE-86699-6
      - configure_strategy
      - file_groupowner_etc_issue
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure group owner 0 on /etc/issue
      file:
        path: /etc/issue
        group: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-86699-6
      - configure_strategy
      - file_groupowner_etc_issue
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_etc_issue:def:1

Class:

compliance

Title:

Verify Group Ownership of System Login Banner

Version:

1

Description:

This test makes sure that /etc/issue is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_etc_issue:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Group Ownership of System Login Banner for Remote Connections medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_etc_issue_net
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86052-8

References:

1.7.6
Description:
To properly set the group owner of `/etc/issue.net`, run the command:

    $ sudo chgrp root /etc/issue.net

Rationale:

Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance.
Proper group ownership will ensure that only root user can modify the banner.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chgrp 0 /etc/issue.net

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/issue.net
      stat:
        path: /etc/issue.net
      register: file_exists
      tags:
      - CCE-86052-8
      - configure_strategy
      - file_groupowner_etc_issue_net
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure group owner 0 on /etc/issue.net
      file:
        path: /etc/issue.net
        group: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-86052-8
      - configure_strategy
      - file_groupowner_etc_issue_net
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_etc_issue_net:def:1

Class:

compliance

Title:

Verify Group Ownership of System Login Banner for Remote Connections

Version:

1

Description:

This test makes sure that /etc/issue.net is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_etc_issue_net:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Group Ownership of Message of the Day Banner medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_etc_motd
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86697-0

References:

1.7.4
Description:
To properly set the group owner of `/etc/motd`, run the command:

    $ sudo chgrp root /etc/motd

Rationale:

Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance.
Proper group ownership will ensure that only root user can modify the banner.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chgrp 0 /etc/motd

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/motd
      stat:
        path: /etc/motd
      register: file_exists
      tags:
      - CCE-86697-0
      - configure_strategy
      - file_groupowner_etc_motd
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure group owner 0 on /etc/motd
      file:
        path: /etc/motd
        group: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-86697-0
      - configure_strategy
      - file_groupowner_etc_motd
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_etc_motd:def:1

Class:

compliance

Title:

Verify Group Ownership of Message of the Day Banner

Version:

1

Description:

This test makes sure that /etc/motd is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_etc_motd:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Group Who Owns passwd File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_etc_passwd
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83950-6

References:

12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-8.7.c, SRG-OS-000480-GPOS-00227, 6.1.1
Description:
To properly set the group owner of `/etc/passwd`, run the command:

    $ sudo chgrp root /etc/passwd

Rationale:

The `/etc/passwd` file contains information about the users that are configured on the system. Protection of this file is critical for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chgrp 0 /etc/passwd

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/passwd
      stat:
        path: /etc/passwd
      register: file_exists
      tags:
      - CCE-83950-6
      - CJIS-5.5.2.2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.7.c
      - configure_strategy
      - file_groupowner_etc_passwd
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure group owner 0 on /etc/passwd
      file:
        path: /etc/passwd
        group: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83950-6
      - CJIS-5.5.2.2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.7.c
      - configure_strategy
      - file_groupowner_etc_passwd
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_etc_passwd:def:1

Class:

compliance

Title:

Verify Group Who Owns passwd File

Version:

1

Description:

This test makes sure that /etc/passwd is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_etc_passwd:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Group Who Owns shadow File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_etc_shadow
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83930-8

References:

12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-8.7.c, SRG-OS-000480-GPOS-00227, 6.1.5
Description:
To properly set the group owner of `/etc/shadow`, run the command:

    $ sudo chgrp root /etc/shadow

Rationale:

The `/etc/shadow` file stores password hashes. Protection of this file is critical for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chgrp 0 /etc/shadow

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/shadow
      stat:
        path: /etc/shadow
      register: file_exists
      tags:
      - CCE-83930-8
      - CJIS-5.5.2.2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.7.c
      - configure_strategy
      - file_groupowner_etc_shadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure group owner 0 on /etc/shadow
      file:
        path: /etc/shadow
        group: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83930-8
      - CJIS-5.5.2.2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.7.c
      - configure_strategy
      - file_groupowner_etc_shadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_etc_shadow:def:1

Class:

compliance

Title:

Verify Group Who Owns shadow File

Version:

1

Description:

This test makes sure that /etc/shadow is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_etc_shadow:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify /boot/grub2/grub.cfg Group Ownership medium notapplicable

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_grub2_cfg
Result: | notapplicable
Multi-check rule: | no
Time: | 2023-03-16T13:56:49+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83848-2

References:

12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, 3.4.5, CCI-000225, 164.308(a)(1)(ii)(B), 164.308(a)(7)(i), 164.308(a)(7)(ii)(A), 164.310(a)(1), 164.310(a)(2)(i), 164.310(a)(2)(ii), 164.310(a)(2)(iii), 164.310(b), 164.310(c), 164.310(d)(1), 164.310(d)(2)(iii), 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-7.1, SRG-OS-000480-GPOS-00227, 1.4.2
Description:
The file `/boot/grub2/grub.cfg` should be group-owned by the `root` group to prevent destruction or modification of the file. To properly set the group owner of `/boot/grub2/grub.cfg`, run the command:

    $ sudo chgrp root /boot/grub2/grub.cfg

Rationale:

The `root` group is a highly-privileged group. Furthermore, the group-owner of this file should not have any access privileges anyway.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /sys/firmware/efi ] && rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then

    chgrp 0 /boot/grub2/grub.cfg

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-83848-2
      - CJIS-5.5.2.2
      - NIST-800-171-3.4.5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-7.1
      - configure_strategy
      - file_groupowner_grub2_cfg
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Test for existence /boot/grub2/grub.cfg
      stat:
        path: /boot/grub2/grub.cfg
      register: file_exists
      when:
      - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list'
      - '"grub2-common" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83848-2
      - CJIS-5.5.2.2
      - NIST-800-171-3.4.5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-7.1
      - configure_strategy
      - file_groupowner_grub2_cfg
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure group owner 0 on /boot/grub2/grub.cfg
      file:
        path: /boot/grub2/grub.cfg
        group: '0'
      when:
      - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list'
      - '"grub2-common" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83848-2
      - CJIS-5.5.2.2
      - NIST-800-171-3.4.5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-7.1
      - configure_strategy
      - file_groupowner_grub2_cfg
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_grub2_cfg:def:1

Class:

compliance

Title:

Verify /boot/grub2/grub.cfg Group Ownership

Version:

1

Description:

This test makes sure that /boot/grub2/grub.cfg is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_grub2_cfg:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#non-uefi
#grub2
CPE platform required by rule:
#machine
Verify Group Who Owns SSH Server config file medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_sshd_config
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90817-8

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, AC-17(a), CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.2.1
Description:
To properly set the group owner of `/etc/ssh/sshd_config`, run the command:

    $ sudo chgrp root /etc/ssh/sshd_config

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    chgrp 0 /etc/ssh/sshd_config

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/ssh/sshd_config
      stat:
        path: /etc/ssh/sshd_config
      register: file_exists
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90817-8
      - NIST-800-53-AC-17(a)
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_groupowner_sshd_config
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure group owner 0 on /etc/ssh/sshd_config
      file:
        path: /etc/ssh/sshd_config
        group: '0'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-90817-8
      - NIST-800-53-AC-17(a)
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_groupowner_sshd_config
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_sshd_config:def:1

Class:

compliance

Title:

Verify Group Who Owns SSH Server config file

Version:

1

Description:

This test makes sure that /etc/ssh/sshd_config is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_sshd_config:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Verify /boot/grub2/user.cfg Group Ownership medium notapplicable

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupowner_user_cfg
Result: | notapplicable
Multi-check rule: | no
Time: | 2023-03-16T13:56:49+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86010-6

References:

12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, 3.4.5, CCI-000225, 164.308(a)(1)(ii)(B), 164.308(a)(7)(i), 164.308(a)(7)(ii)(A), 164.310(a)(1), 164.310(a)(2)(i), 164.310(a)(2)(ii), 164.310(a)(2)(iii), 164.310(b), 164.310(c), 164.310(d)(1), 164.310(d)(2)(iii), 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-7.1, SRG-OS-000480-GPOS-00227, 1.4.2
Description:
The file `/boot/grub2/user.cfg` should be group-owned by the `root` group to prevent reading or modification of the file. To properly set the group owner of `/boot/grub2/user.cfg`, run the command:

    $ sudo chgrp root /boot/grub2/user.cfg

Rationale:

The `root` group is a highly-privileged group. Furthermore, the group-owner of this file should not have any access privileges anyway. Non-root users who read the boot parameters may be able to identify weaknesses in security upon boot and be able to exploit them.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /sys/firmware/efi ] && rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then

    chgrp 0 /boot/grub2/user.cfg

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-86010-6
      - CJIS-5.5.2.2
      - NIST-800-171-3.4.5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-7.1
      - configure_strategy
      - file_groupowner_user_cfg
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Test for existence /boot/grub2/user.cfg
      stat:
        path: /boot/grub2/user.cfg
      register: file_exists
      when:
      - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list'
      - '"grub2-common" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-86010-6
      - CJIS-5.5.2.2
      - NIST-800-171-3.4.5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-7.1
      - configure_strategy
      - file_groupowner_user_cfg
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure group owner 0 on /boot/grub2/user.cfg
      file:
        path: /boot/grub2/user.cfg
        group: '0'
      when:
      - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list'
      - '"grub2-common" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-86010-6
      - CJIS-5.5.2.2
      - NIST-800-171-3.4.5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-7.1
      - configure_strategy
      - file_groupowner_user_cfg
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_groupowner_user_cfg:def:1

Class:

compliance

Title:

Verify /boot/grub2/user.cfg Group Ownership

Version:

1

Description:

This test makes sure that /boot/grub2/user.cfg is group owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupowner_user_cfg:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#non-uefi
#grub2
CPE platform required by rule:
#machine
All Interactive User Home Directories Must Be Group-Owned By The Primary User medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_groupownership_home_directories
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:49+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83629-6

References:

CCI-000366, SRG-OS-000480-GPOS-00227, 6.2.11
Description:
Change the group owner of interactive users home directory to the group found in `/etc/passwd`. To change the group owner of interactive users home directory, use the following command:

    $ sudo chgrp USER_GROUP /home/USER

This rule ensures every home directory related to an interactive user is group-owned by an interactive user. It also ensures that interactive users are group-owners of one and only one home directory.
Rationale:

If the Group Identifier (GID) of a local interactive users home directory is not the same as the primary GID of the user, this would allow unauthorized access to the users files, and users that share the same group may not be able to access files that they legitimately should.

Warnings:

General warning
Due to OVAL limitation, this rule can report a false negative in a specific situation where two interactive users swap the group-ownership of their respective home directories.
Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    awk -F':' '{ if ($4 >= 1000 && $4 != 65534) system("chgrp -f " $4" "$6) }' /etc/passwd

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Get all local users from /etc/passwd
      ansible.builtin.getent:
        database: passwd
        split: ':'
      tags:
      - CCE-83629-6
      - file_groupownership_home_directories
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Create local_users variable from the getent output
      ansible.builtin.set_fact:
        local_users: '{{ ansible_facts.getent_passwd|dict2items }}'
      tags:
      - CCE-83629-6
      - file_groupownership_home_directories
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Test for existence of home directories to avoid creating them, but only fixing
        group ownership
      ansible.builtin.stat:
        path: '{{ item.value[4] }}'
      register: path_exists
      loop: '{{ local_users }}'
      when:
      - item.value[2]|int >= 1000
      - item.value[2]|int != 65534
      tags:
      - CCE-83629-6
      - file_groupownership_home_directories
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Ensure interactive local users are the group-owners of their respective home
        directories
      ansible.builtin.file:
        path: '{{ item.0.value[4] }}'
        group: '{{ item.0.value[2] }}'
      loop: '{{ local_users|zip(path_exists.results)|list }}'
      when: item.1.stat is defined and item.1.stat.exists
      tags:
      - CCE-83629-6
      - file_groupownership_home_directories
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-file_groupownership_home_directories:def:1

Class:

compliance

Title:

All Interactive User Home Directories Must Be Group-Owned By The Primary User

Version:

1

Description:

All interactive user's Home Directories must be group-owned by its user

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_groupownership_home_directories:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify User Who Owns Backup group File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_backup_etc_group
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83944-9

References:

CCI-002223, AC-6 (1), SRG-OS-000480-GPOS-00227, 6.1.4
Description:
To properly set the owner of `/etc/group-`, run the command:

    $ sudo chown root /etc/group-

Rationale:

The `/etc/group-` file is a backup file of `/etc/group`, and as such, it contains information regarding groups that are configured on the system. Protection of this file is important for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chown 0 /etc/group-

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/group-
      stat:
        path: /etc/group-
      register: file_exists
      tags:
      - CCE-83944-9
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_owner_backup_etc_group
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure owner 0 on /etc/group-
      file:
        path: /etc/group-
        owner: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83944-9
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_owner_backup_etc_group
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_backup_etc_group:def:1

Class:

compliance

Title:

Verify User Who Owns Backup group File

Version:

1

Description:

This test makes sure that /etc/group- is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_backup_etc_group:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify User Who Owns Backup gshadow File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_backup_etc_gshadow
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83929-0

References:

CCI-002223, AC-6 (1), SRG-OS-000480-GPOS-00227, 6.1.8
Description:
To properly set the owner of `/etc/gshadow-`, run the command:

    $ sudo chown root /etc/gshadow-

Rationale:

The `/etc/gshadow-` file is a backup of `/etc/gshadow`, and as such, it contains group password hashes. Protection of this file is critical for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chown 0 /etc/gshadow-

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/gshadow-
      stat:
        path: /etc/gshadow-
      register: file_exists
      tags:
      - CCE-83929-0
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_owner_backup_etc_gshadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure owner 0 on /etc/gshadow-
      file:
        path: /etc/gshadow-
        owner: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83929-0
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_owner_backup_etc_gshadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_backup_etc_gshadow:def:1

Class:

compliance

Title:

Verify User Who Owns Backup gshadow File

Version:

1

Description:

This test makes sure that /etc/gshadow- is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_backup_etc_gshadow:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify User Who Owns Backup passwd File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_backup_etc_passwd
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83947-2

References:

CCI-002223, AC-6 (1), SRG-OS-000480-GPOS-00227, 6.1.2
Description:
To properly set the owner of `/etc/passwd-`, run the command:

    $ sudo chown root /etc/passwd-

Rationale:

The `/etc/passwd-` file is a backup file of `/etc/passwd`, and as such, it contains information about the users that are configured on the system. Protection of this file is critical for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chown 0 /etc/passwd-

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/passwd-
      stat:
        path: /etc/passwd-
      register: file_exists
      tags:
      - CCE-83947-2
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_owner_backup_etc_passwd
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure owner 0 on /etc/passwd-
      file:
        path: /etc/passwd-
        owner: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83947-2
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_owner_backup_etc_passwd
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_backup_etc_passwd:def:1

Class:

compliance

Title:

Verify User Who Owns Backup passwd File

Version:

1

Description:

This test makes sure that /etc/passwd- is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_backup_etc_passwd:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Group Who Owns Backup shadow File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_backup_etc_shadow
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83949-8

References:

CCI-002223, AC-6 (1), SRG-OS-000480-GPOS-00227, 6.1.6
Description:
To properly set the owner of `/etc/shadow-`, run the command:

    $ sudo chown root /etc/shadow-

Rationale:

The `/etc/shadow-` file is a backup file of `/etc/shadow`, and as such, it contains the list of local system accounts and password hashes. Protection of this file is critical for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chown 0 /etc/shadow-

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/shadow-
      stat:
        path: /etc/shadow-
      register: file_exists
      tags:
      - CCE-83949-8
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_owner_backup_etc_shadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure owner 0 on /etc/shadow-
      file:
        path: /etc/shadow-
        owner: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83949-8
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_owner_backup_etc_shadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_backup_etc_shadow:def:1

Class:

compliance

Title:

Verify Group Who Owns Backup shadow File

Version:

1

Description:

This test makes sure that /etc/shadow- is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_backup_etc_shadow:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify User Who Owns /etc/cron.allow file medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_cron_allow
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86844-8

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-000366, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.8
Description:
If `/etc/cron.allow` exists, it must be owned by `root`. To properly set the owner of `/etc/cron.allow`, run the command:

    $ sudo chown root /etc/cron.allow

Rationale:

If the owner of the cron.allow file is not set to root, the possibility exists for an unauthorized user to view or edit sensitive information.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    chown 0 /etc/cron.allow

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/cron.allow
      stat:
        path: /etc/cron.allow
      register: file_exists
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-86844-8
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_owner_cron_allow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure owner 0 on /etc/cron.allow
      file:
        path: /etc/cron.allow
        owner: '0'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-86844-8
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_owner_cron_allow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_cron_allow:def:1

Class:

compliance

Title:

Verify User Who Owns /etc/cron.allow file

Version:

1

Description:

This test makes sure that /etc/cron.allow is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_cron_allow:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Verify Owner on cron.d medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_cron_d
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84169-2

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.7
Description:
To properly set the owner of `/etc/cron.d`, run the command:

    $ sudo chown root /etc/cron.d

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    find -H /etc/cron.d/ -maxdepth 1 -type d -exec chown 0 {} \;

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Ensure owner on directory /etc/cron.d/
      file:
        path: /etc/cron.d/
        state: directory
        owner: '0'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84169-2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_owner_cron_d
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_cron_d:def:1

Class:

compliance

Title:

Verify Owner on cron.d

Version:

1

Description:

This test makes sure that /etc/cron.d/ is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_cron_d:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Owner on cron.daily medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_cron_daily
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84188-2

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.4
Description:
To properly set the owner of `/etc/cron.daily`, run the command:

    $ sudo chown root /etc/cron.daily

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    find -H /etc/cron.daily/ -maxdepth 1 -type d -exec chown 0 {} \;

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Ensure owner on directory /etc/cron.daily/
      file:
        path: /etc/cron.daily/
        state: directory
        owner: '0'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84188-2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_owner_cron_daily
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_cron_daily:def:1

Class:

compliance

Title:

Verify Owner on cron.daily

Version:

1

Description:

This test makes sure that /etc/cron.daily/ is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_cron_daily:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Owner on cron.hourly medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_cron_hourly
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84168-4

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.3
Description:
To properly set the owner of `/etc/cron.hourly`, run the command:

    $ sudo chown root /etc/cron.hourly

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    find -H /etc/cron.hourly/ -maxdepth 1 -type d -exec chown 0 {} \;

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Ensure owner on directory /etc/cron.hourly/
      file:
        path: /etc/cron.hourly/
        state: directory
        owner: '0'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84168-4
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_owner_cron_hourly
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_cron_hourly:def:1

Class:

compliance

Title:

Verify Owner on cron.hourly

Version:

1

Description:

This test makes sure that /etc/cron.hourly/ is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_cron_hourly:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Owner on cron.monthly medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_cron_monthly
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84179-1

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.6
Description:
To properly set the owner of `/etc/cron.monthly`, run the command:

    $ sudo chown root /etc/cron.monthly

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    find -H /etc/cron.monthly/ -maxdepth 1 -type d -exec chown 0 {} \;

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Ensure owner on directory /etc/cron.monthly/
      file:
        path: /etc/cron.monthly/
        state: directory
        owner: '0'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84179-1
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_owner_cron_monthly
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_cron_monthly:def:1

Class:

compliance

Title:

Verify Owner on cron.monthly

Version:

1

Description:

This test makes sure that /etc/cron.monthly/ is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_cron_monthly:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Owner on cron.weekly medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_cron_weekly
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84190-8

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.5
Description:
To properly set the owner of `/etc/cron.weekly`, run the command:

    $ sudo chown root /etc/cron.weekly

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    find -H /etc/cron.weekly/ -maxdepth 1 -type d -exec chown 0 {} \;

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Ensure owner on directory /etc/cron.weekly/
      file:
        path: /etc/cron.weekly/
        state: directory
        owner: '0'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84190-8
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_owner_cron_weekly
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_cron_weekly:def:1

Class:

compliance

Title:

Verify Owner on cron.weekly

Version:

1

Description:

This test makes sure that /etc/cron.weekly/ is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_cron_weekly:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Owner on crontab medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_crontab
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84167-6

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.2
Description:
To properly set the owner of `/etc/crontab`, run the command:

    $ sudo chown root /etc/crontab

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    chown 0 /etc/crontab

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/crontab
      stat:
        path: /etc/crontab
      register: file_exists
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84167-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_owner_crontab
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure owner 0 on /etc/crontab
      file:
        path: /etc/crontab
        owner: '0'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-84167-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_owner_crontab
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_crontab:def:1

Class:

compliance

Title:

Verify Owner on crontab

Version:

1

Description:

This test makes sure that /etc/crontab is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_crontab:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify User Who Owns group File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_etc_group
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83925-8

References:

12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-002223, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-8.7.c, SRG-OS-000480-GPOS-00227, 6.1.3
Description:
To properly set the owner of `/etc/group`, run the command:

    $ sudo chown root /etc/group

Rationale:

The `/etc/group` file contains information regarding groups that are configured on the system. Protection of this file is important for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chown 0 /etc/group

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/group
      stat:
        path: /etc/group
      register: file_exists
      tags:
      - CCE-83925-8
      - CJIS-5.5.2.2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.7.c
      - configure_strategy
      - file_owner_etc_group
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure owner 0 on /etc/group
      file:
        path: /etc/group
        owner: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83925-8
      - CJIS-5.5.2.2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.7.c
      - configure_strategy
      - file_owner_etc_group
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_etc_group:def:1

Class:

compliance

Title:

Verify User Who Owns group File

Version:

1

Description:

This test makes sure that /etc/group is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_etc_group:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify User Who Owns gshadow File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_etc_gshadow
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83924-1

References:

BP28(R36), 12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-002223, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 6.1.7
Description:
To properly set the owner of `/etc/gshadow`, run the command:

    $ sudo chown root /etc/gshadow

Rationale:

The `/etc/gshadow` file contains group password hashes. Protection of this file is critical for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chown 0 /etc/gshadow

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/gshadow
      stat:
        path: /etc/gshadow
      register: file_exists
      tags:
      - CCE-83924-1
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_owner_etc_gshadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure owner 0 on /etc/gshadow
      file:
        path: /etc/gshadow
        owner: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83924-1
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_owner_etc_gshadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_etc_gshadow:def:1

Class:

compliance

Title:

Verify User Who Owns gshadow File

Version:

1

Description:

This test makes sure that /etc/gshadow is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_etc_gshadow:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify ownership of System Login Banner medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_etc_issue
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86700-2

References:

1.7.5
Description:
To properly set the owner of `/etc/issue`, run the command:

    $ sudo chown root /etc/issue

Rationale:

Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance.
Proper ownership will ensure that only root user can modify the banner.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chown 0 /etc/issue

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/issue
      stat:
        path: /etc/issue
      register: file_exists
      tags:
      - CCE-86700-2
      - configure_strategy
      - file_owner_etc_issue
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure owner 0 on /etc/issue
      file:
        path: /etc/issue
        owner: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-86700-2
      - configure_strategy
      - file_owner_etc_issue
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_etc_issue:def:1

Class:

compliance

Title:

Verify ownership of System Login Banner

Version:

1

Description:

This test makes sure that /etc/issue is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_etc_issue:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify ownership of System Login Banner for Remote Connections medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_etc_issue_net
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86057-7

References:

1.7.6
Description:
To properly set the owner of `/etc/issue.net`, run the command:

    $ sudo chown root /etc/issue.net

Rationale:

Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance.
Proper ownership will ensure that only root user can modify the banner.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chown 0 /etc/issue.net

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/issue.net
      stat:
        path: /etc/issue.net
      register: file_exists
      tags:
      - CCE-86057-7
      - configure_strategy
      - file_owner_etc_issue_net
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure owner 0 on /etc/issue.net
      file:
        path: /etc/issue.net
        owner: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-86057-7
      - configure_strategy
      - file_owner_etc_issue_net
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_etc_issue_net:def:1

Class:

compliance

Title:

Verify ownership of System Login Banner for Remote Connections

Version:

1

Description:

This test makes sure that /etc/issue.net is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_etc_issue_net:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify ownership of Message of the Day Banner medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_etc_motd
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86698-8

References:

1.7.4
Description:
To properly set the owner of `/etc/motd`, run the command:

    $ sudo chown root /etc/motd

Rationale:

Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance.
Proper ownership will ensure that only root user can modify the banner.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chown 0 /etc/motd

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/motd
      stat:
        path: /etc/motd
      register: file_exists
      tags:
      - CCE-86698-8
      - configure_strategy
      - file_owner_etc_motd
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure owner 0 on /etc/motd
      file:
        path: /etc/motd
        owner: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-86698-8
      - configure_strategy
      - file_owner_etc_motd
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_etc_motd:def:1

Class:

compliance

Title:

Verify ownership of Message of the Day Banner

Version:

1

Description:

This test makes sure that /etc/motd is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_etc_motd:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify User Who Owns passwd File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_etc_passwd
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83943-1

References:

12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-002223, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-8.7.c, SRG-OS-000480-GPOS-00227, 6.1.1
Description:
To properly set the owner of `/etc/passwd`, run the command:

    $ sudo chown root /etc/passwd

Rationale:

The `/etc/passwd` file contains information about the users that are configured on the system. Protection of this file is critical for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chown 0 /etc/passwd

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/passwd
      stat:
        path: /etc/passwd
      register: file_exists
      tags:
      - CCE-83943-1
      - CJIS-5.5.2.2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.7.c
      - configure_strategy
      - file_owner_etc_passwd
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure owner 0 on /etc/passwd
      file:
        path: /etc/passwd
        owner: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83943-1
      - CJIS-5.5.2.2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.7.c
      - configure_strategy
      - file_owner_etc_passwd
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_etc_passwd:def:1

Class:

compliance

Title:

Verify User Who Owns passwd File

Version:

1

Description:

This test makes sure that /etc/passwd is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_etc_passwd:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify User Who Owns shadow File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_etc_shadow
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83926-6

References:

BP28(R36), 12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-002223, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-8.7.c, SRG-OS-000480-GPOS-00227, 6.1.5
Description:
To properly set the owner of `/etc/shadow`, run the command:

    $ sudo chown root /etc/shadow

Rationale:

The `/etc/shadow` file contains the list of local system accounts and stores password hashes. Protection of this file is critical for system security. Failure to give ownership of this file to root provides the designated owner with access to sensitive information which could weaken the system security posture.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chown 0 /etc/shadow

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/shadow
      stat:
        path: /etc/shadow
      register: file_exists
      tags:
      - CCE-83926-6
      - CJIS-5.5.2.2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.7.c
      - configure_strategy
      - file_owner_etc_shadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure owner 0 on /etc/shadow
      file:
        path: /etc/shadow
        owner: '0'
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83926-6
      - CJIS-5.5.2.2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.7.c
      - configure_strategy
      - file_owner_etc_shadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_etc_shadow:def:1

Class:

compliance

Title:

Verify User Who Owns shadow File

Version:

1

Description:

This test makes sure that /etc/shadow is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_etc_shadow:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify /boot/grub2/grub.cfg User Ownership medium notapplicable

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_grub2_cfg
Result: | notapplicable
Multi-check rule: | no
Time: | 2023-03-16T13:56:49+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83845-8

References:

12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, 3.4.5, CCI-000225, 164.308(a)(1)(ii)(B), 164.308(a)(7)(i), 164.308(a)(7)(ii)(A), 164.310(a)(1), 164.310(a)(2)(i), 164.310(a)(2)(ii), 164.310(a)(2)(iii), 164.310(b), 164.310(c), 164.310(d)(1), 164.310(d)(2)(iii), 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-7.1, 1.4.2
Description:
The file `/boot/grub2/grub.cfg` should be owned by the `root` user to prevent destruction or modification of the file. To properly set the owner of `/boot/grub2/grub.cfg`, run the command:

    $ sudo chown root /boot/grub2/grub.cfg

Rationale:

Only root should be able to modify important boot parameters.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /sys/firmware/efi ] && rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then

    chown 0 /boot/grub2/grub.cfg

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-83845-8
      - CJIS-5.5.2.2
      - NIST-800-171-3.4.5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-7.1
      - configure_strategy
      - file_owner_grub2_cfg
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Test for existence /boot/grub2/grub.cfg
      stat:
        path: /boot/grub2/grub.cfg
      register: file_exists
      when:
      - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list'
      - '"grub2-common" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83845-8
      - CJIS-5.5.2.2
      - NIST-800-171-3.4.5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-7.1
      - configure_strategy
      - file_owner_grub2_cfg
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure owner 0 on /boot/grub2/grub.cfg
      file:
        path: /boot/grub2/grub.cfg
        owner: '0'
      when:
      - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list'
      - '"grub2-common" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83845-8
      - CJIS-5.5.2.2
      - NIST-800-171-3.4.5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-7.1
      - configure_strategy
      - file_owner_grub2_cfg
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_grub2_cfg:def:1

Class:

compliance

Title:

Verify /boot/grub2/grub.cfg User Ownership

Version:

1

Description:

This test makes sure that /boot/grub2/grub.cfg is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_grub2_cfg:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#non-uefi
#grub2
CPE platform required by rule:
#machine
Verify Owner on SSH Server config file medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_sshd_config
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90821-0

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, AC-17(a), CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.2.1
Description:
To properly set the owner of `/etc/ssh/sshd_config`, run the command:

    $ sudo chown root /etc/ssh/sshd_config

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    chown 0 /etc/ssh/sshd_config

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/ssh/sshd_config
      stat:
        path: /etc/ssh/sshd_config
      register: file_exists
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90821-0
      - NIST-800-53-AC-17(a)
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_owner_sshd_config
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure owner 0 on /etc/ssh/sshd_config
      file:
        path: /etc/ssh/sshd_config
        owner: '0'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-90821-0
      - NIST-800-53-AC-17(a)
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_owner_sshd_config
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_sshd_config:def:1

Class:

compliance

Title:

Verify Owner on SSH Server config file

Version:

1

Description:

This test makes sure that /etc/ssh/sshd_config is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_sshd_config:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Verify /boot/grub2/user.cfg User Ownership medium notapplicable

Rule ID: | xccdf_org.ssgproject.content_rule_file_owner_user_cfg
Result: | notapplicable
Multi-check rule: | no
Time: | 2023-03-16T13:56:49+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86016-3

References:

12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, 3.4.5, CCI-000225, 164.308(a)(1)(ii)(B), 164.308(a)(7)(i), 164.308(a)(7)(ii)(A), 164.310(a)(1), 164.310(a)(2)(i), 164.310(a)(2)(ii), 164.310(a)(2)(iii), 164.310(b), 164.310(c), 164.310(d)(1), 164.310(d)(2)(iii), 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-7.1, 1.4.2
Description:
The file `/boot/grub2/user.cfg` should be owned by the `root` user to prevent reading or modification of the file. To properly set the owner of `/boot/grub2/user.cfg`, run the command:

    $ sudo chown root /boot/grub2/user.cfg

Rationale:

Only root should be able to modify important boot parameters. Also, non-root users who read the boot parameters may be able to identify weaknesses in security upon boot and be able to exploit them.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /sys/firmware/efi ] && rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then

    chown 0 /boot/grub2/user.cfg

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-86016-3
      - CJIS-5.5.2.2
      - NIST-800-171-3.4.5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-7.1
      - configure_strategy
      - file_owner_user_cfg
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Test for existence /boot/grub2/user.cfg
      stat:
        path: /boot/grub2/user.cfg
      register: file_exists
      when:
      - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list'
      - '"grub2-common" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-86016-3
      - CJIS-5.5.2.2
      - NIST-800-171-3.4.5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-7.1
      - configure_strategy
      - file_owner_user_cfg
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure owner 0 on /boot/grub2/user.cfg
      file:
        path: /boot/grub2/user.cfg
        owner: '0'
      when:
      - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list'
      - '"grub2-common" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-86016-3
      - CJIS-5.5.2.2
      - NIST-800-171-3.4.5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-7.1
      - configure_strategy
      - file_owner_user_cfg
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_owner_user_cfg:def:1

Class:

compliance

Title:

Verify /boot/grub2/user.cfg User Ownership

Version:

1

Description:

This test makes sure that /boot/grub2/user.cfg is owned by 0.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_owner_user_cfg:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#non-uefi
#grub2
CPE platform required by rule:
#machine
Verify Permissions on /etc/at.allow file medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_at_allow
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86904-0

References:

5.1.9
Description:
If `/etc/at.allow` exists, it must have permissions `0600` or more restrictive. To properly set the permissions of `/etc/at.allow`, run the command:

    $ sudo chmod 0600 /etc/at.allow

Rationale:

If the permissions of the at.allow file are not set to 0600 or more restrictive, the possibility exists for an unauthorized user to view or edit sensitive information.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    chmod u-xs,g-xwrs,o-xwrt /etc/at.allow

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/at.allow
      stat:
        path: /etc/at.allow
      register: file_exists
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-86904-0
      - configure_strategy
      - file_permissions_at_allow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure permission u-xs,g-xwrs,o-xwrt on /etc/at.allow
      file:
        path: /etc/at.allow
        mode: u-xs,g-xwrs,o-xwrt
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-86904-0
      - configure_strategy
      - file_permissions_at_allow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_at_allow:def:1

Class:

compliance

Title:

Verify Permissions on /etc/at.allow file

Version:

1

Description:

This test makes sure that /etc/at.allow has mode 0600. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_at_allow:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Verify Permissions on Backup group File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_backup_etc_group
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83939-9

References:

CCI-002223, AC-6 (1), SRG-OS-000480-GPOS-00227, 6.1.4
Description:
To properly set the permissions of `/etc/group-`, run the command:

    $ sudo chmod 0644 /etc/group-

Rationale:

The `/etc/group-` file is a backup file of `/etc/group`, and as such, it contains information regarding groups that are configured on the system. Protection of this file is important for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chmod u-xs,g-xws,o-xwt /etc/group-

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/group-
      stat:
        path: /etc/group-
      register: file_exists
      tags:
      - CCE-83939-9
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_permissions_backup_etc_group
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure permission u-xs,g-xws,o-xwt on /etc/group-
      file:
        path: /etc/group-
        mode: u-xs,g-xws,o-xwt
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83939-9
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_permissions_backup_etc_group
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_backup_etc_group:def:1

Class:

compliance

Title:

Verify Permissions on Backup group File

Version:

1

Description:

This test makes sure that /etc/group- has mode 0644. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_backup_etc_group:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Permissions on Backup gshadow File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_backup_etc_gshadow
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83942-3

References:

CCI-002223, AC-6 (1), SRG-OS-000480-GPOS-00227, 6.1.8
Description:
To properly set the permissions of `/etc/gshadow-`, run the command:

    $ sudo chmod 0000 /etc/gshadow-

Rationale:

The `/etc/gshadow-` file is a backup of `/etc/gshadow`, and as such, it contains group password hashes. Protection of this file is critical for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chmod u-xwrs,g-xwrs,o-xwrt /etc/gshadow-

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/gshadow-
      stat:
        path: /etc/gshadow-
      register: file_exists
      tags:
      - CCE-83942-3
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_permissions_backup_etc_gshadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/gshadow-
      file:
        path: /etc/gshadow-
        mode: u-xwrs,g-xwrs,o-xwrt
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83942-3
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_permissions_backup_etc_gshadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_backup_etc_gshadow:def:1

Class:

compliance

Title:

Verify Permissions on Backup gshadow File

Version:

1

Description:

This test makes sure that /etc/gshadow- has mode 0000. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_backup_etc_gshadow:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Permissions on Backup passwd File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_backup_etc_passwd
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83940-7

References:

CCI-002223, AC-6 (1), SRG-OS-000480-GPOS-00227, 6.1.2
Description:
To properly set the permissions of `/etc/passwd-`, run the command:

    $ sudo chmod 0644 /etc/passwd-

Rationale:

The `/etc/passwd-` file is a backup file of `/etc/passwd`, and as such, it contains information about the users that are configured on the system. Protection of this file is critical for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chmod u-xs,g-xws,o-xwt /etc/passwd-

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/passwd-
      stat:
        path: /etc/passwd-
      register: file_exists
      tags:
      - CCE-83940-7
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_permissions_backup_etc_passwd
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure permission u-xs,g-xws,o-xwt on /etc/passwd-
      file:
        path: /etc/passwd-
        mode: u-xs,g-xws,o-xwt
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83940-7
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_permissions_backup_etc_passwd
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_backup_etc_passwd:def:1

Class:

compliance

Title:

Verify Permissions on Backup passwd File

Version:

1

Description:

This test makes sure that /etc/passwd- has mode 0644. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_backup_etc_passwd:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Permissions on Backup shadow File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_backup_etc_shadow
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83935-7

References:

CCI-002223, AC-6 (1), SRG-OS-000480-GPOS-00227, 6.1.6
Description:
To properly set the permissions of `/etc/shadow-`, run the command:

    $ sudo chmod 0000 /etc/shadow-

Rationale:

The `/etc/shadow-` file is a backup file of `/etc/shadow`, and as such, it contains the list of local system accounts and password hashes. Protection of this file is critical for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chmod u-xwrs,g-xwrs,o-xwrt /etc/shadow-

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/shadow-
      stat:
        path: /etc/shadow-
      register: file_exists
      tags:
      - CCE-83935-7
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_permissions_backup_etc_shadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/shadow-
      file:
        path: /etc/shadow-
        mode: u-xwrs,g-xwrs,o-xwrt
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83935-7
      - NIST-800-53-AC-6 (1)
      - configure_strategy
      - file_permissions_backup_etc_shadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_backup_etc_shadow:def:1

Class:

compliance

Title:

Verify Permissions on Backup shadow File

Version:

1

Description:

This test makes sure that /etc/shadow- has mode 0000. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_backup_etc_shadow:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Permissions on /etc/cron.allow file medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_cron_allow
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86877-8

References:

SRG-OS-000480-GPOS-00227, 5.1.8
Description:
If `/etc/cron.allow` exists, it must have permissions `0600` or more restrictive. To properly set the permissions of `/etc/cron.allow`, run the command:

    $ sudo chmod 0600 /etc/cron.allow

Rationale:

If the permissions of the cron.allow file are not set to 0600 or more restrictive, the possibility exists for an unauthorized user to view or edit sensitive information.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    chmod u-xs,g-xwrs,o-xwrt /etc/cron.allow

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/cron.allow
      stat:
        path: /etc/cron.allow
      register: file_exists
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-86877-8
      - configure_strategy
      - file_permissions_cron_allow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure permission u-xs,g-xwrs,o-xwrt on /etc/cron.allow
      file:
        path: /etc/cron.allow
        mode: u-xs,g-xwrs,o-xwrt
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-86877-8
      - configure_strategy
      - file_permissions_cron_allow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_cron_allow:def:1

Class:

compliance

Title:

Verify Permissions on /etc/cron.allow file

Version:

1

Description:

This test makes sure that /etc/cron.allow has mode 0600. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_cron_allow:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Verify Permissions on cron.d medium fix unsuccessful

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_cron_d
Result: | fix unsuccessful
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84183-3

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.7
Description:
To properly set the permissions of `/etc/cron.d`, run the command:

    $ sudo chmod 0700 /etc/cron.d

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the correct access rights to prevent unauthorized changes.

Messages:

Message: Message:

    Fix execution completed and returned: 0

Message: Message:

    chmod: changing permissions of '/etc/cron.d/': Operation not permitted

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    find -H /etc/cron.d/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \;

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Set permissions for /etc/cron.d/
      file:
        path: /etc/cron.d/
        state: directory
        mode: u-s,g-xwrs,o-xwrt
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84183-3
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_permissions_cron_d
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_cron_d:def:1

Class:

compliance

Title:

Verify Permissions on cron.d

Version:

1

Description:

This test makes sure that /etc/cron.d/ has mode 0700. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_cron_d:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Permissions on cron.daily medium fix unsuccessful

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_cron_daily
Result: | fix unsuccessful
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84175-9

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.4
Description:
To properly set the permissions of `/etc/cron.daily`, run the command:

    $ sudo chmod 0700 /etc/cron.daily

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the correct access rights to prevent unauthorized changes.

Messages:

Message: Message:

    Fix execution completed and returned: 0

Message: Message:

    chmod: changing permissions of '/etc/cron.daily/': Operation not permitted

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    find -H /etc/cron.daily/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \;

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Set permissions for /etc/cron.daily/
      file:
        path: /etc/cron.daily/
        state: directory
        mode: u-s,g-xwrs,o-xwrt
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84175-9
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_permissions_cron_daily
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_cron_daily:def:1

Class:

compliance

Title:

Verify Permissions on cron.daily

Version:

1

Description:

This test makes sure that /etc/cron.daily/ has mode 0700. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_cron_daily:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Permissions on cron.hourly medium fix unsuccessful

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_cron_hourly
Result: | fix unsuccessful
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84173-4

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.3
Description:
To properly set the permissions of `/etc/cron.hourly`, run the command:

    $ sudo chmod 0700 /etc/cron.hourly

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the correct access rights to prevent unauthorized changes.

Messages:

Message: Message:

    Fix execution completed and returned: 0

Message: Message:

    chmod: changing permissions of '/etc/cron.hourly/': Operation not permitted

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    find -H /etc/cron.hourly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \;

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Set permissions for /etc/cron.hourly/
      file:
        path: /etc/cron.hourly/
        state: directory
        mode: u-s,g-xwrs,o-xwrt
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84173-4
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_permissions_cron_hourly
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_cron_hourly:def:1

Class:

compliance

Title:

Verify Permissions on cron.hourly

Version:

1

Description:

This test makes sure that /etc/cron.hourly/ has mode 0700. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_cron_hourly:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Permissions on cron.monthly medium fix unsuccessful

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_cron_monthly
Result: | fix unsuccessful
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84181-7

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.6
Description:
To properly set the permissions of `/etc/cron.monthly`, run the command:

    $ sudo chmod 0700 /etc/cron.monthly

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the correct access rights to prevent unauthorized changes.

Messages:

Message: Message:

    Fix execution completed and returned: 0

Message: Message:

    chmod: changing permissions of '/etc/cron.monthly/': Operation not permitted

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    find -H /etc/cron.monthly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \;

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Set permissions for /etc/cron.monthly/
      file:
        path: /etc/cron.monthly/
        state: directory
        mode: u-s,g-xwrs,o-xwrt
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84181-7
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_permissions_cron_monthly
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_cron_monthly:def:1

Class:

compliance

Title:

Verify Permissions on cron.monthly

Version:

1

Description:

This test makes sure that /etc/cron.monthly/ has mode 0700. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_cron_monthly:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Permissions on cron.weekly medium fix unsuccessful

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_cron_weekly
Result: | fix unsuccessful
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84187-4

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.5
Description:
To properly set the permissions of `/etc/cron.weekly`, run the command:

    $ sudo chmod 0700 /etc/cron.weekly

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the correct access rights to prevent unauthorized changes.

Messages:

Message: Message:

    Fix execution completed and returned: 0

Message: Message:

    chmod: changing permissions of '/etc/cron.weekly/': Operation not permitted

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    find -H /etc/cron.weekly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \;

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Set permissions for /etc/cron.weekly/
      file:
        path: /etc/cron.weekly/
        state: directory
        mode: u-s,g-xwrs,o-xwrt
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84187-4
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_permissions_cron_weekly
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_cron_weekly:def:1

Class:

compliance

Title:

Verify Permissions on cron.weekly

Version:

1

Description:

This test makes sure that /etc/cron.weekly/ has mode 0700. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_cron_weekly:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Permissions on crontab medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_crontab
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84176-7

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.1.2
Description:
To properly set the permissions of `/etc/crontab`, run the command:

    $ sudo chmod 0600 /etc/crontab

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the correct access rights to prevent unauthorized changes.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    chmod: changing permissions of '/etc/crontab': Operation not permitted

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    chmod u-xs,g-xwrs,o-xwrt /etc/crontab

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/crontab
      stat:
        path: /etc/crontab
      register: file_exists
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84176-7
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_permissions_crontab
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure permission u-xs,g-xwrs,o-xwrt on /etc/crontab
      file:
        path: /etc/crontab
        mode: u-xs,g-xwrs,o-xwrt
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-84176-7
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_permissions_crontab
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_crontab:def:1

Class:

compliance

Title:

Verify Permissions on crontab

Version:

1

Description:

This test makes sure that /etc/crontab has mode 0600. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_crontab:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Permissions on group File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_etc_group
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83934-0

References:

BP28(R36), 12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-002223, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-8.7.c, SRG-OS-000480-GPOS-00227, 6.1.3
Description:
To properly set the permissions of `/etc/passwd`, run the command:

    $ sudo chmod 0644 /etc/passwd

Rationale:

The `/etc/group` file contains information regarding groups that are configured on the system. Protection of this file is important for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chmod u-xs,g-xws,o-xwt /etc/group

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/group
      stat:
        path: /etc/group
      register: file_exists
      tags:
      - CCE-83934-0
      - CJIS-5.5.2.2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.7.c
      - configure_strategy
      - file_permissions_etc_group
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure permission u-xs,g-xws,o-xwt on /etc/group
      file:
        path: /etc/group
        mode: u-xs,g-xws,o-xwt
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83934-0
      - CJIS-5.5.2.2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.7.c
      - configure_strategy
      - file_permissions_etc_group
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_etc_group:def:1

Class:

compliance

Title:

Verify Permissions on group File

Version:

1

Description:

This test makes sure that /etc/group has mode 0644. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_etc_group:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Permissions on gshadow File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_etc_gshadow
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83921-7

References:

BP28(R36), 12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-002223, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 6.1.7
Description:
To properly set the permissions of `/etc/gshadow`, run the command:

    $ sudo chmod 0000 /etc/gshadow

Rationale:

The `/etc/gshadow` file contains group password hashes. Protection of this file is critical for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chmod u-xwrs,g-xwrs,o-xwrt /etc/gshadow

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/gshadow
      stat:
        path: /etc/gshadow
      register: file_exists
      tags:
      - CCE-83921-7
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_permissions_etc_gshadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/gshadow
      file:
        path: /etc/gshadow
        mode: u-xwrs,g-xwrs,o-xwrt
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83921-7
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_permissions_etc_gshadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_etc_gshadow:def:1

Class:

compliance

Title:

Verify Permissions on gshadow File

Version:

1

Description:

This test makes sure that /etc/gshadow has mode 0000. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_etc_gshadow:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify permissions on System Login Banner medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_etc_issue
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83551-2

References:

1.7.5
Description:
To properly set the permissions of `/etc/issue`, run the command:

    $ sudo chmod 0644 /etc/issue

Rationale:

Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance.
Proper permissions will ensure that only root user can modify the banner.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chmod u-xs,g-xws,o-xwt /etc/issue

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/issue
      stat:
        path: /etc/issue
      register: file_exists
      tags:
      - CCE-83551-2
      - configure_strategy
      - file_permissions_etc_issue
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure permission u-xs,g-xws,o-xwt on /etc/issue
      file:
        path: /etc/issue
        mode: u-xs,g-xws,o-xwt
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83551-2
      - configure_strategy
      - file_permissions_etc_issue
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_etc_issue:def:1

Class:

compliance

Title:

Verify permissions on System Login Banner

Version:

1

Description:

This test makes sure that /etc/issue has mode 0644. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_etc_issue:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify permissions on System Login Banner for Remote Connections medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_etc_issue_net
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86048-6

References:

1.7.6
Description:
To properly set the permissions of `/etc/issue.net`, run the command:

    $ sudo chmod 0644 /etc/issue.net

Rationale:

Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance.
Proper permissions will ensure that only root user can modify the banner.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chmod u-xs,g-xws,o-xwt /etc/issue.net

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/issue.net
      stat:
        path: /etc/issue.net
      register: file_exists
      tags:
      - CCE-86048-6
      - configure_strategy
      - file_permissions_etc_issue_net
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure permission u-xs,g-xws,o-xwt on /etc/issue.net
      file:
        path: /etc/issue.net
        mode: u-xs,g-xws,o-xwt
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-86048-6
      - configure_strategy
      - file_permissions_etc_issue_net
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_etc_issue_net:def:1

Class:

compliance

Title:

Verify permissions on System Login Banner for Remote Connections

Version:

1

Description:

This test makes sure that /etc/issue.net has mode 0644. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_etc_issue_net:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify permissions on Message of the Day Banner medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_etc_motd
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83554-6

References:

1.7.4
Description:
To properly set the permissions of `/etc/motd`, run the command:

    $ sudo chmod 0644 /etc/motd

Rationale:

Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance.
Proper permissions will ensure that only root user can modify the banner.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chmod u-xs,g-xws,o-xwt /etc/motd

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/motd
      stat:
        path: /etc/motd
      register: file_exists
      tags:
      - CCE-83554-6
      - configure_strategy
      - file_permissions_etc_motd
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure permission u-xs,g-xws,o-xwt on /etc/motd
      file:
        path: /etc/motd
        mode: u-xs,g-xws,o-xwt
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83554-6
      - configure_strategy
      - file_permissions_etc_motd
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_etc_motd:def:1

Class:

compliance

Title:

Verify permissions on Message of the Day Banner

Version:

1

Description:

This test makes sure that /etc/motd has mode 0644. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_etc_motd:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Permissions on passwd File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_etc_passwd
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83931-6

References:

BP28(R36), 12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-002223, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-8.7.c, SRG-OS-000480-GPOS-00227, 6.1.1
Description:
To properly set the permissions of `/etc/passwd`, run the command:

    $ sudo chmod 0644 /etc/passwd

Rationale:

If the `/etc/passwd` file is writable by a group-owner or the world the risk of its compromise is increased. The file contains the list of accounts on the system and associated information, and protection of this file is critical for system security.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chmod u-xs,g-xws,o-xwt /etc/passwd

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/passwd
      stat:
        path: /etc/passwd
      register: file_exists
      tags:
      - CCE-83931-6
      - CJIS-5.5.2.2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.7.c
      - configure_strategy
      - file_permissions_etc_passwd
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure permission u-xs,g-xws,o-xwt on /etc/passwd
      file:
        path: /etc/passwd
        mode: u-xs,g-xws,o-xwt
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83931-6
      - CJIS-5.5.2.2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.7.c
      - configure_strategy
      - file_permissions_etc_passwd
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_etc_passwd:def:1

Class:

compliance

Title:

Verify Permissions on passwd File

Version:

1

Description:

This test makes sure that /etc/passwd has mode 0644. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_etc_passwd:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Permissions on shadow File medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_etc_shadow
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83941-5

References:

BP28(R36), 12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-002223, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-8.7.c, SRG-OS-000480-GPOS-00227, 6.1.5
Description:
To properly set the permissions of `/etc/shadow`, run the command:

    $ sudo chmod 0000 /etc/shadow

Rationale:

The `/etc/shadow` file contains the list of local system accounts and stores password hashes. Protection of this file is critical for system security. Failure to give ownership of this file to root provides the designated owner with access to sensitive information which could weaken the system security posture.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    chmod u-xwrs,g-xwrs,o-xwrt /etc/shadow

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/shadow
      stat:
        path: /etc/shadow
      register: file_exists
      tags:
      - CCE-83941-5
      - CJIS-5.5.2.2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.7.c
      - configure_strategy
      - file_permissions_etc_shadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/shadow
      file:
        path: /etc/shadow
        mode: u-xwrs,g-xwrs,o-xwrt
      when: file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83941-5
      - CJIS-5.5.2.2
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-8.7.c
      - configure_strategy
      - file_permissions_etc_shadow
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_etc_shadow:def:1

Class:

compliance

Title:

Verify Permissions on shadow File

Version:

1

Description:

This test makes sure that /etc/shadow has mode 0000. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_etc_shadow:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify /boot/grub2/grub.cfg Permissions medium notapplicable

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_grub2_cfg
Result: | notapplicable
Multi-check rule: | no
Time: | 2023-03-16T13:56:49+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83846-6

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 3.4.5, CCI-000225, 164.308(a)(1)(ii)(B), 164.308(a)(7)(i), 164.308(a)(7)(ii)(A), 164.310(a)(1), 164.310(a)(2)(i), 164.310(a)(2)(ii), 164.310(a)(2)(iii), 164.310(b), 164.310(c), 164.310(d)(1), 164.310(d)(2)(iii), 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, 1.4.2
Description:
File permissions for `/boot/grub2/grub.cfg` should be set to 600. To properly set the permissions of `/boot/grub2/grub.cfg`, run the command:

    $ sudo chmod 600 /boot/grub2/grub.cfg

Rationale:

Proper permissions ensure that only the root user can modify important boot parameters.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /sys/firmware/efi ] && rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then

    chmod u-xs,g-xwrs,o-xwrt /boot/grub2/grub.cfg

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-83846-6
      - NIST-800-171-3.4.5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_permissions_grub2_cfg
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Test for existence /boot/grub2/grub.cfg
      stat:
        path: /boot/grub2/grub.cfg
      register: file_exists
      when:
      - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list'
      - '"grub2-common" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83846-6
      - NIST-800-171-3.4.5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_permissions_grub2_cfg
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure permission u-xs,g-xwrs,o-xwrt on /boot/grub2/grub.cfg
      file:
        path: /boot/grub2/grub.cfg
        mode: u-xs,g-xwrs,o-xwrt
      when:
      - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list'
      - '"grub2-common" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-83846-6
      - NIST-800-171-3.4.5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_permissions_grub2_cfg
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_grub2_cfg:def:1

Class:

compliance

Title:

Verify /boot/grub2/grub.cfg Permissions

Version:

1

Description:

This test makes sure that /boot/grub2/grub.cfg has mode 0600. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_grub2_cfg:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#non-uefi
#grub2
CPE platform required by rule:
#machine
All Interactive User Home Directories Must Have mode 0750 Or Less Permissive medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_home_directories
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:49+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83634-6

References:

CCI-000366, SRG-OS-000480-GPOS-00227, 6.2.12
Description:
Change the mode of interactive users home directories to `0750`. To change the mode of interactive users home directory, use the following command:

    $ sudo chmod 0750 /home/USER

Rationale:

Excessive permissions on local interactive user home directories may allow unauthorized access to user files by other users.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    for home_dir in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $6 }' /etc/passwd); do
        # Only update the permissions when necessary. This will avoid changing the inode timestamp when
        # the permission is already defined as expected, therefore not impacting in possible integrity
        # check systems that also check inodes timestamps.
        find "$home_dir" -maxdepth 0 -perm /7027 -exec chmod u-s,g-w-s,o=- {} \;
    done

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Get all local users from /etc/passwd
      ansible.builtin.getent:
        database: passwd
        split: ':'
      tags:
      - CCE-83634-6
      - file_permissions_home_directories
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Create local_users variable from the getent output
      ansible.builtin.set_fact:
        local_users: '{{ ansible_facts.getent_passwd|dict2items }}'
      tags:
      - CCE-83634-6
      - file_permissions_home_directories
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Test for existence home directories to avoid creating them.
      ansible.builtin.stat:
        path: '{{ item.value[4] }}'
      register: path_exists
      loop: '{{ local_users }}'
      when:
      - item.value[1]|int >= 1000
      - item.value[1]|int != 65534
      tags:
      - CCE-83634-6
      - file_permissions_home_directories
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Ensure interactive local users have proper permissions on their respective
        home directories
      ansible.builtin.file:
        path: '{{ item.0.value[4] }}'
        mode: u-s,g-w-s,o=-
        follow: false
        recurse: false
      loop: '{{ local_users|zip(path_exists.results)|list }}'
      when: item.1.stat is defined and item.1.stat.exists
      tags:
      - CCE-83634-6
      - file_permissions_home_directories
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-file_permissions_home_directories:def:1

Class:

compliance

Title:

All Interactive User Home Directories Must Have mode 0750 Or Less Permissive

Version:

1

Description:

All Interactive User Home Directories Must Have mode 0750 Or Less Permissive

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_home_directories:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify Permissions on SSH Server config file medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_sshd_config
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90818-6

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, AC-17(a), CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, 5.2.1
Description:
To properly set the permissions of `/etc/ssh/sshd_config`, run the command:

    $ sudo chmod 0600 /etc/ssh/sshd_config

Rationale:

Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    chmod u-xs,g-xwrs,o-xwrt /etc/ssh/sshd_config

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Test for existence /etc/ssh/sshd_config
      stat:
        path: /etc/ssh/sshd_config
      register: file_exists
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90818-6
      - NIST-800-53-AC-17(a)
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_permissions_sshd_config
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure permission u-xs,g-xwrs,o-xwrt on /etc/ssh/sshd_config
      file:
        path: /etc/ssh/sshd_config
        mode: u-xs,g-xwrs,o-xwrt
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-90818-6
      - NIST-800-53-AC-17(a)
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_permissions_sshd_config
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_sshd_config:def:1

Class:

compliance

Title:

Verify Permissions on SSH Server config file

Version:

1

Description:

This test makes sure that /etc/ssh/sshd_config has mode 0600. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_sshd_config:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Verify Permissions on SSH Server Private *_key Key Files medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_sshd_private_key
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90820-2

References:

BP28(R36), 12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 3.1.13, 3.13.10, CCI-000366, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, AC-17(a), CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-2.2.6, SRG-OS-000480-GPOS-00227, 5.2.2
Description:
SSH server private keys - files that match the `/etc/ssh/*_key` glob, have to have restricted permissions. If those files are owned by the `root` user and the `root` group, they have to have the `0600` permission or stricter. If they are owned by the `root` user, but by a dedicated group `ssh_keys`, they can have the `0640` permission or stricter.
Rationale:

If an unauthorized user obtains the private SSH host key file, the host could be impersonated.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    for keyfile in /etc/ssh/*_key; do
        test -f "$keyfile" || continue
        if test root:root = "$(stat -c "%U:%G" "$keyfile")"; then
    	chmod u-xs,g-xwrs,o-xwrt "$keyfile"
        elif test root:ssh_keys = "$(stat -c "%U:%G" "$keyfile")"; then
    	chmod u-xs,g-xws,o-xwrt "$keyfile"
        else
            echo "Key-like file '$keyfile' is owned by an unexpected user:group combination"
        fi
    done

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Find root:root-owned keys
      command: find -H /etc/ssh/ -maxdepth 1 -user root -regex ".*_key$" -type f -group
        root -perm /u+xs,g+xwrs,o+xwrt
      register: root_owned_keys
      changed_when: false
      failed_when: false
      check_mode: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90820-2
      - NIST-800-171-3.1.13
      - NIST-800-171-3.13.10
      - NIST-800-53-AC-17(a)
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-2.2.6
      - configure_strategy
      - file_permissions_sshd_private_key
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Set permissions for root:root-owned keys
      file:
        path: '{{ item }}'
        mode: u-xs,g-xwrs,o-xwrt
        state: file
      with_items:
      - '{{ root_owned_keys.stdout_lines }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90820-2
      - NIST-800-171-3.1.13
      - NIST-800-171-3.13.10
      - NIST-800-53-AC-17(a)
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-2.2.6
      - configure_strategy
      - file_permissions_sshd_private_key
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Find root:ssh_keys-owned keys
      command: find -H /etc/ssh/ -maxdepth 1 -user root -regex ".*_key$" -type f -group
        ssh_keys -perm /u+xs,g+xws,o+xwrt
      register: dedicated_group_owned_keys
      changed_when: false
      failed_when: false
      check_mode: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90820-2
      - NIST-800-171-3.1.13
      - NIST-800-171-3.13.10
      - NIST-800-53-AC-17(a)
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-2.2.6
      - configure_strategy
      - file_permissions_sshd_private_key
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Set permissions for root:ssh_keys-owned keys
      file:
        path: '{{ item }}'
        mode: u-xs,g-xws,o-xwrt
        state: file
      with_items:
      - '{{ dedicated_group_owned_keys.stdout_lines }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90820-2
      - NIST-800-171-3.1.13
      - NIST-800-171-3.13.10
      - NIST-800-53-AC-17(a)
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-2.2.6
      - configure_strategy
      - file_permissions_sshd_private_key
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

Remediation Puppet snippet

    include ssh_private_key_perms

    class ssh_private_key_perms {
      exec { 'sshd_priv_key':
        command => "chmod 0640 /etc/ssh/*_key",
        path    => '/bin:/usr/bin'
      }
    }

OVAL definition:

Definition ID:

oval:ssg-file_permissions_sshd_private_key:def:1

Class:

compliance

Title:

Verify Permissions on SSH Server Private *_key Key Files

Version:

1

Description:

The system sshd key is owned by root:root and has the 0600 permission, or by a root:ssh_keys with the 0640 permission

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_sshd_private_key:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Verify Permissions on SSH Server Public *.pub Key Files medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_sshd_pub_key
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90819-4

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 3.1.13, 3.13.10, CCI-000366, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, AC-17(a), CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-2.2.6, SRG-OS-000480-GPOS-00227, 5.2.3
Description:
To properly set the permissions of `/etc/ssh/*.pub`, run the command:

    $ sudo chmod 0644 /etc/ssh/*.pub

Rationale:

If a public host key file is modified by an unauthorized user, the SSH service may be compromised.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    find -H /etc/ssh/ -maxdepth 1 -perm /u+xs,g+xws,o+xwt -type f -regex '^.*\.pub$' -exec chmod u-xs,g-xws,o-xwt {} \;

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Find /etc/ssh/ file(s)
      command: find -H /etc/ssh/ -maxdepth 1 -perm /u+xs,g+xws,o+xwt -type f -regex "^.*\.pub$"
      register: files_found
      changed_when: false
      failed_when: false
      check_mode: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90819-4
      - NIST-800-171-3.1.13
      - NIST-800-171-3.13.10
      - NIST-800-53-AC-17(a)
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-2.2.6
      - configure_strategy
      - file_permissions_sshd_pub_key
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Set permissions for /etc/ssh/ file(s)
      file:
        path: '{{ item }}'
        mode: u-xs,g-xws,o-xwt
        state: file
      with_items:
      - '{{ files_found.stdout_lines }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90819-4
      - NIST-800-171-3.1.13
      - NIST-800-171-3.13.10
      - NIST-800-53-AC-17(a)
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-2.2.6
      - configure_strategy
      - file_permissions_sshd_pub_key
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

Remediation Puppet snippet

    include ssh_public_key_perms

    class ssh_public_key_perms {
      exec { 'sshd_pub_key':
        command => "chmod 0644 /etc/ssh/*.pub",
        path    => '/bin:/usr/bin'
      }
    }

OVAL definition:

Definition ID:

oval:ssg-file_permissions_sshd_pub_key:def:1

Class:

compliance

Title:

Verify Permissions on SSH Server Public *.pub Key Files

Version:

1

Description:

This test makes sure that /etc/ssh/ has mode 0644. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_sshd_pub_key:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Ensure No World-Writable Files Exist medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_unauthorized_world_writable
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:55+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83902-7

References:

BP28(R40), 12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, 6.1.9
Description:
It is generally a good idea to remove global (other) write access to a file when it is discovered. However, check with documentation for specific applications before making changes. Also, monitor for recurring world-writable files, as these may be symptoms of a misconfigured application or user account. Finally, this applies to real files and not virtual files that are a part of pseudo file systems such as `sysfs` or `procfs`.
Rationale:

Data in world-writable files can be modified by any user on the system. In almost all circumstances, files can be configured using a combination of user and group permissions to support whatever legitimate access is needed without the risk caused by world-writable files.

Remediation Shell script

    find / -xdev -type f -perm -002 -exec chmod o-w {} \;

OVAL definition:

Definition ID:

oval:ssg-file_permissions_unauthorized_world_writable:def:1

Class:

compliance

Title:

Ensure No World-Writable Files Exist

Version:

1

Description:

The world-write permission should be disabled for all files.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_unauthorized_world_writable:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Ensure All Files Are Owned by a Group medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_ungroupowned
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:00+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83906-8

References:

1, 11, 12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.02, DSS06.03, DSS06.06, DSS06.10, CCI-000366, CCI-002165, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.18.1.4, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-1, PR.AC-4, PR.AC-6, PR.AC-7, PR.DS-5, PR.PT-3, SRG-OS-000480-GPOS-00227, 6.1.11
Description:
If any files are not owned by a group, then the cause of their lack of group-ownership should be investigated. Following this, the files should be deleted or assigned to an appropriate group. The following command will discover and print any files on local partitions which do not belong to a valid group:

    $ df --local -P | awk '{if (NR!=1) print $6}' | sudo xargs -I '{}' find '{}' -xdev -nogroup

To search all filesystems on a system including network mounted filesystems the following command can be run manually for each partition:

    $ sudo find PARTITION -xdev -nogroup

Rationale:

Unowned files do not directly imply a security problem, but they are generally a sign that something is amiss. They may be caused by an intruder, by incorrect software installation or draft software removal, or by failure to remove all files belonging to a deleted account. The files should be repaired so they will not cause problems when accounts are created in the future, and the cause should be discovered and addressed.

Warnings:

General warning
This rule only considers local groups. If you have your groups defined outside `/etc/group`, the rule won't consider those.
OVAL definition:

Definition ID:

oval:ssg-file_permissions_ungroupowned:def:1

Class:

compliance

Title:

Ensure All Files Are Owned by a Group

Version:

2

Description:

All files should be owned by a group

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_ungroupowned:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Verify /boot/grub2/user.cfg Permissions medium notapplicable

Rule ID: | xccdf_org.ssgproject.content_rule_file_permissions_user_cfg
Result: | notapplicable
Multi-check rule: | no
Time: | 2023-03-16T13:56:49+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86025-4

References:

12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 3.4.5, CCI-000225, 164.308(a)(1)(ii)(B), 164.308(a)(7)(i), 164.308(a)(7)(ii)(A), 164.310(a)(1), 164.310(a)(2)(i), 164.310(a)(2)(ii), 164.310(a)(2)(iii), 164.310(b), 164.310(c), 164.310(d)(1), 164.310(d)(2)(iii), 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, 1.4.2
Description:
File permissions for `/boot/grub2/user.cfg` should be set to 600. To properly set the permissions of `/boot/grub2/user.cfg`, run the command:

    $ sudo chmod 600 /boot/grub2/user.cfg

Rationale:

Proper permissions ensure that only the root user can read or modify important boot parameters.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /sys/firmware/efi ] && rpm --quiet -q grub2-common && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then

    chmod u-xs,g-xwrs,o-xwrt /boot/grub2/user.cfg

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-86025-4
      - NIST-800-171-3.4.5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_permissions_user_cfg
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Test for existence /boot/grub2/user.cfg
      stat:
        path: /boot/grub2/user.cfg
      register: file_exists
      when:
      - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list'
      - '"grub2-common" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-86025-4
      - NIST-800-171-3.4.5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_permissions_user_cfg
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

    - name: Ensure permission u-xs,g-xwrs,o-xwrt on /boot/grub2/user.cfg
      file:
        path: /boot/grub2/user.cfg
        mode: u-xs,g-xwrs,o-xwrt
      when:
      - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list'
      - '"grub2-common" in ansible_facts.packages'
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - file_exists.stat is defined and file_exists.stat.exists
      tags:
      - CCE-86025-4
      - NIST-800-171-3.4.5
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - configure_strategy
      - file_permissions_user_cfg
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-file_permissions_user_cfg:def:1

Class:

compliance

Title:

Verify /boot/grub2/user.cfg Permissions

Version:

1

Description:

This test makes sure that /boot/grub2/user.cfg has mode 0600. If the target file or directory has an extended ACL, then it will fail the mode check.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-file_permissions_user_cfg:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#non-uefi
#grub2
CPE platform required by rule:
#machine
All GIDs referenced in /etc/passwd must be defined in /etc/group low pass

Rule ID: | xccdf_org.ssgproject.content_rule_gid_passwd_group_same
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

low

Identifiers:

CCE-83613-0

References:

1, 12, 15, 16, 5, 5.5.2, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, CCI-000764, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.2, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, A.18.1.4, A.7.1.1, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.2, A.9.4.3, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.2.3, CIP-004-6 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.2, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, IA-2, CM-6(a), PR.AC-1, PR.AC-6, PR.AC-7, Req-8.5.a, SRG-OS-000104-GPOS-00051, 6.2.3
Description:
Add a group to the system for each GID referenced without a corresponding group.
Rationale:

If a user is assigned the Group Identifier (GID) of a group not existing on the system, and a group with the Group Identifier (GID) is subsequently created, the user may have unintended rights to any files associated with the group.

OVAL definition:

Definition ID:

oval:ssg-gid_passwd_group_same:def:1

Class:

compliance

Title:

All GIDs referenced in /etc/passwd must be defined in /etc/group

Version:

2

Description:

All GIDs referenced in /etc/passwd must be defined in /etc/group.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-gid_passwd_group_same:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Disable XDMCP in GDM high fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_gnome_gdm_disable_xdmcp
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

high

Identifiers:

CCE-86033-8

References:

1.8.10
Description:
XDMCP is an unencrypted protocol, and therefore, presents a security risk, see e.g. XDMCP Gnome docs. To disable XDMCP support in Gnome, set `Enable` to `false` under the `[xdmcp]` configuration section in `/etc/gdm/custom.conf`. For example:

    [xdmcp]
    Enable=false

Rationale:

XDMCP provides unencrypted remote access through the Gnome Display Manager (GDM) which does not provide for the confidentiality and integrity of user passwords or the remote session. If a privileged user were to login using XDMCP, the privileged user password could be compromised due to typed XEvents and keystrokes will traversing over the network in clear text.

Messages:

Message: Message:

    Fix execution completed and returned: 4

Message: Message:

    sed: couldn't open temporary file /etc/gdm/sedxBjH5O: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q gdm; then

    # Try find '[xdmcp]' and 'Enable' in '/etc/gdm/custom.conf', if it exists, set
    # to 'false', if it isn't here, add it, if '[xdmcp]' doesn't exist, add it there
    if grep -qzosP '[[:space:]]*\[xdmcp]([^\n\[]*\n+)+?[[:space:]]*Enable' '/etc/gdm/custom.conf'; then

        sed -i "s/Enable[^(\n)]*/Enable=false/" '/etc/gdm/custom.conf'
    elif grep -qs '[[:space:]]*\[xdmcp]' '/etc/gdm/custom.conf'; then
        sed -i "/[[:space:]]*\[xdmcp]/a Enable=false" '/etc/gdm/custom.conf'
    else
        if test -d "/etc/gdm"; then
            printf '%s\n' '[xdmcp]' "Enable=false" >> '/etc/gdm/custom.conf'
        else
            echo "Config file directory '/etc/gdm' doesnt exist, not remediating, assuming non-applicability." >&2
        fi
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | unknown

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-86033-8
      - gnome_gdm_disable_xdmcp
      - high_severity
      - low_complexity
      - medium_disruption
      - no_reboot_needed
      - unknown_strategy

    - name: Disable XDMCP in GDM
      ini_file:
        path: /etc/gdm/custom.conf
        section: xdmcp
        option: Enable
        value: 'false'
        create: true
        mode: 420
      when: '"gdm" in ansible_facts.packages'
      tags:
      - CCE-86033-8
      - gnome_gdm_disable_xdmcp
      - high_severity
      - low_complexity
      - medium_disruption
      - no_reboot_needed
      - unknown_strategy

OVAL definition:

Definition ID:

oval:ssg-gnome_gdm_disable_xdmcp:def:1

Class:

compliance

Title:

Disable XDMCP in GDM

Version:

1

Description:

Ensure 'Enable' is configured with value 'false in section 'xdmcp' in /etc/gdm/custom.conf

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-gnome_gdm_disable_xdmcp:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#package_gdm
Ensure All Groups on the System Have Unique Group ID medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_group_unique_id
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86043-7

References:

CCI-000764, SRG-OS-000104-GPOS-00051, 6.2.5
Description:
Change the group name or delete groups, so each has a unique id.
Rationale:

To assure accountability and prevent unauthenticated access, groups must be identified uniquely to prevent potential misuse and compromise of the system.

Warnings:

General warning
Automatic remediation of this control is not available due to the unique requirements of each system.
OVAL definition:

Definition ID:

oval:ssg-group_unique_id:def:1

Class:

compliance

Title:

Ensure All Groups on the System Have Unique Group ID

Version:

1

Description:

All groups on the system should have unique names for proper accountability.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-group_unique_id:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Ensure SELinux Not Disabled in /etc/default/grub medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_grub2_enable_selinux
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84078-5

References:

1, 11, 12, 13, 14, 15, 16, 18, 3, 4, 5, 6, 8, 9, APO01.06, APO11.04, APO13.01, BAI03.05, DSS01.05, DSS03.01, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.03, DSS06.06, MEA02.01, 3.1.2, 3.7.2, CCI-000022, CCI-000032, 164.308(a)(1)(ii)(D), 164.308(a)(3), 164.308(a)(4), 164.310(b), 164.310(c), 164.312(a), 164.312(e), 4.2.3.4, 4.3.3.2.2, 4.3.3.3.9, 4.3.3.4, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.4.7, 4.4.2.1, 4.4.2.2, 4.4.2.4, 4.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.10, SR 2.11, SR 2.12, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 7.1, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.1, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.2.3, CIP-004-6 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.2, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, AC-3, AC-3(3)(a), DE.AE-1, ID.AM-3, PR.AC-4, PR.AC-5, PR.AC-6, PR.DS-5, PR.PT-1, PR.PT-3, PR.PT-4, SRG-OS-000445-VMM-001780, 1.6.1.2
Description:
SELinux can be disabled at boot time by an argument in `/etc/default/grub`. Remove any instances of `selinux=0` from the kernel arguments in that file to prevent SELinux from being disabled at boot.
Rationale:

Disabling a major host protection feature, such as SELinux, at boot time prevents it from confining system services at boot time. Further, it increases the chances that it will remain off during system operation.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q grub2-common; }; then

    sed -i --follow-symlinks "s/selinux=0//gI" /etc/default/grub /etc/grub2.cfg /etc/grub.d/*
    sed -i --follow-symlinks "s/enforcing=0//gI" /etc/default/grub /etc/grub2.cfg /etc/grub.d/*

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-84078-5
      - NIST-800-171-3.1.2
      - NIST-800-171-3.7.2
      - NIST-800-53-AC-3
      - NIST-800-53-AC-3(3)(a)
      - grub2_enable_selinux
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Ensure SELinux Not Disabled in /etc/default/grub - Find /etc/grub.d/ files
      ansible.builtin.find:
        paths:
        - /etc/grub.d/
        follow: true
      register: result_grub_d
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - '"grub2-common" in ansible_facts.packages'
      tags:
      - CCE-84078-5
      - NIST-800-171-3.1.2
      - NIST-800-171-3.7.2
      - NIST-800-53-AC-3
      - NIST-800-53-AC-3(3)(a)
      - grub2_enable_selinux
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Ensure SELinux Not Disabled in /etc/default/grub - Ensure SELinux Not Disabled
        in /etc/grub.d/ files
      ansible.builtin.replace:
        dest: '{{ item.path }}'
        regexp: (selinux|enforcing)=0
      with_items:
      - '{{ result_grub_d.files }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - '"grub2-common" in ansible_facts.packages'
      tags:
      - CCE-84078-5
      - NIST-800-171-3.1.2
      - NIST-800-171-3.7.2
      - NIST-800-53-AC-3
      - NIST-800-53-AC-3(3)(a)
      - grub2_enable_selinux
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Ensure SELinux Not Disabled in /etc/default/grub - Check if /etc/grub2.cfg
        exists
      ansible.builtin.stat:
        path: /etc/grub2.cfg
      register: result_grub2_cfg_present
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - '"grub2-common" in ansible_facts.packages'
      tags:
      - CCE-84078-5
      - NIST-800-171-3.1.2
      - NIST-800-171-3.7.2
      - NIST-800-53-AC-3
      - NIST-800-53-AC-3(3)(a)
      - grub2_enable_selinux
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Ensure SELinux Not Disabled in /etc/default/grub - Check if /etc/default/grub
        exists
      ansible.builtin.stat:
        path: /etc/default/grub
      register: result_default_grub_present
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - '"grub2-common" in ansible_facts.packages'
      tags:
      - CCE-84078-5
      - NIST-800-171-3.1.2
      - NIST-800-171-3.7.2
      - NIST-800-53-AC-3
      - NIST-800-53-AC-3(3)(a)
      - grub2_enable_selinux
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Ensure SELinux Not Disabled in /etc/default/grub - Ensure SELinux Not Disabled
        in /etc/grub2.cfg
      ansible.builtin.replace:
        dest: /etc/grub2.cfg
        regexp: (selinux|enforcing)=0
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - '"grub2-common" in ansible_facts.packages'
      - result_grub2_cfg_present.stat.exists
      tags:
      - CCE-84078-5
      - NIST-800-171-3.1.2
      - NIST-800-171-3.7.2
      - NIST-800-53-AC-3
      - NIST-800-53-AC-3(3)(a)
      - grub2_enable_selinux
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

    - name: Ensure SELinux Not Disabled in /etc/default/grub - Ensure SELinux Not Disabled
        in /etc/default/grub
      ansible.builtin.replace:
        dest: /etc/default/grub
        regexp: (selinux|enforcing)=0
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - '"grub2-common" in ansible_facts.packages'
      - result_default_grub_present.stat.exists
      tags:
      - CCE-84078-5
      - NIST-800-171-3.1.2
      - NIST-800-171-3.7.2
      - NIST-800-53-AC-3
      - NIST-800-53-AC-3(3)(a)
      - grub2_enable_selinux
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-grub2_enable_selinux:def:1

Class:

compliance

Title:

Ensure SELinux Not Disabled in /etc/default/grub

Version:

2

Description:

Check if selinux=0 OR enforcing=0 within the GRUB2 configuration files, fail if found.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-grub2_enable_selinux:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
CPE platform required by rule:
#grub2
Set Boot Loader Password in grub2 high notapplicable

Rule ID: | xccdf_org.ssgproject.content_rule_grub2_password
Result: | notapplicable
Multi-check rule: | no
Time: | 2023-03-16T13:56:49+01:00
Weight: | 1.0
Severity:

high

Identifiers:

CCE-83849-0

References:

BP28(R17), 1, 11, 12, 14, 15, 16, 18, 3, 5, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.06, DSS06.10, 3.4.5, CCI-000213, 164.308(a)(1)(ii)(B), 164.308(a)(7)(i), 164.308(a)(7)(ii)(A), 164.310(a)(1), 164.310(a)(2)(i), 164.310(a)(2)(ii), 164.310(a)(2)(iii), 164.310(b), 164.310(c), 164.310(d)(1), 164.310(d)(2)(iii), 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, A.18.1.4, A.6.1.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, CM-6(a), PR.AC-1, PR.AC-4, PR.AC-6, PR.AC-7, PR.PT-3, FIA_UAU.1, SRG-OS-000080-GPOS-00048, 1.4.1
Description:
The grub2 boot loader should have a superuser account and password protection enabled to protect boot-time settings.
Since plaintext passwords are a security risk, generate a hash for the password by running the following command:

    # grub2-setpassword

When prompted, enter the password that was selected.
Rationale:

Password protection on the boot loader configuration ensures users with physical access cannot trivially alter important bootloader settings. These include which kernel to use, and whether to enter single-user mode.

Warnings:

General warning
To prevent hard-coded passwords, automatic remediation of this control is not available. Remediation must be automated as a component of machine provisioning, or followed manually as outlined above. Also, do NOT manually add the superuser account and password to the `grub.cfg` file as the grub2-mkconfig command overwrites this file.
OVAL definition:

Definition ID:

oval:ssg-grub2_password:def:1

Class:

compliance

Title:

Set Boot Loader Password in grub2

Version:

1

Description:

The grub2 boot loader should have password protection enabled.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-grub2_password:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#non-uefi
#grub2
CPE platform required by rule:
#machine
Ensure journald is configured to compress large log files medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_journald_compress
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:16+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-85931-4

References:

4.2.2.3
Description:
The journald system can compress large log files to avoid fill the system disk.
Rationale:

Log files that are not properly compressed run the risk of growing so large that they fill up the log partition. Valuable logging information could be lost if the log partition becomes full.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    sed: couldn't open temporary file /etc/systemd/sedIJE2sY: Permission denied
    sed: couldn't open temporary file /etc/systemd/sedhz1z37: Permission denied
    cp: cannot create regular file '/etc/systemd/journald.conf.bak': Permission denied
    grep: /etc/systemd/journald.conf.bak: No such file or directory
    /tmp/oscap.YvJLVr/fix-XXmxN8f8: line 19: /etc/systemd/journald.conf: Permission denied
    rm: cannot remove '/etc/systemd/journald.conf.bak': No such file or directory

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    if [ -e "/etc/systemd/journald.conf" ] ; then

        LC_ALL=C sed -i "/^\s*Compress\s*=\s*/d" "/etc/systemd/journald.conf"
    else
        touch "/etc/systemd/journald.conf"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/systemd/journald.conf"

    cp "/etc/systemd/journald.conf" "/etc/systemd/journald.conf.bak"
    # Insert before the line matching the regex '^#\s*Compress'.
    line_number="$(LC_ALL=C grep -n "^#\s*Compress" "/etc/systemd/journald.conf.bak" | LC_ALL=C sed 's/:.*//g')"
    if [ -z "$line_number" ]; then
        # There was no match of '^#\s*Compress', insert at
        # the end of the file.
        printf '%s\n' "Compress='yes'" >> "/etc/systemd/journald.conf"
    else
        head -n "$(( line_number - 1 ))" "/etc/systemd/journald.conf.bak" > "/etc/systemd/journald.conf"
        printf '%s\n' "Compress='yes'" >> "/etc/systemd/journald.conf"
        tail -n "+$(( line_number ))" "/etc/systemd/journald.conf.bak" >> "/etc/systemd/journald.conf"
    fi
    # Clean up after ourselves.
    rm "/etc/systemd/journald.conf.bak"

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Setting shell-quoted shell-style assignment of 'Compress' to 'yes' in '/etc/systemd/journald.conf'
      block:

      - name: Check for duplicate values
        lineinfile:
          path: /etc/systemd/journald.conf
          create: false
          regexp: ^\s*Compress=
          state: absent
        check_mode: true
        changed_when: false
        register: dupes

      - name: Deduplicate values from /etc/systemd/journald.conf
        lineinfile:
          path: /etc/systemd/journald.conf
          create: false
          regexp: ^\s*Compress=
          state: absent
        when: dupes.found is defined and dupes.found > 1

      - name: Insert correct line to /etc/systemd/journald.conf
        lineinfile:
          path: /etc/systemd/journald.conf
          create: true
          regexp: ^\s*Compress=
          line: Compress="yes"
          state: present
          insertbefore: ^# Compress
          validate: /usr/bin/bash -n %s
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-85931-4
      - journald_compress
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-journald_compress:def:1

Class:

compliance

Title:

Ensure journald is configured to compress large log files

Version:

1

Description:

Ensure 'Compress' is configured with value 'yes' in /etc/systemd/journald.conf

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-journald_compress:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Ensure journald is configured to send logs to rsyslog medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_journald_forward_to_syslog
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:16+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-85996-7

References:

4.2.1.3
Description:
Data from journald may be stored in volatile memory or persisted locally. Utilities exist to accept remote export of journald logs.
Rationale:

Storing log data on a remote host protects log integrity from local attacks. If an attacker gains root access on the local system, they could tamper with or remove log data that is stored on the local system.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    sed: couldn't open temporary file /etc/systemd/sed74qSV2: Permission denied
    sed: couldn't open temporary file /etc/systemd/sedhLTMRn: Permission denied
    cp: cannot create regular file '/etc/systemd/journald.conf.bak': Permission denied
    grep: /etc/systemd/journald.conf.bak: No such file or directory
    /tmp/oscap.pSUGxu/fix-XXSR7Vkv: line 19: /etc/systemd/journald.conf: Permission denied
    rm: cannot remove '/etc/systemd/journald.conf.bak': No such file or directory

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    if [ -e "/etc/systemd/journald.conf" ] ; then

        LC_ALL=C sed -i "/^\s*ForwardToSyslog\s*=\s*/d" "/etc/systemd/journald.conf"
    else
        touch "/etc/systemd/journald.conf"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/systemd/journald.conf"

    cp "/etc/systemd/journald.conf" "/etc/systemd/journald.conf.bak"
    # Insert before the line matching the regex '^#\s*ForwardToSyslog'.
    line_number="$(LC_ALL=C grep -n "^#\s*ForwardToSyslog" "/etc/systemd/journald.conf.bak" | LC_ALL=C sed 's/:.*//g')"
    if [ -z "$line_number" ]; then
        # There was no match of '^#\s*ForwardToSyslog', insert at
        # the end of the file.
        printf '%s\n' "ForwardToSyslog='yes'" >> "/etc/systemd/journald.conf"
    else
        head -n "$(( line_number - 1 ))" "/etc/systemd/journald.conf.bak" > "/etc/systemd/journald.conf"
        printf '%s\n' "ForwardToSyslog='yes'" >> "/etc/systemd/journald.conf"
        tail -n "+$(( line_number ))" "/etc/systemd/journald.conf.bak" >> "/etc/systemd/journald.conf"
    fi
    # Clean up after ourselves.
    rm "/etc/systemd/journald.conf.bak"

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Setting shell-quoted shell-style assignment of 'ForwardToSyslog' to 'yes'
        in '/etc/systemd/journald.conf'
      block:

      - name: Check for duplicate values
        lineinfile:
          path: /etc/systemd/journald.conf
          create: false
          regexp: ^\s*ForwardToSyslog=
          state: absent
        check_mode: true
        changed_when: false
        register: dupes

      - name: Deduplicate values from /etc/systemd/journald.conf
        lineinfile:
          path: /etc/systemd/journald.conf
          create: false
          regexp: ^\s*ForwardToSyslog=
          state: absent
        when: dupes.found is defined and dupes.found > 1

      - name: Insert correct line to /etc/systemd/journald.conf
        lineinfile:
          path: /etc/systemd/journald.conf
          create: true
          regexp: ^\s*ForwardToSyslog=
          line: ForwardToSyslog="yes"
          state: present
          insertbefore: ^# ForwardToSyslog
          validate: /usr/bin/bash -n %s
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-85996-7
      - journald_forward_to_syslog
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-journald_forward_to_syslog:def:1

Class:

compliance

Title:

Ensure journald is configured to send logs to rsyslog

Version:

1

Description:

Ensure 'ForwardToSyslog' is configured with value 'yes' in /etc/systemd/journald.conf

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-journald_forward_to_syslog:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Ensure journald is configured to write log files to persistent disk medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_journald_storage
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:16+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86046-0

References:

4.2.2.4
Description:
The journald system may store log files in volatile memory or locally on disk. If the logs are only stored in volatile memory they will we lost upon reboot.
Rationale:

Log files contain valuable data and need to be persistent to aid in possible investigations.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    sed: couldn't open temporary file /etc/systemd/sedFuUcgj: Permission denied
    sed: couldn't open temporary file /etc/systemd/sed1RWq9P: Permission denied
    cp: cannot create regular file '/etc/systemd/journald.conf.bak': Permission denied
    grep: /etc/systemd/journald.conf.bak: No such file or directory
    /tmp/oscap.7f5pEk/fix-XX817ZAB: line 19: /etc/systemd/journald.conf: Permission denied
    rm: cannot remove '/etc/systemd/journald.conf.bak': No such file or directory

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    if [ -e "/etc/systemd/journald.conf" ] ; then

        LC_ALL=C sed -i "/^\s*Storage\s*=\s*/d" "/etc/systemd/journald.conf"
    else
        touch "/etc/systemd/journald.conf"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/systemd/journald.conf"

    cp "/etc/systemd/journald.conf" "/etc/systemd/journald.conf.bak"
    # Insert before the line matching the regex '^#\s*Storage'.
    line_number="$(LC_ALL=C grep -n "^#\s*Storage" "/etc/systemd/journald.conf.bak" | LC_ALL=C sed 's/:.*//g')"
    if [ -z "$line_number" ]; then
        # There was no match of '^#\s*Storage', insert at
        # the end of the file.
        printf '%s\n' "Storage='persistent'" >> "/etc/systemd/journald.conf"
    else
        head -n "$(( line_number - 1 ))" "/etc/systemd/journald.conf.bak" > "/etc/systemd/journald.conf"
        printf '%s\n' "Storage='persistent'" >> "/etc/systemd/journald.conf"
        tail -n "+$(( line_number ))" "/etc/systemd/journald.conf.bak" >> "/etc/systemd/journald.conf"
    fi
    # Clean up after ourselves.
    rm "/etc/systemd/journald.conf.bak"

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Setting shell-quoted shell-style assignment of 'Storage' to 'persistent' in
        '/etc/systemd/journald.conf'
      block:

      - name: Check for duplicate values
        lineinfile:
          path: /etc/systemd/journald.conf
          create: false
          regexp: ^\s*Storage=
          state: absent
        check_mode: true
        changed_when: false
        register: dupes

      - name: Deduplicate values from /etc/systemd/journald.conf
        lineinfile:
          path: /etc/systemd/journald.conf
          create: false
          regexp: ^\s*Storage=
          state: absent
        when: dupes.found is defined and dupes.found > 1

      - name: Insert correct line to /etc/systemd/journald.conf
        lineinfile:
          path: /etc/systemd/journald.conf
          create: true
          regexp: ^\s*Storage=
          line: Storage="persistent"
          state: present
          insertbefore: ^# Storage
          validate: /usr/bin/bash -n %s
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-86046-0
      - journald_storage
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-journald_storage:def:1

Class:

compliance

Title:

Ensure journald is configured to write log files to persistent disk

Version:

1

Description:

Ensure 'Storage' is configured with value 'persistent' in /etc/systemd/journald.conf

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-journald_storage:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Disable Mounting of squashfs low fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_kernel_module_squashfs_disabled
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

low

Identifiers:

CCE-83855-7

References:

11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 3.4.6, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3, 1.1.1.1
Description:
To configure the system to prevent the `squashfs` kernel module from being loaded, add the following line to the file `/etc/modprobe.d/squashfs.conf`:

    install squashfs /bin/true

This effectively prevents usage of this uncommon filesystem. The `squashfs` filesystem type is a compressed read-only Linux filesystem embedded in small footprint systems (similar to `cramfs`). A `squashfs` image can be used without having to first decompress the image.
Rationale:

Removing support for unneeded filesystem types reduces the local attack surface of the system.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /etc/modprobe.d/squashfs.conf: No such file or directory
    /tmp/oscap.iU0Gl2/fix-XXQWFvEl: line 8: /etc/modprobe.d/squashfs.conf: Permission denied
    /tmp/oscap.iU0Gl2/fix-XXQWFvEl: line 9: /etc/modprobe.d/squashfs.conf: Permission denied
    grep: /etc/modprobe.d/squashfs.conf: No such file or directory
    /tmp/oscap.iU0Gl2/fix-XXQWFvEl: line 13: /etc/modprobe.d/squashfs.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    if LC_ALL=C grep -q -m 1 "^install squashfs" /etc/modprobe.d/squashfs.conf ; then

    	sed -i 's#^install squashfs.*#install squashfs /bin/true#g' /etc/modprobe.d/squashfs.conf
    else
    	echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/squashfs.conf
    	echo "install squashfs /bin/true" >> /etc/modprobe.d/squashfs.conf
    fi

    if ! LC_ALL=C grep -q -m 1 "^blacklist squashfs$" /etc/modprobe.d/squashfs.conf ; then
    	echo "blacklist squashfs" >> /etc/modprobe.d/squashfs.conf
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: Ensure kernel module 'squashfs' is disabled
      lineinfile:
        create: true
        dest: /etc/modprobe.d/squashfs.conf
        regexp: squashfs
        line: install squashfs /bin/true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83855-7
      - NIST-800-171-3.4.6
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - kernel_module_squashfs_disabled
      - low_complexity
      - low_severity
      - medium_disruption
      - reboot_required

    - name: Ensure kernel module 'squashfs' is blacklisted
      lineinfile:
        create: true
        dest: /etc/modprobe.d/squashfs.conf
        regexp: ^blacklist squashfs$
        line: blacklist squashfs
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83855-7
      - NIST-800-171-3.4.6
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - kernel_module_squashfs_disabled
      - low_complexity
      - low_severity
      - medium_disruption
      - reboot_required

Remediation Kubernetes snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,install%20squashfs%20/bin/true%0Ablacklist%20squashfs%0A
            mode: 0644
            path: /etc/modprobe.d/squashfs.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-kernel_module_squashfs_disabled:def:1

Class:

compliance

Title:

Disable Mounting of squashfs

Version:

1

Description:

The kernel module squashfs should be disabled.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-kernel_module_squashfs_disabled:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Disable Mounting of udf low fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_kernel_module_udf_disabled
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

low

Identifiers:

CCE-83852-4

References:

11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 3.4.6, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3, 1.1.1.2
Description:
To configure the system to prevent the `udf` kernel module from being loaded, add the following line to the file `/etc/modprobe.d/udf.conf`:

    install udf /bin/true

This effectively prevents usage of this uncommon filesystem. The `udf` filesystem type is the universal disk format used to implement the ISO/IEC 13346 and ECMA-167 specifications. This is an open vendor filesystem type for data storage on a broad range of media. This filesystem type is neccessary to support writing DVDs and newer optical disc formats.
Rationale:

Removing support for unneeded filesystem types reduces the local attack surface of the system.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /etc/modprobe.d/udf.conf: No such file or directory
    /tmp/oscap.Rvt2iy/fix-XXHghRVl: line 8: /etc/modprobe.d/udf.conf: Permission denied
    /tmp/oscap.Rvt2iy/fix-XXHghRVl: line 9: /etc/modprobe.d/udf.conf: Permission denied
    grep: /etc/modprobe.d/udf.conf: No such file or directory
    /tmp/oscap.Rvt2iy/fix-XXHghRVl: line 13: /etc/modprobe.d/udf.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    if LC_ALL=C grep -q -m 1 "^install udf" /etc/modprobe.d/udf.conf ; then

    	sed -i 's#^install udf.*#install udf /bin/true#g' /etc/modprobe.d/udf.conf
    else
    	echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/udf.conf
    	echo "install udf /bin/true" >> /etc/modprobe.d/udf.conf
    fi

    if ! LC_ALL=C grep -q -m 1 "^blacklist udf$" /etc/modprobe.d/udf.conf ; then
    	echo "blacklist udf" >> /etc/modprobe.d/udf.conf
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: Ensure kernel module 'udf' is disabled
      lineinfile:
        create: true
        dest: /etc/modprobe.d/udf.conf
        regexp: udf
        line: install udf /bin/true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83852-4
      - NIST-800-171-3.4.6
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - kernel_module_udf_disabled
      - low_complexity
      - low_severity
      - medium_disruption
      - reboot_required

    - name: Ensure kernel module 'udf' is blacklisted
      lineinfile:
        create: true
        dest: /etc/modprobe.d/udf.conf
        regexp: ^blacklist udf$
        line: blacklist udf
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83852-4
      - NIST-800-171-3.4.6
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - kernel_module_udf_disabled
      - low_complexity
      - low_severity
      - medium_disruption
      - reboot_required

Remediation Kubernetes snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,install%20udf%20/bin/true%0Ablacklist%20udf%0A
            mode: 0644
            path: /etc/modprobe.d/udf.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-kernel_module_udf_disabled:def:1

Class:

compliance

Title:

Disable Mounting of udf

Version:

1

Description:

The kernel module udf should be disabled.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-kernel_module_udf_disabled:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Add nodev Option to /dev/shm medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_mount_option_dev_shm_nodev
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83881-3

References:

11, 13, 14, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS05.06, DSS06.06, CCI-001764, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.11.2.9, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.8.2.1, A.8.2.2, A.8.2.3, A.8.3.1, A.8.3.3, A.9.1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154, 1.1.8.2
Description:
The `nodev` mount option can be used to prevent creation of device files in `/dev/shm`. Legitimate character and block devices should not exist within temporary directories like `/dev/shm`. Add the `nodev` option to the fourth column of `/etc/fstab` for the line which controls mounting of `/dev/shm`.
Rationale:

The only legitimate location for device files is the `/dev` directory located on the root partition. The only exception to this is chroot jails.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    function perform_remediation {

        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /dev/shm)"

        # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
        if [ "$(grep -c "$mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
            # runtime opts without some automatic kernel/userspace-added defaults
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
                        | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//")
            [ "$previous_mount_opts" ] && previous_mount_opts+=","
            echo "tmpfs /dev/shm tmpfs defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab
        # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
        elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nodev")" -eq 0 ]; then
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
            sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab
        fi

        if mkdir -p "/dev/shm"; then
            if mountpoint -q "/dev/shm"; then
                mount -o remount --target "/dev/shm"
            else
                mount --target "/dev/shm"
            fi
        fi
    }

    perform_remediation

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | high
Strategy: | configure

    - name: 'Add nodev Option to /dev/shm: Check information associated to mountpoint'
      command: findmnt  '/dev/shm'
      register: device_name
      failed_when: device_name.rc > 1
      changed_when: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83881-3
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_dev_shm_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /dev/shm: Create mount_info dictionary variable'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - '{{ device_name.stdout_lines[0].split() | list | lower }}'
      - '{{ device_name.stdout_lines[1].split() | list }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - device_name.stdout is defined and device_name.stdout_lines is defined
      - (device_name.stdout | length > 0)
      tags:
      - CCE-83881-3
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_dev_shm_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /dev/shm: If /dev/shm not mounted, craft mount_info manually'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - - target
        - source
        - fstype
        - options
      - - /dev/shm
        - tmpfs
        - tmpfs
        - defaults
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - ("" | length == 0)
      - (device_name.stdout | length == 0)
      tags:
      - CCE-83881-3
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_dev_shm_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /dev/shm: Make sure nodev option is part of the to /dev/shm
        options'
      set_fact:
        mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev''
          }) }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - mount_info is defined and "nodev" not in mount_info.options
      tags:
      - CCE-83881-3
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_dev_shm_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /dev/shm: Ensure /dev/shm is mounted with nodev option'
      mount:
        path: /dev/shm
        src: '{{ mount_info.source }}'
        opts: '{{ mount_info.options }}'
        state: mounted
        fstype: '{{ mount_info.fstype }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("" |
        length == 0)
      tags:
      - CCE-83881-3
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_dev_shm_nodev
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-mount_option_dev_shm_nodev:def:1

Class:

compliance

Title:

Add nodev Option to /dev/shm

Version:

2

Description:

/dev/shm should be mounted with mount option nodev.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-mount_option_dev_shm_nodev:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Add noexec Option to /dev/shm medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_mount_option_dev_shm_noexec
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83857-3

References:

11, 13, 14, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS05.06, DSS06.06, CCI-001764, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.11.2.9, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.8.2.1, A.8.2.2, A.8.2.3, A.8.3.1, A.8.3.3, A.9.1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154, 1.1.8.3
Description:
The `noexec` mount option can be used to prevent binaries from being executed out of `/dev/shm`. It can be dangerous to allow the execution of binaries from world-writable temporary storage directories such as `/dev/shm`. Add the `noexec` option to the fourth column of `/etc/fstab` for the line which controls mounting of `/dev/shm`.
Rationale:

Allowing users to execute binaries from world-writable directories such as `/dev/shm` can expose the system to potential compromise.

Messages:

Message: Message:

    Fix execution completed and returned: 32

Message: Message:

    /tmp/oscap.0Pl4TQ/fix-XX4Xu8Pf: line 16: /etc/fstab: Permission denied
    mount: /dev/shm: must be superuser to use mount.

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    function perform_remediation {

        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /dev/shm)"

        # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
        if [ "$(grep -c "$mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
            # runtime opts without some automatic kernel/userspace-added defaults
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
                        | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//")
            [ "$previous_mount_opts" ] && previous_mount_opts+=","
            echo "tmpfs /dev/shm tmpfs defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab
        # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
        elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "noexec")" -eq 0 ]; then
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
            sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab
        fi

        if mkdir -p "/dev/shm"; then
            if mountpoint -q "/dev/shm"; then
                mount -o remount --target "/dev/shm"
            else
                mount --target "/dev/shm"
            fi
        fi
    }

    perform_remediation

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | high
Strategy: | configure

    - name: 'Add noexec Option to /dev/shm: Check information associated to mountpoint'
      command: findmnt  '/dev/shm'
      register: device_name
      failed_when: device_name.rc > 1
      changed_when: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83857-3
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_dev_shm_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /dev/shm: Create mount_info dictionary variable'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - '{{ device_name.stdout_lines[0].split() | list | lower }}'
      - '{{ device_name.stdout_lines[1].split() | list }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - device_name.stdout is defined and device_name.stdout_lines is defined
      - (device_name.stdout | length > 0)
      tags:
      - CCE-83857-3
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_dev_shm_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /dev/shm: If /dev/shm not mounted, craft mount_info
        manually'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - - target
        - source
        - fstype
        - options
      - - /dev/shm
        - tmpfs
        - tmpfs
        - defaults
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - ("" | length == 0)
      - (device_name.stdout | length == 0)
      tags:
      - CCE-83857-3
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_dev_shm_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /dev/shm: Make sure noexec option is part of the to
        /dev/shm options'
      set_fact:
        mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec''
          }) }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - mount_info is defined and "noexec" not in mount_info.options
      tags:
      - CCE-83857-3
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_dev_shm_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /dev/shm: Ensure /dev/shm is mounted with noexec option'
      mount:
        path: /dev/shm
        src: '{{ mount_info.source }}'
        opts: '{{ mount_info.options }}'
        state: mounted
        fstype: '{{ mount_info.fstype }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("" |
        length == 0)
      tags:
      - CCE-83857-3
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_dev_shm_noexec
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-mount_option_dev_shm_noexec:def:1

Class:

compliance

Title:

Add noexec Option to /dev/shm

Version:

2

Description:

/dev/shm should be mounted with mount option noexec.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-mount_option_dev_shm_noexec:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Add nosuid Option to /dev/shm medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_mount_option_dev_shm_nosuid
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83891-2

References:

11, 13, 14, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS05.06, DSS06.06, CCI-001764, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.11.2.9, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.8.2.1, A.8.2.2, A.8.2.3, A.8.3.1, A.8.3.3, A.9.1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154, 1.1.8.4
Description:
The `nosuid` mount option can be used to prevent execution of setuid programs in `/dev/shm`. The SUID and SGID permissions should not be required in these world-writable directories. Add the `nosuid` option to the fourth column of `/etc/fstab` for the line which controls mounting of `/dev/shm`.
Rationale:

The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from temporary storage partitions.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    function perform_remediation {

        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /dev/shm)"

        # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
        if [ "$(grep -c "$mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
            # runtime opts without some automatic kernel/userspace-added defaults
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
                        | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//")
            [ "$previous_mount_opts" ] && previous_mount_opts+=","
            echo "tmpfs /dev/shm tmpfs defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab
        # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
        elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nosuid")" -eq 0 ]; then
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
            sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab
        fi

        if mkdir -p "/dev/shm"; then
            if mountpoint -q "/dev/shm"; then
                mount -o remount --target "/dev/shm"
            else
                mount --target "/dev/shm"
            fi
        fi
    }

    perform_remediation

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | high
Strategy: | configure

    - name: 'Add nosuid Option to /dev/shm: Check information associated to mountpoint'
      command: findmnt  '/dev/shm'
      register: device_name
      failed_when: device_name.rc > 1
      changed_when: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83891-2
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_dev_shm_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /dev/shm: Create mount_info dictionary variable'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - '{{ device_name.stdout_lines[0].split() | list | lower }}'
      - '{{ device_name.stdout_lines[1].split() | list }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - device_name.stdout is defined and device_name.stdout_lines is defined
      - (device_name.stdout | length > 0)
      tags:
      - CCE-83891-2
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_dev_shm_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /dev/shm: If /dev/shm not mounted, craft mount_info
        manually'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - - target
        - source
        - fstype
        - options
      - - /dev/shm
        - tmpfs
        - tmpfs
        - defaults
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - ("" | length == 0)
      - (device_name.stdout | length == 0)
      tags:
      - CCE-83891-2
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_dev_shm_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /dev/shm: Make sure nosuid option is part of the to
        /dev/shm options'
      set_fact:
        mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid''
          }) }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - mount_info is defined and "nosuid" not in mount_info.options
      tags:
      - CCE-83891-2
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_dev_shm_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /dev/shm: Ensure /dev/shm is mounted with nosuid option'
      mount:
        path: /dev/shm
        src: '{{ mount_info.source }}'
        opts: '{{ mount_info.options }}'
        state: mounted
        fstype: '{{ mount_info.fstype }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("" |
        length == 0)
      tags:
      - CCE-83891-2
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_dev_shm_nosuid
      - no_reboot_needed

OVAL definition:

Definition ID:

oval:ssg-mount_option_dev_shm_nosuid:def:1

Class:

compliance

Title:

Add nosuid Option to /dev/shm

Version:

2

Description:

/dev/shm should be mounted with mount option nosuid.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-mount_option_dev_shm_nosuid:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Add nodev Option to /home unknown fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_mount_option_home_nodev
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

unknown

Identifiers:

CCE-83871-4

References:

BP28(R12), SRG-OS-000368-GPOS-00154, 1.1.7.2
Description:
The `nodev` mount option can be used to prevent device files from being created in `/home`. Legitimate character and block devices should exist only in the `/dev` directory on the root partition or within chroot jails built for system services. Add the `nodev` option to the fourth column of `/etc/fstab` for the line which controls mounting of `/home`.
Rationale:

The only legitimate location for device files is the `/dev` directory located on the root partition. The only exception to this is chroot jails.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    The mount point '/home' is not even in /etc/fstab, so we can't set up mount options
    Not remediating, because there is no record of /home in /etc/fstab

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    function perform_remediation {

            mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/home")"

        grep "$mount_point_match_regexp" -q /etc/fstab \
            || { echo "The mount point '/home' is not even in /etc/fstab, so we can't set up mount options" >&2;
                    echo "Not remediating, because there is no record of /home in /etc/fstab" >&2; return 1; }

        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /home)"

        # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
        if [ "$(grep -c "$mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
            # runtime opts without some automatic kernel/userspace-added defaults
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
                        | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//")
            [ "$previous_mount_opts" ] && previous_mount_opts+=","
            echo " /home  defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab
        # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
        elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nodev")" -eq 0 ]; then
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
            sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab
        fi

        if mkdir -p "/home"; then
            if mountpoint -q "/home"; then
                mount -o remount --target "/home"
            else
                mount --target "/home"
            fi
        fi
    }

    perform_remediation

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | high
Strategy: | configure

    - name: 'Add nodev Option to /home: Check information associated to mountpoint'
      command: findmnt --fstab '/home'
      register: device_name
      failed_when: device_name.rc > 1
      changed_when: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83871-4
      - configure_strategy
      - high_disruption
      - low_complexity
      - mount_option_home_nodev
      - no_reboot_needed
      - unknown_severity

    - name: 'Add nodev Option to /home: Create mount_info dictionary variable'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - '{{ device_name.stdout_lines[0].split() | list | lower }}'
      - '{{ device_name.stdout_lines[1].split() | list }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - device_name.stdout is defined and device_name.stdout_lines is defined
      - (device_name.stdout | length > 0)
      tags:
      - CCE-83871-4
      - configure_strategy
      - high_disruption
      - low_complexity
      - mount_option_home_nodev
      - no_reboot_needed
      - unknown_severity

    - name: 'Add nodev Option to /home: If /home not mounted, craft mount_info manually'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - - target
        - source
        - fstype
        - options
      - - /home
        - ''
        - ''
        - defaults
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - ("--fstab" | length == 0)
      - (device_name.stdout | length == 0)
      tags:
      - CCE-83871-4
      - configure_strategy
      - high_disruption
      - low_complexity
      - mount_option_home_nodev
      - no_reboot_needed
      - unknown_severity

    - name: 'Add nodev Option to /home: Make sure nodev option is part of the to /home
        options'
      set_fact:
        mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev''
          }) }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - mount_info is defined and "nodev" not in mount_info.options
      tags:
      - CCE-83871-4
      - configure_strategy
      - high_disruption
      - low_complexity
      - mount_option_home_nodev
      - no_reboot_needed
      - unknown_severity

    - name: 'Add nodev Option to /home: Ensure /home is mounted with nodev option'
      mount:
        path: /home
        src: '{{ mount_info.source }}'
        opts: '{{ mount_info.options }}'
        state: mounted
        fstype: '{{ mount_info.fstype }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
        | length == 0)
      tags:
      - CCE-83871-4
      - configure_strategy
      - high_disruption
      - low_complexity
      - mount_option_home_nodev
      - no_reboot_needed
      - unknown_severity

Remediation Anaconda snippet

Complexity: | low
Disruption: | high
Strategy: | enable

    part /home --mountoptions="nodev"

OVAL definition:

Definition ID:

oval:ssg-mount_option_home_nodev:def:1

Class:

compliance

Title:

Add nodev Option to /home

Version:

2

Description:

/home should be mounted with mount option nodev.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-mount_option_home_nodev:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Add nosuid Option to /home medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_mount_option_home_nosuid
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83894-6

References:

BP28(R12), 11, 13, 14, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS05.06, DSS06.06, CCI-000366, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.11.2.9, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.8.2.1, A.8.2.2, A.8.2.3, A.8.3.1, A.8.3.3, A.9.1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154, SRG-OS-000480-GPOS-00227, 1.1.7.3
Description:
The `nosuid` mount option can be used to prevent execution of setuid programs in `/home`. The SUID and SGID permissions should not be required in these user data directories. Add the `nosuid` option to the fourth column of `/etc/fstab` for the line which controls mounting of `/home`.
Rationale:

The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from user home directory partitions.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    The mount point '/home' is not even in /etc/fstab, so we can't set up mount options
    Not remediating, because there is no record of /home in /etc/fstab

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    function perform_remediation {

            mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/home")"

        grep "$mount_point_match_regexp" -q /etc/fstab \
            || { echo "The mount point '/home' is not even in /etc/fstab, so we can't set up mount options" >&2;
                    echo "Not remediating, because there is no record of /home in /etc/fstab" >&2; return 1; }

        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /home)"

        # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
        if [ "$(grep -c "$mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
            # runtime opts without some automatic kernel/userspace-added defaults
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
                        | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//")
            [ "$previous_mount_opts" ] && previous_mount_opts+=","
            echo " /home  defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab
        # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
        elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nosuid")" -eq 0 ]; then
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
            sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab
        fi

        if mkdir -p "/home"; then
            if mountpoint -q "/home"; then
                mount -o remount --target "/home"
            else
                mount --target "/home"
            fi
        fi
    }

    perform_remediation

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | high
Strategy: | configure

    - name: 'Add nosuid Option to /home: Check information associated to mountpoint'
      command: findmnt --fstab '/home'
      register: device_name
      failed_when: device_name.rc > 1
      changed_when: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83894-6
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_home_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /home: Create mount_info dictionary variable'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - '{{ device_name.stdout_lines[0].split() | list | lower }}'
      - '{{ device_name.stdout_lines[1].split() | list }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - device_name.stdout is defined and device_name.stdout_lines is defined
      - (device_name.stdout | length > 0)
      tags:
      - CCE-83894-6
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_home_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /home: If /home not mounted, craft mount_info manually'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - - target
        - source
        - fstype
        - options
      - - /home
        - ''
        - ''
        - defaults
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - ("--fstab" | length == 0)
      - (device_name.stdout | length == 0)
      tags:
      - CCE-83894-6
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_home_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /home: Make sure nosuid option is part of the to /home
        options'
      set_fact:
        mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid''
          }) }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - mount_info is defined and "nosuid" not in mount_info.options
      tags:
      - CCE-83894-6
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_home_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /home: Ensure /home is mounted with nosuid option'
      mount:
        path: /home
        src: '{{ mount_info.source }}'
        opts: '{{ mount_info.options }}'
        state: mounted
        fstype: '{{ mount_info.fstype }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
        | length == 0)
      tags:
      - CCE-83894-6
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_home_nosuid
      - no_reboot_needed

Remediation Anaconda snippet

Complexity: | low
Disruption: | high
Strategy: | enable

    part /home --mountoptions="nosuid"

OVAL definition:

Definition ID:

oval:ssg-mount_option_home_nosuid:def:1

Class:

compliance

Title:

Add nosuid Option to /home

Version:

2

Description:

/home should be mounted with mount option nosuid.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-mount_option_home_nosuid:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Add nodev Option to /tmp medium notapplicable

Rule ID: | xccdf_org.ssgproject.content_rule_mount_option_tmp_nodev
Result: | notapplicable
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83869-8

References:

BP28(R12), 11, 13, 14, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS05.06, DSS06.06, CCI-001764, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.11.2.9, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.8.2.1, A.8.2.2, A.8.2.3, A.8.3.1, A.8.3.3, A.9.1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154, 1.1.2.2
Description:
The `nodev` mount option can be used to prevent device files from being created in `/tmp`. Legitimate character and block devices should not exist within temporary directories like `/tmp`. Add the `nodev` option to the fourth column of `/etc/fstab` for the line which controls mounting of `/tmp`.
Rationale:

The only legitimate location for device files is the `/dev` directory located on the root partition. The only exception to this is chroot jails.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/tmp" > /dev/null ); then

    function perform_remediation {

            mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/tmp")"

        grep "$mount_point_match_regexp" -q /etc/fstab \
            || { echo "The mount point '/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2;
                    echo "Not remediating, because there is no record of /tmp in /etc/fstab" >&2; return 1; }

        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /tmp)"

        # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
        if [ "$(grep -c "$mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
            # runtime opts without some automatic kernel/userspace-added defaults
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
                        | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//")
            [ "$previous_mount_opts" ] && previous_mount_opts+=","
            echo " /tmp  defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab
        # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
        elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nodev")" -eq 0 ]; then
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
            sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab
        fi

        if mkdir -p "/tmp"; then
            if mountpoint -q "/tmp"; then
                mount -o remount --target "/tmp"
            else
                mount --target "/tmp"
            fi
        fi
    }

    perform_remediation

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | high
Strategy: | configure

    - name: 'Add nodev Option to /tmp: Check information associated to mountpoint'
      command: findmnt --fstab '/tmp'
      register: device_name
      failed_when: device_name.rc > 1
      changed_when: false
      when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman",
        "container"] and "/tmp" in ansible_mounts | map(attribute="mount") | list )
      tags:
      - CCE-83869-8
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_tmp_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /tmp: Create mount_info dictionary variable'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - '{{ device_name.stdout_lines[0].split() | list | lower }}'
      - '{{ device_name.stdout_lines[1].split() | list }}'
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/tmp" in ansible_mounts | map(attribute="mount") | list )
      - device_name.stdout is defined and device_name.stdout_lines is defined
      - (device_name.stdout | length > 0)
      tags:
      - CCE-83869-8
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_tmp_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /tmp: If /tmp not mounted, craft mount_info manually'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - - target
        - source
        - fstype
        - options
      - - /tmp
        - ''
        - ''
        - defaults
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/tmp" in ansible_mounts | map(attribute="mount") | list )
      - ("--fstab" | length == 0)
      - (device_name.stdout | length == 0)
      tags:
      - CCE-83869-8
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_tmp_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /tmp: Make sure nodev option is part of the to /tmp options'
      set_fact:
        mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev''
          }) }}'
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/tmp" in ansible_mounts | map(attribute="mount") | list )
      - mount_info is defined and "nodev" not in mount_info.options
      tags:
      - CCE-83869-8
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_tmp_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /tmp: Ensure /tmp is mounted with nodev option'
      mount:
        path: /tmp
        src: '{{ mount_info.source }}'
        opts: '{{ mount_info.options }}'
        state: mounted
        fstype: '{{ mount_info.fstype }}'
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/tmp" in ansible_mounts | map(attribute="mount") | list )
      - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
        | length == 0)
      tags:
      - CCE-83869-8
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_tmp_nodev
      - no_reboot_needed

Remediation Anaconda snippet

Complexity: | low
Disruption: | high
Strategy: | enable

    part /tmp --mountoptions="nodev"

OVAL definition:

Definition ID:

oval:ssg-mount_option_tmp_nodev:def:1

Class:

compliance

Title:

Add nodev Option to /tmp

Version:

2

Description:

/tmp should be mounted with mount option nodev.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-mount_option_tmp_nodev:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine_and_partition-tmp
Add noexec Option to /tmp medium notapplicable

Rule ID: | xccdf_org.ssgproject.content_rule_mount_option_tmp_noexec
Result: | notapplicable
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83885-4

References:

BP28(R12), 11, 13, 14, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS05.06, DSS06.06, CCI-001764, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.11.2.9, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.8.2.1, A.8.2.2, A.8.2.3, A.8.3.1, A.8.3.3, A.9.1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154, 1.1.2.3
Description:
The `noexec` mount option can be used to prevent binaries from being executed out of `/tmp`. Add the `noexec` option to the fourth column of `/etc/fstab` for the line which controls mounting of `/tmp`.
Rationale:

Allowing users to execute binaries from world-writable directories such as `/tmp` should never be necessary in normal operation and can expose the system to potential compromise.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/tmp" > /dev/null ); then

    function perform_remediation {

            mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/tmp")"

        grep "$mount_point_match_regexp" -q /etc/fstab \
            || { echo "The mount point '/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2;
                    echo "Not remediating, because there is no record of /tmp in /etc/fstab" >&2; return 1; }

        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /tmp)"

        # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
        if [ "$(grep -c "$mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
            # runtime opts without some automatic kernel/userspace-added defaults
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
                        | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//")
            [ "$previous_mount_opts" ] && previous_mount_opts+=","
            echo " /tmp  defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab
        # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
        elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "noexec")" -eq 0 ]; then
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
            sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab
        fi

        if mkdir -p "/tmp"; then
            if mountpoint -q "/tmp"; then
                mount -o remount --target "/tmp"
            else
                mount --target "/tmp"
            fi
        fi
    }

    perform_remediation

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | high
Strategy: | configure

    - name: 'Add noexec Option to /tmp: Check information associated to mountpoint'
      command: findmnt --fstab '/tmp'
      register: device_name
      failed_when: device_name.rc > 1
      changed_when: false
      when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman",
        "container"] and "/tmp" in ansible_mounts | map(attribute="mount") | list )
      tags:
      - CCE-83885-4
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_tmp_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /tmp: Create mount_info dictionary variable'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - '{{ device_name.stdout_lines[0].split() | list | lower }}'
      - '{{ device_name.stdout_lines[1].split() | list }}'
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/tmp" in ansible_mounts | map(attribute="mount") | list )
      - device_name.stdout is defined and device_name.stdout_lines is defined
      - (device_name.stdout | length > 0)
      tags:
      - CCE-83885-4
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_tmp_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /tmp: If /tmp not mounted, craft mount_info manually'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - - target
        - source
        - fstype
        - options
      - - /tmp
        - ''
        - ''
        - defaults
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/tmp" in ansible_mounts | map(attribute="mount") | list )
      - ("--fstab" | length == 0)
      - (device_name.stdout | length == 0)
      tags:
      - CCE-83885-4
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_tmp_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /tmp: Make sure noexec option is part of the to /tmp
        options'
      set_fact:
        mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec''
          }) }}'
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/tmp" in ansible_mounts | map(attribute="mount") | list )
      - mount_info is defined and "noexec" not in mount_info.options
      tags:
      - CCE-83885-4
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_tmp_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /tmp: Ensure /tmp is mounted with noexec option'
      mount:
        path: /tmp
        src: '{{ mount_info.source }}'
        opts: '{{ mount_info.options }}'
        state: mounted
        fstype: '{{ mount_info.fstype }}'
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/tmp" in ansible_mounts | map(attribute="mount") | list )
      - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
        | length == 0)
      tags:
      - CCE-83885-4
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_tmp_noexec
      - no_reboot_needed

Remediation Anaconda snippet

Complexity: | low
Disruption: | high
Strategy: | enable

    part /tmp --mountoptions="noexec"

OVAL definition:

Definition ID:

oval:ssg-mount_option_tmp_noexec:def:1

Class:

compliance

Title:

Add noexec Option to /tmp

Version:

2

Description:

/tmp should be mounted with mount option noexec.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-mount_option_tmp_noexec:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine_and_partition-tmp
Add nosuid Option to /tmp medium notapplicable

Rule ID: | xccdf_org.ssgproject.content_rule_mount_option_tmp_nosuid
Result: | notapplicable
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83872-2

References:

BP28(R12), 11, 13, 14, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS05.06, DSS06.06, CCI-001764, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.11.2.9, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.8.2.1, A.8.2.2, A.8.2.3, A.8.3.1, A.8.3.3, A.9.1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154, 1.1.2.4
Description:
The `nosuid` mount option can be used to prevent execution of setuid programs in `/tmp`. The SUID and SGID permissions should not be required in these world-writable directories. Add the `nosuid` option to the fourth column of `/etc/fstab` for the line which controls mounting of `/tmp`.
Rationale:

The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from temporary storage partitions.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/tmp" > /dev/null ); then

    function perform_remediation {

            mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/tmp")"

        grep "$mount_point_match_regexp" -q /etc/fstab \
            || { echo "The mount point '/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2;
                    echo "Not remediating, because there is no record of /tmp in /etc/fstab" >&2; return 1; }

        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /tmp)"

        # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
        if [ "$(grep -c "$mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
            # runtime opts without some automatic kernel/userspace-added defaults
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
                        | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//")
            [ "$previous_mount_opts" ] && previous_mount_opts+=","
            echo " /tmp  defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab
        # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
        elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nosuid")" -eq 0 ]; then
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
            sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab
        fi

        if mkdir -p "/tmp"; then
            if mountpoint -q "/tmp"; then
                mount -o remount --target "/tmp"
            else
                mount --target "/tmp"
            fi
        fi
    }

    perform_remediation

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | high
Strategy: | configure

    - name: 'Add nosuid Option to /tmp: Check information associated to mountpoint'
      command: findmnt --fstab '/tmp'
      register: device_name
      failed_when: device_name.rc > 1
      changed_when: false
      when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman",
        "container"] and "/tmp" in ansible_mounts | map(attribute="mount") | list )
      tags:
      - CCE-83872-2
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_tmp_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /tmp: Create mount_info dictionary variable'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - '{{ device_name.stdout_lines[0].split() | list | lower }}'
      - '{{ device_name.stdout_lines[1].split() | list }}'
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/tmp" in ansible_mounts | map(attribute="mount") | list )
      - device_name.stdout is defined and device_name.stdout_lines is defined
      - (device_name.stdout | length > 0)
      tags:
      - CCE-83872-2
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_tmp_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /tmp: If /tmp not mounted, craft mount_info manually'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - - target
        - source
        - fstype
        - options
      - - /tmp
        - ''
        - ''
        - defaults
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/tmp" in ansible_mounts | map(attribute="mount") | list )
      - ("--fstab" | length == 0)
      - (device_name.stdout | length == 0)
      tags:
      - CCE-83872-2
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_tmp_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /tmp: Make sure nosuid option is part of the to /tmp
        options'
      set_fact:
        mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid''
          }) }}'
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/tmp" in ansible_mounts | map(attribute="mount") | list )
      - mount_info is defined and "nosuid" not in mount_info.options
      tags:
      - CCE-83872-2
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_tmp_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /tmp: Ensure /tmp is mounted with nosuid option'
      mount:
        path: /tmp
        src: '{{ mount_info.source }}'
        opts: '{{ mount_info.options }}'
        state: mounted
        fstype: '{{ mount_info.fstype }}'
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/tmp" in ansible_mounts | map(attribute="mount") | list )
      - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
        | length == 0)
      tags:
      - CCE-83872-2
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_tmp_nosuid
      - no_reboot_needed

Remediation Anaconda snippet

Complexity: | low
Disruption: | high
Strategy: | enable

    part /tmp --mountoptions="nosuid"

OVAL definition:

Definition ID:

oval:ssg-mount_option_tmp_nosuid:def:1

Class:

compliance

Title:

Add nosuid Option to /tmp

Version:

2

Description:

/tmp should be mounted with mount option nosuid.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-mount_option_tmp_nosuid:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine_and_partition-tmp
Add nodev Option to /var/log/audit medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_mount_option_var_log_audit_nodev
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83882-1

References:

CCI-001764, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154, 1.1.6.3
Description:
The `nodev` mount option can be used to prevent device files from being created in `/var/log/audit`. Legitimate character and block devices should exist only in the `/dev` directory on the root partition or within chroot jails built for system services. Add the `nodev` option to the fourth column of `/etc/fstab` for the line which controls mounting of `/var/log/audit`.
Rationale:

The only legitimate location for device files is the `/dev` directory located on the root partition. The only exception to this is chroot jails.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    The mount point '/var/log/audit' is not even in /etc/fstab, so we can't set up mount options
    Not remediating, because there is no record of /var/log/audit in /etc/fstab

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    function perform_remediation {

            mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var/log/audit")"

        grep "$mount_point_match_regexp" -q /etc/fstab \
            || { echo "The mount point '/var/log/audit' is not even in /etc/fstab, so we can't set up mount options" >&2;
                    echo "Not remediating, because there is no record of /var/log/audit in /etc/fstab" >&2; return 1; }

        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var/log/audit)"

        # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
        if [ "$(grep -c "$mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
            # runtime opts without some automatic kernel/userspace-added defaults
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
                        | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//")
            [ "$previous_mount_opts" ] && previous_mount_opts+=","
            echo " /var/log/audit  defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab
        # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
        elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nodev")" -eq 0 ]; then
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
            sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab
        fi

        if mkdir -p "/var/log/audit"; then
            if mountpoint -q "/var/log/audit"; then
                mount -o remount --target "/var/log/audit"
            else
                mount --target "/var/log/audit"
            fi
        fi
    }

    perform_remediation

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | high
Strategy: | configure

    - name: 'Add nodev Option to /var/log/audit: Check information associated to mountpoint'
      command: findmnt --fstab '/var/log/audit'
      register: device_name
      failed_when: device_name.rc > 1
      changed_when: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83882-1
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_audit_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /var/log/audit: Create mount_info dictionary variable'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - '{{ device_name.stdout_lines[0].split() | list | lower }}'
      - '{{ device_name.stdout_lines[1].split() | list }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - device_name.stdout is defined and device_name.stdout_lines is defined
      - (device_name.stdout | length > 0)
      tags:
      - CCE-83882-1
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_audit_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /var/log/audit: If /var/log/audit not mounted, craft
        mount_info manually'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - - target
        - source
        - fstype
        - options
      - - /var/log/audit
        - ''
        - ''
        - defaults
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - ("--fstab" | length == 0)
      - (device_name.stdout | length == 0)
      tags:
      - CCE-83882-1
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_audit_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /var/log/audit: Make sure nodev option is part of the
        to /var/log/audit options'
      set_fact:
        mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev''
          }) }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - mount_info is defined and "nodev" not in mount_info.options
      tags:
      - CCE-83882-1
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_audit_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /var/log/audit: Ensure /var/log/audit is mounted with
        nodev option'
      mount:
        path: /var/log/audit
        src: '{{ mount_info.source }}'
        opts: '{{ mount_info.options }}'
        state: mounted
        fstype: '{{ mount_info.fstype }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
        | length == 0)
      tags:
      - CCE-83882-1
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_audit_nodev
      - no_reboot_needed

Remediation Anaconda snippet

Complexity: | low
Disruption: | high
Strategy: | enable

    part /var/log/audit --mountoptions="nodev"

OVAL definition:

Definition ID:

oval:ssg-mount_option_var_log_audit_nodev:def:1

Class:

compliance

Title:

Add nodev Option to /var/log/audit

Version:

2

Description:

/var/log/audit should be mounted with mount option nodev.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-mount_option_var_log_audit_nodev:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Add noexec Option to /var/log/audit medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_mount_option_var_log_audit_noexec
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83878-9

References:

CCI-001764, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154, 1.1.6.2
Description:
The `noexec` mount option can be used to prevent binaries from being executed out of `/var/log/audit`. Add the `noexec` option to the fourth column of `/etc/fstab` for the line which controls mounting of `/var/log/audit`.
Rationale:

Allowing users to execute binaries from directories containing audit log files such as `/var/log/audit` should never be necessary in normal operation and can expose the system to potential compromise.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    The mount point '/var/log/audit' is not even in /etc/fstab, so we can't set up mount options
    Not remediating, because there is no record of /var/log/audit in /etc/fstab

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    function perform_remediation {

            mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var/log/audit")"

        grep "$mount_point_match_regexp" -q /etc/fstab \
            || { echo "The mount point '/var/log/audit' is not even in /etc/fstab, so we can't set up mount options" >&2;
                    echo "Not remediating, because there is no record of /var/log/audit in /etc/fstab" >&2; return 1; }

        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var/log/audit)"

        # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
        if [ "$(grep -c "$mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
            # runtime opts without some automatic kernel/userspace-added defaults
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
                        | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//")
            [ "$previous_mount_opts" ] && previous_mount_opts+=","
            echo " /var/log/audit  defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab
        # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
        elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "noexec")" -eq 0 ]; then
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
            sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab
        fi

        if mkdir -p "/var/log/audit"; then
            if mountpoint -q "/var/log/audit"; then
                mount -o remount --target "/var/log/audit"
            else
                mount --target "/var/log/audit"
            fi
        fi
    }

    perform_remediation

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | high
Strategy: | configure

    - name: 'Add noexec Option to /var/log/audit: Check information associated to mountpoint'
      command: findmnt --fstab '/var/log/audit'
      register: device_name
      failed_when: device_name.rc > 1
      changed_when: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83878-9
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_audit_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /var/log/audit: Create mount_info dictionary variable'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - '{{ device_name.stdout_lines[0].split() | list | lower }}'
      - '{{ device_name.stdout_lines[1].split() | list }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - device_name.stdout is defined and device_name.stdout_lines is defined
      - (device_name.stdout | length > 0)
      tags:
      - CCE-83878-9
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_audit_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /var/log/audit: If /var/log/audit not mounted, craft
        mount_info manually'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - - target
        - source
        - fstype
        - options
      - - /var/log/audit
        - ''
        - ''
        - defaults
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - ("--fstab" | length == 0)
      - (device_name.stdout | length == 0)
      tags:
      - CCE-83878-9
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_audit_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /var/log/audit: Make sure noexec option is part of the
        to /var/log/audit options'
      set_fact:
        mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec''
          }) }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - mount_info is defined and "noexec" not in mount_info.options
      tags:
      - CCE-83878-9
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_audit_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /var/log/audit: Ensure /var/log/audit is mounted with
        noexec option'
      mount:
        path: /var/log/audit
        src: '{{ mount_info.source }}'
        opts: '{{ mount_info.options }}'
        state: mounted
        fstype: '{{ mount_info.fstype }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
        | length == 0)
      tags:
      - CCE-83878-9
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_audit_noexec
      - no_reboot_needed

Remediation Anaconda snippet

Complexity: | low
Disruption: | high
Strategy: | enable

    part /var/log/audit --mountoptions="noexec"

OVAL definition:

Definition ID:

oval:ssg-mount_option_var_log_audit_noexec:def:1

Class:

compliance

Title:

Add noexec Option to /var/log/audit

Version:

2

Description:

/var/log/audit should be mounted with mount option noexec.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-mount_option_var_log_audit_noexec:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Add nosuid Option to /var/log/audit medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_mount_option_var_log_audit_nosuid
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83893-8

References:

CCI-001764, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154, 1.1.6.4
Description:
The `nosuid` mount option can be used to prevent execution of setuid programs in `/var/log/audit`. The SUID and SGID permissions should not be required in directories containing audit log files. Add the `nosuid` option to the fourth column of `/etc/fstab` for the line which controls mounting of `/var/log/audit`.
Rationale:

The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from partitions designated for audit log files.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    The mount point '/var/log/audit' is not even in /etc/fstab, so we can't set up mount options
    Not remediating, because there is no record of /var/log/audit in /etc/fstab

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    function perform_remediation {

            mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var/log/audit")"

        grep "$mount_point_match_regexp" -q /etc/fstab \
            || { echo "The mount point '/var/log/audit' is not even in /etc/fstab, so we can't set up mount options" >&2;
                    echo "Not remediating, because there is no record of /var/log/audit in /etc/fstab" >&2; return 1; }

        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var/log/audit)"

        # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
        if [ "$(grep -c "$mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
            # runtime opts without some automatic kernel/userspace-added defaults
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
                        | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//")
            [ "$previous_mount_opts" ] && previous_mount_opts+=","
            echo " /var/log/audit  defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab
        # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
        elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nosuid")" -eq 0 ]; then
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
            sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab
        fi

        if mkdir -p "/var/log/audit"; then
            if mountpoint -q "/var/log/audit"; then
                mount -o remount --target "/var/log/audit"
            else
                mount --target "/var/log/audit"
            fi
        fi
    }

    perform_remediation

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | high
Strategy: | configure

    - name: 'Add nosuid Option to /var/log/audit: Check information associated to mountpoint'
      command: findmnt --fstab '/var/log/audit'
      register: device_name
      failed_when: device_name.rc > 1
      changed_when: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83893-8
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_audit_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /var/log/audit: Create mount_info dictionary variable'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - '{{ device_name.stdout_lines[0].split() | list | lower }}'
      - '{{ device_name.stdout_lines[1].split() | list }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - device_name.stdout is defined and device_name.stdout_lines is defined
      - (device_name.stdout | length > 0)
      tags:
      - CCE-83893-8
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_audit_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /var/log/audit: If /var/log/audit not mounted, craft
        mount_info manually'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - - target
        - source
        - fstype
        - options
      - - /var/log/audit
        - ''
        - ''
        - defaults
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - ("--fstab" | length == 0)
      - (device_name.stdout | length == 0)
      tags:
      - CCE-83893-8
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_audit_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /var/log/audit: Make sure nosuid option is part of the
        to /var/log/audit options'
      set_fact:
        mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid''
          }) }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - mount_info is defined and "nosuid" not in mount_info.options
      tags:
      - CCE-83893-8
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_audit_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /var/log/audit: Ensure /var/log/audit is mounted with
        nosuid option'
      mount:
        path: /var/log/audit
        src: '{{ mount_info.source }}'
        opts: '{{ mount_info.options }}'
        state: mounted
        fstype: '{{ mount_info.fstype }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
        | length == 0)
      tags:
      - CCE-83893-8
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_audit_nosuid
      - no_reboot_needed

Remediation Anaconda snippet

Complexity: | low
Disruption: | high
Strategy: | enable

    part /var/log/audit --mountoptions="nosuid"

OVAL definition:

Definition ID:

oval:ssg-mount_option_var_log_audit_nosuid:def:1

Class:

compliance

Title:

Add nosuid Option to /var/log/audit

Version:

2

Description:

/var/log/audit should be mounted with mount option nosuid.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-mount_option_var_log_audit_nosuid:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Add nodev Option to /var/log medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_mount_option_var_log_nodev
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83886-2

References:

CCI-001764, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154, 1.1.5.2
Description:
The `nodev` mount option can be used to prevent device files from being created in `/var/log`. Legitimate character and block devices should exist only in the `/dev` directory on the root partition or within chroot jails built for system services. Add the `nodev` option to the fourth column of `/etc/fstab` for the line which controls mounting of `/var/log`.
Rationale:

The only legitimate location for device files is the `/dev` directory located on the root partition. The only exception to this is chroot jails.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    The mount point '/var/log' is not even in /etc/fstab, so we can't set up mount options
    Not remediating, because there is no record of /var/log in /etc/fstab

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    function perform_remediation {

            mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var/log")"

        grep "$mount_point_match_regexp" -q /etc/fstab \
            || { echo "The mount point '/var/log' is not even in /etc/fstab, so we can't set up mount options" >&2;
                    echo "Not remediating, because there is no record of /var/log in /etc/fstab" >&2; return 1; }

        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var/log)"

        # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
        if [ "$(grep -c "$mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
            # runtime opts without some automatic kernel/userspace-added defaults
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
                        | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//")
            [ "$previous_mount_opts" ] && previous_mount_opts+=","
            echo " /var/log  defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab
        # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
        elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nodev")" -eq 0 ]; then
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
            sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab
        fi

        if mkdir -p "/var/log"; then
            if mountpoint -q "/var/log"; then
                mount -o remount --target "/var/log"
            else
                mount --target "/var/log"
            fi
        fi
    }

    perform_remediation

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | high
Strategy: | configure

    - name: 'Add nodev Option to /var/log: Check information associated to mountpoint'
      command: findmnt --fstab '/var/log'
      register: device_name
      failed_when: device_name.rc > 1
      changed_when: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83886-2
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /var/log: Create mount_info dictionary variable'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - '{{ device_name.stdout_lines[0].split() | list | lower }}'
      - '{{ device_name.stdout_lines[1].split() | list }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - device_name.stdout is defined and device_name.stdout_lines is defined
      - (device_name.stdout | length > 0)
      tags:
      - CCE-83886-2
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /var/log: If /var/log not mounted, craft mount_info manually'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - - target
        - source
        - fstype
        - options
      - - /var/log
        - ''
        - ''
        - defaults
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - ("--fstab" | length == 0)
      - (device_name.stdout | length == 0)
      tags:
      - CCE-83886-2
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /var/log: Make sure nodev option is part of the to /var/log
        options'
      set_fact:
        mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev''
          }) }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - mount_info is defined and "nodev" not in mount_info.options
      tags:
      - CCE-83886-2
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /var/log: Ensure /var/log is mounted with nodev option'
      mount:
        path: /var/log
        src: '{{ mount_info.source }}'
        opts: '{{ mount_info.options }}'
        state: mounted
        fstype: '{{ mount_info.fstype }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
        | length == 0)
      tags:
      - CCE-83886-2
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_nodev
      - no_reboot_needed

Remediation Anaconda snippet

Complexity: | low
Disruption: | high
Strategy: | enable

    part /var/log --mountoptions="nodev"

OVAL definition:

Definition ID:

oval:ssg-mount_option_var_log_nodev:def:1

Class:

compliance

Title:

Add nodev Option to /var/log

Version:

2

Description:

/var/log should be mounted with mount option nodev.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-mount_option_var_log_nodev:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Add noexec Option to /var/log medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_mount_option_var_log_noexec
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83887-0

References:

BP28(R12), CCI-001764, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154, 1.1.5.3
Description:
The `noexec` mount option can be used to prevent binaries from being executed out of `/var/log`. Add the `noexec` option to the fourth column of `/etc/fstab` for the line which controls mounting of `/var/log`.
Rationale:

Allowing users to execute binaries from directories containing log files such as `/var/log` should never be necessary in normal operation and can expose the system to potential compromise.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    The mount point '/var/log' is not even in /etc/fstab, so we can't set up mount options
    Not remediating, because there is no record of /var/log in /etc/fstab

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    function perform_remediation {

            mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var/log")"

        grep "$mount_point_match_regexp" -q /etc/fstab \
            || { echo "The mount point '/var/log' is not even in /etc/fstab, so we can't set up mount options" >&2;
                    echo "Not remediating, because there is no record of /var/log in /etc/fstab" >&2; return 1; }

        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var/log)"

        # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
        if [ "$(grep -c "$mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
            # runtime opts without some automatic kernel/userspace-added defaults
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
                        | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//")
            [ "$previous_mount_opts" ] && previous_mount_opts+=","
            echo " /var/log  defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab
        # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
        elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "noexec")" -eq 0 ]; then
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
            sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab
        fi

        if mkdir -p "/var/log"; then
            if mountpoint -q "/var/log"; then
                mount -o remount --target "/var/log"
            else
                mount --target "/var/log"
            fi
        fi
    }

    perform_remediation

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | high
Strategy: | configure

    - name: 'Add noexec Option to /var/log: Check information associated to mountpoint'
      command: findmnt --fstab '/var/log'
      register: device_name
      failed_when: device_name.rc > 1
      changed_when: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83887-0
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /var/log: Create mount_info dictionary variable'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - '{{ device_name.stdout_lines[0].split() | list | lower }}'
      - '{{ device_name.stdout_lines[1].split() | list }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - device_name.stdout is defined and device_name.stdout_lines is defined
      - (device_name.stdout | length > 0)
      tags:
      - CCE-83887-0
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /var/log: If /var/log not mounted, craft mount_info
        manually'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - - target
        - source
        - fstype
        - options
      - - /var/log
        - ''
        - ''
        - defaults
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - ("--fstab" | length == 0)
      - (device_name.stdout | length == 0)
      tags:
      - CCE-83887-0
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /var/log: Make sure noexec option is part of the to
        /var/log options'
      set_fact:
        mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec''
          }) }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - mount_info is defined and "noexec" not in mount_info.options
      tags:
      - CCE-83887-0
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /var/log: Ensure /var/log is mounted with noexec option'
      mount:
        path: /var/log
        src: '{{ mount_info.source }}'
        opts: '{{ mount_info.options }}'
        state: mounted
        fstype: '{{ mount_info.fstype }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
        | length == 0)
      tags:
      - CCE-83887-0
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_noexec
      - no_reboot_needed

Remediation Anaconda snippet

Complexity: | low
Disruption: | high
Strategy: | enable

    part /var/log --mountoptions="noexec"

OVAL definition:

Definition ID:

oval:ssg-mount_option_var_log_noexec:def:1

Class:

compliance

Title:

Add noexec Option to /var/log

Version:

2

Description:

/var/log should be mounted with mount option noexec.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-mount_option_var_log_noexec:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Add nosuid Option to /var/log medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_mount_option_var_log_nosuid
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83870-6

References:

BP28(R12), CCI-001764, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154, 1.1.5.4
Description:
The `nosuid` mount option can be used to prevent execution of setuid programs in `/var/log`. The SUID and SGID permissions should not be required in directories containing log files. Add the `nosuid` option to the fourth column of `/etc/fstab` for the line which controls mounting of `/var/log`.
Rationale:

The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from partitions designated for log files.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    The mount point '/var/log' is not even in /etc/fstab, so we can't set up mount options
    Not remediating, because there is no record of /var/log in /etc/fstab

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    function perform_remediation {

            mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var/log")"

        grep "$mount_point_match_regexp" -q /etc/fstab \
            || { echo "The mount point '/var/log' is not even in /etc/fstab, so we can't set up mount options" >&2;
                    echo "Not remediating, because there is no record of /var/log in /etc/fstab" >&2; return 1; }

        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var/log)"

        # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
        if [ "$(grep -c "$mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
            # runtime opts without some automatic kernel/userspace-added defaults
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
                        | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//")
            [ "$previous_mount_opts" ] && previous_mount_opts+=","
            echo " /var/log  defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab
        # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
        elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nosuid")" -eq 0 ]; then
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
            sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab
        fi

        if mkdir -p "/var/log"; then
            if mountpoint -q "/var/log"; then
                mount -o remount --target "/var/log"
            else
                mount --target "/var/log"
            fi
        fi
    }

    perform_remediation

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | high
Strategy: | configure

    - name: 'Add nosuid Option to /var/log: Check information associated to mountpoint'
      command: findmnt --fstab '/var/log'
      register: device_name
      failed_when: device_name.rc > 1
      changed_when: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83870-6
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /var/log: Create mount_info dictionary variable'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - '{{ device_name.stdout_lines[0].split() | list | lower }}'
      - '{{ device_name.stdout_lines[1].split() | list }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - device_name.stdout is defined and device_name.stdout_lines is defined
      - (device_name.stdout | length > 0)
      tags:
      - CCE-83870-6
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /var/log: If /var/log not mounted, craft mount_info
        manually'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - - target
        - source
        - fstype
        - options
      - - /var/log
        - ''
        - ''
        - defaults
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - ("--fstab" | length == 0)
      - (device_name.stdout | length == 0)
      tags:
      - CCE-83870-6
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /var/log: Make sure nosuid option is part of the to
        /var/log options'
      set_fact:
        mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid''
          }) }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - mount_info is defined and "nosuid" not in mount_info.options
      tags:
      - CCE-83870-6
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /var/log: Ensure /var/log is mounted with nosuid option'
      mount:
        path: /var/log
        src: '{{ mount_info.source }}'
        opts: '{{ mount_info.options }}'
        state: mounted
        fstype: '{{ mount_info.fstype }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
        | length == 0)
      tags:
      - CCE-83870-6
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_log_nosuid
      - no_reboot_needed

Remediation Anaconda snippet

Complexity: | low
Disruption: | high
Strategy: | enable

    part /var/log --mountoptions="nosuid"

OVAL definition:

Definition ID:

oval:ssg-mount_option_var_log_nosuid:def:1

Class:

compliance

Title:

Add nosuid Option to /var/log

Version:

2

Description:

/var/log should be mounted with mount option nosuid.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-mount_option_var_log_nosuid:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Add nodev Option to /var medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_mount_option_var_nodev
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83868-0

References:

CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154, 1.1.3.2
Description:
The `nodev` mount option can be used to prevent device files from being created in `/var`. Legitimate character and block devices should exist only in the `/dev` directory on the root partition or within chroot jails built for system services. Add the `nodev` option to the fourth column of `/etc/fstab` for the line which controls mounting of `/var`.
Rationale:

The only legitimate location for device files is the `/dev` directory located on the root partition. The only exception to this is chroot jails.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    The mount point '/var' is not even in /etc/fstab, so we can't set up mount options
    Not remediating, because there is no record of /var in /etc/fstab

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    function perform_remediation {

            mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var")"

        grep "$mount_point_match_regexp" -q /etc/fstab \
            || { echo "The mount point '/var' is not even in /etc/fstab, so we can't set up mount options" >&2;
                    echo "Not remediating, because there is no record of /var in /etc/fstab" >&2; return 1; }

        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var)"

        # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
        if [ "$(grep -c "$mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
            # runtime opts without some automatic kernel/userspace-added defaults
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
                        | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//")
            [ "$previous_mount_opts" ] && previous_mount_opts+=","
            echo " /var  defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab
        # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
        elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nodev")" -eq 0 ]; then
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
            sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab
        fi

        if mkdir -p "/var"; then
            if mountpoint -q "/var"; then
                mount -o remount --target "/var"
            else
                mount --target "/var"
            fi
        fi
    }

    perform_remediation

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | high
Strategy: | configure

    - name: 'Add nodev Option to /var: Check information associated to mountpoint'
      command: findmnt --fstab '/var'
      register: device_name
      failed_when: device_name.rc > 1
      changed_when: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83868-0
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /var: Create mount_info dictionary variable'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - '{{ device_name.stdout_lines[0].split() | list | lower }}'
      - '{{ device_name.stdout_lines[1].split() | list }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - device_name.stdout is defined and device_name.stdout_lines is defined
      - (device_name.stdout | length > 0)
      tags:
      - CCE-83868-0
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /var: If /var not mounted, craft mount_info manually'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - - target
        - source
        - fstype
        - options
      - - /var
        - ''
        - ''
        - defaults
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - ("--fstab" | length == 0)
      - (device_name.stdout | length == 0)
      tags:
      - CCE-83868-0
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /var: Make sure nodev option is part of the to /var options'
      set_fact:
        mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev''
          }) }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - mount_info is defined and "nodev" not in mount_info.options
      tags:
      - CCE-83868-0
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /var: Ensure /var is mounted with nodev option'
      mount:
        path: /var
        src: '{{ mount_info.source }}'
        opts: '{{ mount_info.options }}'
        state: mounted
        fstype: '{{ mount_info.fstype }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
        | length == 0)
      tags:
      - CCE-83868-0
      - NIST-800-53-AC-6
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-MP-7
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_nodev
      - no_reboot_needed

Remediation Anaconda snippet

Complexity: | low
Disruption: | high
Strategy: | enable

    part /var --mountoptions="nodev"

OVAL definition:

Definition ID:

oval:ssg-mount_option_var_nodev:def:1

Class:

compliance

Title:

Add nodev Option to /var

Version:

2

Description:

/var should be mounted with mount option nodev.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-mount_option_var_nodev:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Add nosuid Option to /var unknown fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_mount_option_var_nosuid
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

unknown

Identifiers:

CCE-83867-2

References:

BP28(R12), 1.1.3.3
Description:
The `nosuid` mount option can be used to prevent execution of setuid programs in `/var`. The SUID and SGID permissions should not be required for this directory. Add the `nosuid` option to the fourth column of `/etc/fstab` for the line which controls mounting of `/var`.
Rationale:

The presence of SUID and SGID executables should be tightly controlled.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    The mount point '/var' is not even in /etc/fstab, so we can't set up mount options
    Not remediating, because there is no record of /var in /etc/fstab

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    function perform_remediation {

            mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var")"

        grep "$mount_point_match_regexp" -q /etc/fstab \
            || { echo "The mount point '/var' is not even in /etc/fstab, so we can't set up mount options" >&2;
                    echo "Not remediating, because there is no record of /var in /etc/fstab" >&2; return 1; }

        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var)"

        # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
        if [ "$(grep -c "$mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
            # runtime opts without some automatic kernel/userspace-added defaults
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
                        | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//")
            [ "$previous_mount_opts" ] && previous_mount_opts+=","
            echo " /var  defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab
        # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
        elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nosuid")" -eq 0 ]; then
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
            sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab
        fi

        if mkdir -p "/var"; then
            if mountpoint -q "/var"; then
                mount -o remount --target "/var"
            else
                mount --target "/var"
            fi
        fi
    }

    perform_remediation

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | high
Strategy: | configure

    - name: 'Add nosuid Option to /var: Check information associated to mountpoint'
      command: findmnt --fstab '/var'
      register: device_name
      failed_when: device_name.rc > 1
      changed_when: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83867-2
      - configure_strategy
      - high_disruption
      - low_complexity
      - mount_option_var_nosuid
      - no_reboot_needed
      - unknown_severity

    - name: 'Add nosuid Option to /var: Create mount_info dictionary variable'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - '{{ device_name.stdout_lines[0].split() | list | lower }}'
      - '{{ device_name.stdout_lines[1].split() | list }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - device_name.stdout is defined and device_name.stdout_lines is defined
      - (device_name.stdout | length > 0)
      tags:
      - CCE-83867-2
      - configure_strategy
      - high_disruption
      - low_complexity
      - mount_option_var_nosuid
      - no_reboot_needed
      - unknown_severity

    - name: 'Add nosuid Option to /var: If /var not mounted, craft mount_info manually'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - - target
        - source
        - fstype
        - options
      - - /var
        - ''
        - ''
        - defaults
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - ("--fstab" | length == 0)
      - (device_name.stdout | length == 0)
      tags:
      - CCE-83867-2
      - configure_strategy
      - high_disruption
      - low_complexity
      - mount_option_var_nosuid
      - no_reboot_needed
      - unknown_severity

    - name: 'Add nosuid Option to /var: Make sure nosuid option is part of the to /var
        options'
      set_fact:
        mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid''
          }) }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - mount_info is defined and "nosuid" not in mount_info.options
      tags:
      - CCE-83867-2
      - configure_strategy
      - high_disruption
      - low_complexity
      - mount_option_var_nosuid
      - no_reboot_needed
      - unknown_severity

    - name: 'Add nosuid Option to /var: Ensure /var is mounted with nosuid option'
      mount:
        path: /var
        src: '{{ mount_info.source }}'
        opts: '{{ mount_info.options }}'
        state: mounted
        fstype: '{{ mount_info.fstype }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
        | length == 0)
      tags:
      - CCE-83867-2
      - configure_strategy
      - high_disruption
      - low_complexity
      - mount_option_var_nosuid
      - no_reboot_needed
      - unknown_severity

Remediation Anaconda snippet

Complexity: | low
Disruption: | high
Strategy: | enable

    part /var --mountoptions="nosuid"

OVAL definition:

Definition ID:

oval:ssg-mount_option_var_nosuid:def:1

Class:

compliance

Title:

Add nosuid Option to /var

Version:

2

Description:

/var should be mounted with mount option nosuid.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-mount_option_var_nosuid:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Add nodev Option to /var/tmp medium notapplicable

Rule ID: | xccdf_org.ssgproject.content_rule_mount_option_var_tmp_nodev
Result: | notapplicable
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83864-9

References:

BP28(R12), CCI-001764, SRG-OS-000368-GPOS-00154, 1.1.4.4
Description:
The `nodev` mount option can be used to prevent device files from being created in `/var/tmp`. Legitimate character and block devices should not exist within temporary directories like `/var/tmp`. Add the `nodev` option to the fourth column of `/etc/fstab` for the line which controls mounting of `/var/tmp`.
Rationale:

The only legitimate location for device files is the `/dev` directory located on the root partition. The only exception to this is chroot jails.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/var/tmp" > /dev/null ); then

    function perform_remediation {

            mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var/tmp")"

        grep "$mount_point_match_regexp" -q /etc/fstab \
            || { echo "The mount point '/var/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2;
                    echo "Not remediating, because there is no record of /var/tmp in /etc/fstab" >&2; return 1; }

        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var/tmp)"

        # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
        if [ "$(grep -c "$mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
            # runtime opts without some automatic kernel/userspace-added defaults
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
                        | sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//")
            [ "$previous_mount_opts" ] && previous_mount_opts+=","
            echo " /var/tmp  defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab
        # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
        elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nodev")" -eq 0 ]; then
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
            sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab
        fi

        if mkdir -p "/var/tmp"; then
            if mountpoint -q "/var/tmp"; then
                mount -o remount --target "/var/tmp"
            else
                mount --target "/var/tmp"
            fi
        fi
    }

    perform_remediation

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | high
Strategy: | configure

    - name: 'Add nodev Option to /var/tmp: Check information associated to mountpoint'
      command: findmnt --fstab '/var/tmp'
      register: device_name
      failed_when: device_name.rc > 1
      changed_when: false
      when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman",
        "container"] and "/var/tmp" in ansible_mounts | map(attribute="mount") | list
        )
      tags:
      - CCE-83864-9
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_tmp_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /var/tmp: Create mount_info dictionary variable'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - '{{ device_name.stdout_lines[0].split() | list | lower }}'
      - '{{ device_name.stdout_lines[1].split() | list }}'
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/var/tmp" in ansible_mounts | map(attribute="mount") | list )
      - device_name.stdout is defined and device_name.stdout_lines is defined
      - (device_name.stdout | length > 0)
      tags:
      - CCE-83864-9
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_tmp_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /var/tmp: If /var/tmp not mounted, craft mount_info manually'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - - target
        - source
        - fstype
        - options
      - - /var/tmp
        - ''
        - ''
        - defaults
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/var/tmp" in ansible_mounts | map(attribute="mount") | list )
      - ("--fstab" | length == 0)
      - (device_name.stdout | length == 0)
      tags:
      - CCE-83864-9
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_tmp_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /var/tmp: Make sure nodev option is part of the to /var/tmp
        options'
      set_fact:
        mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev''
          }) }}'
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/var/tmp" in ansible_mounts | map(attribute="mount") | list )
      - mount_info is defined and "nodev" not in mount_info.options
      tags:
      - CCE-83864-9
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_tmp_nodev
      - no_reboot_needed

    - name: 'Add nodev Option to /var/tmp: Ensure /var/tmp is mounted with nodev option'
      mount:
        path: /var/tmp
        src: '{{ mount_info.source }}'
        opts: '{{ mount_info.options }}'
        state: mounted
        fstype: '{{ mount_info.fstype }}'
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/var/tmp" in ansible_mounts | map(attribute="mount") | list )
      - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
        | length == 0)
      tags:
      - CCE-83864-9
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_tmp_nodev
      - no_reboot_needed

Remediation Anaconda snippet

Complexity: | low
Disruption: | high
Strategy: | enable

    part /var/tmp --mountoptions="nodev"

OVAL definition:

Definition ID:

oval:ssg-mount_option_var_tmp_nodev:def:1

Class:

compliance

Title:

Add nodev Option to /var/tmp

Version:

2

Description:

/var/tmp should be mounted with mount option nodev.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-mount_option_var_tmp_nodev:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine_and_partition-var-tmp
Add noexec Option to /var/tmp medium notapplicable

Rule ID: | xccdf_org.ssgproject.content_rule_mount_option_var_tmp_noexec
Result: | notapplicable
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83866-4

References:

BP28(R12), CCI-001764, SRG-OS-000368-GPOS-00154, 1.1.4.2
Description:
The `noexec` mount option can be used to prevent binaries from being executed out of `/var/tmp`. Add the `noexec` option to the fourth column of `/etc/fstab` for the line which controls mounting of `/var/tmp`.
Rationale:

Allowing users to execute binaries from world-writable directories such as `/var/tmp` should never be necessary in normal operation and can expose the system to potential compromise.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/var/tmp" > /dev/null ); then

    function perform_remediation {

            mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var/tmp")"

        grep "$mount_point_match_regexp" -q /etc/fstab \
            || { echo "The mount point '/var/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2;
                    echo "Not remediating, because there is no record of /var/tmp in /etc/fstab" >&2; return 1; }

        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var/tmp)"

        # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
        if [ "$(grep -c "$mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
            # runtime opts without some automatic kernel/userspace-added defaults
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
                        | sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//")
            [ "$previous_mount_opts" ] && previous_mount_opts+=","
            echo " /var/tmp  defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab
        # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
        elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "noexec")" -eq 0 ]; then
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
            sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab
        fi

        if mkdir -p "/var/tmp"; then
            if mountpoint -q "/var/tmp"; then
                mount -o remount --target "/var/tmp"
            else
                mount --target "/var/tmp"
            fi
        fi
    }

    perform_remediation

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | high
Strategy: | configure

    - name: 'Add noexec Option to /var/tmp: Check information associated to mountpoint'
      command: findmnt --fstab '/var/tmp'
      register: device_name
      failed_when: device_name.rc > 1
      changed_when: false
      when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman",
        "container"] and "/var/tmp" in ansible_mounts | map(attribute="mount") | list
        )
      tags:
      - CCE-83866-4
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_tmp_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /var/tmp: Create mount_info dictionary variable'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - '{{ device_name.stdout_lines[0].split() | list | lower }}'
      - '{{ device_name.stdout_lines[1].split() | list }}'
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/var/tmp" in ansible_mounts | map(attribute="mount") | list )
      - device_name.stdout is defined and device_name.stdout_lines is defined
      - (device_name.stdout | length > 0)
      tags:
      - CCE-83866-4
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_tmp_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /var/tmp: If /var/tmp not mounted, craft mount_info
        manually'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - - target
        - source
        - fstype
        - options
      - - /var/tmp
        - ''
        - ''
        - defaults
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/var/tmp" in ansible_mounts | map(attribute="mount") | list )
      - ("--fstab" | length == 0)
      - (device_name.stdout | length == 0)
      tags:
      - CCE-83866-4
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_tmp_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /var/tmp: Make sure noexec option is part of the to
        /var/tmp options'
      set_fact:
        mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec''
          }) }}'
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/var/tmp" in ansible_mounts | map(attribute="mount") | list )
      - mount_info is defined and "noexec" not in mount_info.options
      tags:
      - CCE-83866-4
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_tmp_noexec
      - no_reboot_needed

    - name: 'Add noexec Option to /var/tmp: Ensure /var/tmp is mounted with noexec option'
      mount:
        path: /var/tmp
        src: '{{ mount_info.source }}'
        opts: '{{ mount_info.options }}'
        state: mounted
        fstype: '{{ mount_info.fstype }}'
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/var/tmp" in ansible_mounts | map(attribute="mount") | list )
      - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
        | length == 0)
      tags:
      - CCE-83866-4
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_tmp_noexec
      - no_reboot_needed

Remediation Anaconda snippet

Complexity: | low
Disruption: | high
Strategy: | enable

    part /var/tmp --mountoptions="noexec"

OVAL definition:

Definition ID:

oval:ssg-mount_option_var_tmp_noexec:def:1

Class:

compliance

Title:

Add noexec Option to /var/tmp

Version:

2

Description:

/var/tmp should be mounted with mount option noexec.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-mount_option_var_tmp_noexec:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine_and_partition-var-tmp
Add nosuid Option to /var/tmp medium notapplicable

Rule ID: | xccdf_org.ssgproject.content_rule_mount_option_var_tmp_nosuid
Result: | notapplicable
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83863-1

References:

BP28(R12), CCI-001764, SRG-OS-000368-GPOS-00154, 1.1.4.3
Description:
The `nosuid` mount option can be used to prevent execution of setuid programs in `/var/tmp`. The SUID and SGID permissions should not be required in these world-writable directories. Add the `nosuid` option to the fourth column of `/etc/fstab` for the line which controls mounting of `/var/tmp`.
Rationale:

The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from temporary storage partitions.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if ( [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && findmnt --kernel "/var/tmp" > /dev/null ); then

    function perform_remediation {

            mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var/tmp")"

        grep "$mount_point_match_regexp" -q /etc/fstab \
            || { echo "The mount point '/var/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2;
                    echo "Not remediating, because there is no record of /var/tmp in /etc/fstab" >&2; return 1; }

        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var/tmp)"

        # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
        if [ "$(grep -c "$mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
            # runtime opts without some automatic kernel/userspace-added defaults
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
                        | sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//")
            [ "$previous_mount_opts" ] && previous_mount_opts+=","
            echo " /var/tmp  defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab
        # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
        elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nosuid")" -eq 0 ]; then
            previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
            sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab
        fi

        if mkdir -p "/var/tmp"; then
            if mountpoint -q "/var/tmp"; then
                mount -o remount --target "/var/tmp"
            else
                mount --target "/var/tmp"
            fi
        fi
    }

    perform_remediation

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | high
Strategy: | configure

    - name: 'Add nosuid Option to /var/tmp: Check information associated to mountpoint'
      command: findmnt --fstab '/var/tmp'
      register: device_name
      failed_when: device_name.rc > 1
      changed_when: false
      when: ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman",
        "container"] and "/var/tmp" in ansible_mounts | map(attribute="mount") | list
        )
      tags:
      - CCE-83863-1
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_tmp_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /var/tmp: Create mount_info dictionary variable'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - '{{ device_name.stdout_lines[0].split() | list | lower }}'
      - '{{ device_name.stdout_lines[1].split() | list }}'
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/var/tmp" in ansible_mounts | map(attribute="mount") | list )
      - device_name.stdout is defined and device_name.stdout_lines is defined
      - (device_name.stdout | length > 0)
      tags:
      - CCE-83863-1
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_tmp_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /var/tmp: If /var/tmp not mounted, craft mount_info
        manually'
      set_fact:
        mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
      with_together:
      - - target
        - source
        - fstype
        - options
      - - /var/tmp
        - ''
        - ''
        - defaults
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/var/tmp" in ansible_mounts | map(attribute="mount") | list )
      - ("--fstab" | length == 0)
      - (device_name.stdout | length == 0)
      tags:
      - CCE-83863-1
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_tmp_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /var/tmp: Make sure nosuid option is part of the to
        /var/tmp options'
      set_fact:
        mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid''
          }) }}'
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/var/tmp" in ansible_mounts | map(attribute="mount") | list )
      - mount_info is defined and "nosuid" not in mount_info.options
      tags:
      - CCE-83863-1
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_tmp_nosuid
      - no_reboot_needed

    - name: 'Add nosuid Option to /var/tmp: Ensure /var/tmp is mounted with nosuid option'
      mount:
        path: /var/tmp
        src: '{{ mount_info.source }}'
        opts: '{{ mount_info.options }}'
        state: mounted
        fstype: '{{ mount_info.fstype }}'
      when:
      - ( ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
        and "/var/tmp" in ansible_mounts | map(attribute="mount") | list )
      - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
        | length == 0)
      tags:
      - CCE-83863-1
      - configure_strategy
      - high_disruption
      - low_complexity
      - medium_severity
      - mount_option_var_tmp_nosuid
      - no_reboot_needed

Remediation Anaconda snippet

Complexity: | low
Disruption: | high
Strategy: | enable

    part /var/tmp --mountoptions="nosuid"

OVAL definition:

Definition ID:

oval:ssg-mount_option_var_tmp_nosuid:def:1

Class:

compliance

Title:

Add nosuid Option to /var/tmp

Version:

2

Description:

/var/tmp should be mounted with mount option nosuid.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-mount_option_var_tmp_nosuid:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine_and_partition-var-tmp
Ensure There Are No Accounts With Blank or Null Passwords high error

Rule ID: | xccdf_org.ssgproject.content_rule_no_empty_passwords_etc_shadow
Result: | error
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

high

Identifiers:

CCE-85972-8

References:

CCI-000366, CM-6(b), CM-6.1(iv), SRG-OS-000480-GPOS-00227, 5.6.6, 6.2.2
Description:
Check the "/etc/shadow" file for blank passwords with the following command:

    $ sudo awk -F: '!$2 {print $1}' /etc/shadow

If the command returns any results, this is a finding. Configure all accounts on the system to have a password or lock the account with the following commands: Perform a password reset:

    $ sudo passwd [username]

Lock an account:

    $ sudo passwd -l [username]

Rationale:

If an account has an empty password, anyone could log in and run commands with the privileges of that account. Accounts with empty passwords should never be used in operational environments.

Warnings:

General warning
Note that this rule is not applicable for systems running within a container. Having user with empty password within a container is not considered a risk, because it should not be possible to directly login into a container anyway.
Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Collect users with no password
      command: |
        awk -F: '!$2 {print $1}' /etc/shadow
      register: users_nopasswd
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-85972-8
      - NIST-800-53-CM-6(b)
      - NIST-800-53-CM-6.1(iv)
      - high_severity
      - low_complexity
      - low_disruption
      - no_empty_passwords_etc_shadow
      - no_reboot_needed
      - restrict_strategy

    - name: Lock users with no password
      command: |
        passwd -l {{ item }}
      with_items: '{{ users_nopasswd.stdout_lines }}'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - users_nopasswd.stdout_lines | length > 0
      tags:
      - CCE-85972-8
      - NIST-800-53-CM-6(b)
      - NIST-800-53-CM-6.1(iv)
      - high_severity
      - low_complexity
      - low_disruption
      - no_empty_passwords_etc_shadow
      - no_reboot_needed
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-no_empty_passwords_etc_shadow:def:1

Class:

compliance

Title:

Ensure There Are No Accounts With Blank or Null Passwords

Version:

1

Description:

The file /etc/shadow shows that there aren't empty passwords

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-no_empty_passwords_etc_shadow:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Ensure All Files Are Owned by a User medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_no_files_unowned_by_user
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83896-1

References:

11, 12, 13, 14, 15, 16, 18, 3, 5, 9, APO01.06, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.03, DSS06.06, CCI-000366, CCI-002165, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 5.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.2, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.1, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.AC-6, PR.DS-5, PR.IP-1, PR.PT-3, SRG-OS-000480-GPOS-00227, 6.1.10
Description:
If any files are not owned by a user, then the cause of their lack of ownership should be investigated. Following this, the files should be deleted or assigned to an appropriate user. The following command will discover and print any files on local partitions which do not belong to a valid user:

    $ df --local -P | awk {'if (NR!=1) print $6'} | sudo xargs -I '{}' find '{}' -xdev -nouser

To search all filesystems on a system including network mounted filesystems the following command can be run manually for each partition:

    $ sudo find PARTITION -xdev -nouser

Rationale:

Unowned files do not directly imply a security problem, but they are generally a sign that something is amiss. They may be caused by an intruder, by incorrect software installation or draft software removal, or by failure to remove all files belonging to a deleted account. The files should be repaired so they will not cause problems when accounts are created in the future, and the cause should be discovered and addressed.

Warnings:

Functionality warning
For this rule to evaluate centralized user accounts, `getent` must be working properly so that running the command

    getent passwd

returns a list of all users in your organization. If using the System Security Services Daemon (SSSD),

    enumerate = true

must be configured in your organization's domain to return a complete list of users

Performance warning
Enabling this rule will result in slower scan times depending on the size of your organization and number of centralized users.
OVAL definition:

Definition ID:

oval:ssg-no_files_unowned_by_user:def:1

Class:

compliance

Title:

Ensure All Files Are Owned by a User

Version:

1

Description:

All files should be owned by a user

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-no_files_unowned_by_user:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Verify No netrc Files Exist medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_no_netrc_files
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83617-1

References:

1, 11, 12, 14, 15, 16, 18, 3, 5, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.06, DSS06.10, CCI-000196, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, A.18.1.4, A.6.1.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, CIP-003-8 R1.3, CIP-003-8 R3, CIP-003-8 R3.1, CIP-003-8 R3.2, CIP-003-8 R3.3, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.2.3, CIP-004-6 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.2, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, IA-5(h), IA-5(1)(c), CM-6(a), IA-5(7), PR.AC-1, PR.AC-4, PR.AC-6, PR.AC-7, PR.PT-3, 6.2.13
Description:
The `.netrc` files contain login information used to auto-login into FTP servers and reside in the user's home directory. These files may contain unencrypted passwords to remote FTP servers making them susceptible to access by unauthorized users and should not be used. Any `.netrc` files should be removed.
Rationale:

Unencrypted passwords for remote FTP servers may be stored in `.netrc` files.

OVAL definition:

Definition ID:

oval:ssg-no_netrc_files:def:1

Class:

compliance

Title:

Verify No netrc Files Exist

Version:

1

Description:

The .netrc files contain login information used to auto-login into FTP servers and reside in the user's home directory. Any .netrc files should be removed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-no_netrc_files:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Remove Rsh Trust Files high pass

Rule ID: | xccdf_org.ssgproject.content_rule_no_rsh_trust_files
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

high

Identifiers:

CCE-84145-2

References:

11, 12, 14, 15, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.04, DSS05.02, DSS05.03, DSS05.05, DSS06.06, CCI-001436, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 7.1, SR 7.6, A.11.2.6, A.12.1.2, A.12.5.1, A.12.6.2, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.6.2.1, A.6.2.2, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.AC-3, PR.IP-1, PR.PT-3, PR.PT-4, 6.2.15
Description:
The files `/etc/hosts.equiv` and `~/.rhosts` (in each user's home directory) list remote hosts and users that are trusted by the local system when using the rshd daemon. To remove these files, run the following command to delete them from any location:

    $ sudo rm /etc/hosts.equiv

    $ rm ~/.rhosts

Rationale:

This action is only meaningful if `.rhosts` support is permitted through PAM. Trust files are convenient, but when used in conjunction with the R-services, they can allow unauthenticated access to a system.

Remediation Shell script

    find /root -xdev -type f -name ".rhosts" -exec rm -f {} \;
    find /home -maxdepth 2 -xdev -type f -name ".rhosts" -exec rm -f {} \;
    rm -f /etc/hosts.equiv

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - block:

      - name: Detect .rhosts files in users home directories
        find:
          paths:
          - /root
          - /home
          recurse: true
          patterns: .rhosts
          hidden: true
          file_type: file
        check_mode: false
        register: rhosts_locations

      - name: Remove .rhosts files
        file:
          path: '{{ item }}'
          state: absent
        with_items: '{{ rhosts_locations.files | map(attribute=''path'') | list }}'
        when: rhosts_locations is success

      - name: Remove /etc/hosts.equiv file
        file:
          path: /etc/hosts.equiv
          state: absent
      tags:
      - CCE-84145-2
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - high_severity
      - low_complexity
      - low_disruption
      - no_reboot_needed
      - no_rsh_trust_files
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-no_rsh_trust_files:def:1

Class:

compliance

Title:

Remove Rsh Trust Files

Version:

1

Description:

There should not be any .rhosts or hosts.equiv files on the system.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-no_rsh_trust_files:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Ensure that System Accounts Do Not Run a Shell Upon Login medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_no_shelllogin_for_systemaccounts
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83623-9

References:

1, 12, 13, 14, 15, 16, 18, 3, 5, 7, 8, DSS01.03, DSS03.05, DSS05.04, DSS05.05, DSS05.07, DSS06.03, CCI-000366, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, SR 1.1, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 6.2, 1491, A.12.4.1, A.12.4.3, A.6.1.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, AC-6, CM-6(a), CM-6(b), CM-6.1(iv), DE.CM-1, DE.CM-3, PR.AC-1, PR.AC-4, PR.AC-6, Req-8.6.1, SRG-OS-000480-GPOS-00227, 5.6.2
Description:
Some accounts are not associated with a human user of the system, and exist to perform some administrative function. Should an attacker be able to log into these accounts, they should not be granted access to a shell.
The login shell for each local account is stored in the last field of each line in `/etc/passwd`. System accounts are those user accounts with a user ID less than UID_MIN, where value of UID_MIN directive is set in /etc/login.defs configuration file. In the default configuration UID_MIN is set to 1000, thus system accounts are those user accounts with a user ID less than 1000. The user ID is stored in the third field. If any system account SYSACCT (other than root) has a login shell, disable it with the command:

    $ sudo usermod -s /sbin/nologin SYSACCT

Rationale:

Ensuring shells are not given to system accounts upon login makes it more difficult for attackers to make use of system accounts.

Warnings:

Functionality warning
Do not perform the steps in this section on the root account. Doing so might cause the system to become inaccessible.
OVAL definition:

Definition ID:

oval:ssg-no_shelllogin_for_systemaccounts:def:1

Class:

compliance

Title:

Ensure that System Accounts Do Not Run a Shell Upon Login

Version:

2

Description:

The root account is the only system account that should have a login shell.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-no_shelllogin_for_systemaccounts:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Install AIDE medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_package_aide_installed
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:14+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90843-4

References:

BP28(R51), 1, 11, 12, 13, 14, 15, 16, 2, 3, 5, 7, 8, 9, 5.10.1.3, APO01.06, BAI01.06, BAI02.01, BAI03.05, BAI06.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS03.05, DSS04.07, DSS05.02, DSS05.03, DSS05.05, DSS05.07, DSS06.02, DSS06.06, CCI-002696, CCI-002699, CCI-001744, 4.3.4.3.2, 4.3.4.3.3, 4.3.4.4.4, SR 3.1, SR 3.3, SR 3.4, SR 3.8, SR 4.1, SR 6.2, SR 7.6, 1034, 1288, 1341, 1417, A.11.2.4, A.12.1.2, A.12.2.1, A.12.4.1, A.12.5.1, A.12.6.2, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.14.2.7, A.15.2.1, A.8.2.3, CM-6(a), DE.CM-1, DE.CM-7, PR.DS-1, PR.DS-6, PR.DS-8, PR.IP-1, PR.IP-3, Req-11.5, SRG-OS-000445-GPOS-00199, 1.3.1
Description:
The `aide` package can be installed with the following command:

    $ sudo dnf install aide

Rationale:

The AIDE package must be installed if it is to be available for integrity checking.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    Not root, Subscription Management repositories not updated
    Error: This command has to be run with superuser privileges (under the root user on most systems).

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | enable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    if ! rpm -q --quiet "aide" ; then
        dnf install -y "aide"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    - name: Ensure aide is installed
      package:
        name: aide
        state: present
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90843-4
      - CJIS-5.10.1.3
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-11.5
      - enable_strategy
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - package_aide_installed

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    include install_aide

    class install_aide {
      package { 'aide':
        ensure => 'installed',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    package --add=aide

Remediation OSBuild Blueprint snippet

    [[packages]]
    name = "aide"
    version = "*"

OVAL definition:

Definition ID:

oval:ssg-package_aide_installed:def:1

Class:

compliance

Title:

Install AIDE

Version:

1

Description:

The RPM package aide should be installed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_aide_installed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Uninstall bind Package low pass

Rule ID: | xccdf_org.ssgproject.content_rule_package_bind_removed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

low

Identifiers:

CCE-86505-5

References:

11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, CCI-000366, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3, 2.2.5
Description:
The `named` service is provided by the `bind` package. The `bind` package can be removed with the following command:

    $ sudo dnf erase bind

Rationale:

If there is no need to make DNS server software available, removing it provides a safeguard against its activation.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | disable

    # CAUTION: This remediation script will remove bind
    #	   from the system, and may remove any packages
    #	   that depend on bind. Execute this
    #	   remediation AFTER testing on a non-production
    #	   system!

    if rpm -q --quiet "bind" ; then

        dnf remove -y "bind"

    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    - name: Ensure bind is removed
      package:
        name: bind
        state: absent
      tags:
      - CCE-86505-5
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - low_disruption
      - low_severity
      - no_reboot_needed
      - package_bind_removed

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    include remove_bind

    class remove_bind {
      package { 'bind':
        ensure => 'purged',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    package --remove=bind

OVAL definition:

Definition ID:

oval:ssg-package_bind_removed:def:1

Class:

compliance

Title:

Uninstall bind Package

Version:

1

Description:

The RPM package bind should be removed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_bind_removed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Uninstall DHCP Server Package medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_package_dhcp_removed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84240-1

References:

BP28(R1), 11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, CCI-000366, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3, 2.2.4
Description:
If the system does not need to act as a DHCP server, the dhcp package can be uninstalled. The `dhcp-server` package can be removed with the following command:

    $ sudo dnf erase dhcp-server

Rationale:

Removing the DHCP server ensures that it cannot be easily or accidentally reactivated and disrupt network operation.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | disable

    # CAUTION: This remediation script will remove dhcp-server
    #	   from the system, and may remove any packages
    #	   that depend on dhcp-server. Execute this
    #	   remediation AFTER testing on a non-production
    #	   system!

    if rpm -q --quiet "dhcp-server" ; then

        dnf remove -y "dhcp-server"

    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    - name: Ensure dhcp-server is removed
      package:
        name: dhcp-server
        state: absent
      tags:
      - CCE-84240-1
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - package_dhcp_removed

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    include remove_dhcp-server

    class remove_dhcp-server {
      package { 'dhcp-server':
        ensure => 'purged',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    package --remove=dhcp-server

OVAL definition:

Definition ID:

oval:ssg-package_dhcp_removed:def:1

Class:

compliance

Title:

Uninstall DHCP Server Package

Version:

1

Description:

The RPM package dhcp-server should be removed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_dhcp_removed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Uninstall dovecot Package unknown pass

Rule ID: | xccdf_org.ssgproject.content_rule_package_dovecot_removed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

unknown

Identifiers:

CCE-85977-7

References:

2.2.9
Description:
The `dovecot` package can be removed with the following command:

    $ sudo dnf erase dovecot

Rationale:

If there is no need to make the Dovecot software available, removing it provides a safeguard against its activation.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | disable

    # CAUTION: This remediation script will remove dovecot
    #	   from the system, and may remove any packages
    #	   that depend on dovecot. Execute this
    #	   remediation AFTER testing on a non-production
    #	   system!

    if rpm -q --quiet "dovecot" ; then

        dnf remove -y "dovecot"

    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    - name: Ensure dovecot is removed
      package:
        name: dovecot
        state: absent
      tags:
      - CCE-85977-7
      - disable_strategy
      - low_complexity
      - low_disruption
      - no_reboot_needed
      - package_dovecot_removed
      - unknown_severity

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    include remove_dovecot

    class remove_dovecot {
      package { 'dovecot':
        ensure => 'purged',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    package --remove=dovecot

OVAL definition:

Definition ID:

oval:ssg-package_dovecot_removed:def:1

Class:

compliance

Title:

Uninstall dovecot Package

Version:

1

Description:

The RPM package dovecot should be removed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_dovecot_removed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Uninstall httpd Package unknown pass

Rule ID: | xccdf_org.ssgproject.content_rule_package_httpd_removed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

unknown

Identifiers:

CCE-85974-4

References:

11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3, 2.2.8
Description:
The `httpd` package can be removed with the following command:

    $ sudo dnf erase httpd

Rationale:

If there is no need to make the web server software available, removing it provides a safeguard against its activation.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | disable

    # CAUTION: This remediation script will remove httpd
    #	   from the system, and may remove any packages
    #	   that depend on httpd. Execute this
    #	   remediation AFTER testing on a non-production
    #	   system!

    if rpm -q --quiet "httpd" ; then

        dnf remove -y "httpd"

    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    - name: Ensure httpd is removed
      package:
        name: httpd
        state: absent
      tags:
      - CCE-85974-4
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - low_disruption
      - no_reboot_needed
      - package_httpd_removed
      - unknown_severity

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    include remove_httpd

    class remove_httpd {
      package { 'httpd':
        ensure => 'purged',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    package --remove=httpd

OVAL definition:

Definition ID:

oval:ssg-package_httpd_removed:def:1

Class:

compliance

Title:

Uninstall httpd Package

Version:

1

Description:

The RPM package httpd should be removed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_httpd_removed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Install libselinux Package high pass

Rule ID: | xccdf_org.ssgproject.content_rule_package_libselinux_installed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

high

Identifiers:

CCE-84069-4

References:

1.6.1.1
Description:
The `libselinux` package can be installed with the following command:

    $ sudo dnf install libselinux

Rationale:

Security-enhanced Linux is a feature of the Linux kernel and a number of utilities with enhanced security functionality designed to add mandatory access controls to Linux. The `libselinux` package contains the core library of the Security-enhanced Linux system.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | enable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    if ! rpm -q --quiet "libselinux" ; then
        dnf install -y "libselinux"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    - name: Ensure libselinux is installed
      package:
        name: libselinux
        state: present
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84069-4
      - enable_strategy
      - high_severity
      - low_complexity
      - low_disruption
      - no_reboot_needed
      - package_libselinux_installed

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    include install_libselinux

    class install_libselinux {
      package { 'libselinux':
        ensure => 'installed',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    package --add=libselinux

Remediation OSBuild Blueprint snippet

    [[packages]]
    name = "libselinux"
    version = "*"

OVAL definition:

Definition ID:

oval:ssg-package_libselinux_installed:def:1

Class:

compliance

Title:

Install libselinux Package

Version:

1

Description:

The RPM package libselinux should be installed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_libselinux_installed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Uninstall mcstrans Package low pass

Rule ID: | xccdf_org.ssgproject.content_rule_package_mcstrans_removed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

low

Identifiers:

CCE-84072-8

References:

1.6.1.8
Description:
The `mcstransd` daemon provides category label information to client processes requesting information. The label translations are defined in `/etc/selinux/targeted/setrans.conf`. The `mcstrans` package can be removed with the following command:

    $ sudo dnf erase mcstrans

Rationale:

Since this service is not used very often, disable it to reduce the amount of potentially vulnerable code running on the system.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # CAUTION: This remediation script will remove mcstrans
    #	   from the system, and may remove any packages
    #	   that depend on mcstrans. Execute this
    #	   remediation AFTER testing on a non-production
    #	   system!

    if rpm -q --quiet "mcstrans" ; then

        dnf remove -y "mcstrans"

    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    - name: Ensure mcstrans is removed
      package:
        name: mcstrans
        state: absent
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84072-8
      - disable_strategy
      - low_complexity
      - low_disruption
      - low_severity
      - no_reboot_needed
      - package_mcstrans_removed

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    include remove_mcstrans

    class remove_mcstrans {
      package { 'mcstrans':
        ensure => 'purged',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    package --remove=mcstrans

OVAL definition:

Definition ID:

oval:ssg-package_mcstrans_removed:def:1

Class:

compliance

Title:

Uninstall mcstrans Package

Version:

1

Description:

The RPM package mcstrans should be removed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_mcstrans_removed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Uninstall net-snmp Package unknown pass

Rule ID: | xccdf_org.ssgproject.content_rule_package_net-snmp_removed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

unknown

Identifiers:

CCE-85981-9

References:

2.2.12
Description:
The `net-snmp` package provides the snmpd service. The `net-snmp` package can be removed with the following command:

    $ sudo dnf erase net-snmp

Rationale:

If there is no need to run SNMP server software, removing the package provides a safeguard against its activation.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | disable

    # CAUTION: This remediation script will remove net-snmp
    #	   from the system, and may remove any packages
    #	   that depend on net-snmp. Execute this
    #	   remediation AFTER testing on a non-production
    #	   system!

    if rpm -q --quiet "net-snmp" ; then

        dnf remove -y "net-snmp"

    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    - name: Ensure net-snmp is removed
      package:
        name: net-snmp
        state: absent
      tags:
      - CCE-85981-9
      - disable_strategy
      - low_complexity
      - low_disruption
      - no_reboot_needed
      - package_net-snmp_removed
      - unknown_severity

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    include remove_net-snmp

    class remove_net-snmp {
      package { 'net-snmp':
        ensure => 'purged',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    package --remove=net-snmp

OVAL definition:

Definition ID:

oval:ssg-package_net-snmp_removed:def:1

Class:

compliance

Title:

Uninstall net-snmp Package

Version:

1

Description:

The RPM package net-snmp should be removed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_net-snmp_removed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Install nftables Package medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_package_nftables_installed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:50+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86378-7

References:

3.4.1.1
Description:
nftables provides a new in-kernel packet classification framework that is based on a network-specific Virtual Machine (VM) and a new nft userspace command line tool. nftables reuses the existing Netfilter subsystems such as the existing hook infrastructure, the connection tracking system, NAT, userspace queuing and logging subsystem. The `nftables` package can be installed with the following command:

    $ sudo dnf install nftables

Rationale:

`nftables` is a subsystem of the Linux kernel that can protect against threats originating from within a corporate network to include malicious mobile code and poorly configured software on a host.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | enable

    if ! rpm -q --quiet "nftables" ; then
        dnf install -y "nftables"
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    - name: Ensure nftables is installed
      package:
        name: nftables
        state: present
      tags:
      - CCE-86378-7
      - enable_strategy
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - package_nftables_installed

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    include install_nftables

    class install_nftables {
      package { 'nftables':
        ensure => 'installed',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    package --add=nftables

Remediation OSBuild Blueprint snippet

    [[packages]]
    name = "nftables"
    version = "*"

OVAL definition:

Definition ID:

oval:ssg-package_nftables_installed:def:1

Class:

compliance

Title:

Install nftables Package

Version:

1

Description:

The RPM package nftables should be installed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_nftables_installed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Ensure LDAP client is not installed low pass

Rule ID: | xccdf_org.ssgproject.content_rule_package_openldap-clients_removed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

low

Identifiers:

CCE-90831-9

References:

Req-2.2.4, 2.3.2
Description:
The Lightweight Directory Access Protocol (LDAP) is a service that provides a method for looking up information from a central database. The `openldap-clients` package can be removed with the following command:

    $ sudo dnf erase openldap-clients

Rationale:

If the system does not need to act as an LDAP client, it is recommended that the software is removed to reduce the potential attack surface.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | disable

    # CAUTION: This remediation script will remove openldap-clients
    #	   from the system, and may remove any packages
    #	   that depend on openldap-clients. Execute this
    #	   remediation AFTER testing on a non-production
    #	   system!

    if rpm -q --quiet "openldap-clients" ; then

        dnf remove -y "openldap-clients"

    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    - name: Ensure openldap-clients is removed
      package:
        name: openldap-clients
        state: absent
      tags:
      - CCE-90831-9
      - PCI-DSS-Req-2.2.4
      - disable_strategy
      - low_complexity
      - low_disruption
      - low_severity
      - no_reboot_needed
      - package_openldap-clients_removed

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    include remove_openldap-clients

    class remove_openldap-clients {
      package { 'openldap-clients':
        ensure => 'purged',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    package --remove=openldap-clients

OVAL definition:

Definition ID:

oval:ssg-package_openldap-clients_removed:def:1

Class:

compliance

Title:

Ensure LDAP client is not installed

Version:

1

Description:

The RPM package openldap-clients should be removed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_openldap-clients_removed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Uninstall rsync Package medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_package_rsync_removed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86336-5

References:

2.2.18
Description:
The rsyncd service can be used to synchronize files between systems over network links. The `rsync-daemon` package can be removed with the following command:

    $ sudo dnf erase rsync-daemon

Rationale:

The rsyncd service presents a security risk as it uses unencrypted protocols for communication.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | disable

    # CAUTION: This remediation script will remove rsync-daemon
    #	   from the system, and may remove any packages
    #	   that depend on rsync-daemon. Execute this
    #	   remediation AFTER testing on a non-production
    #	   system!

    if rpm -q --quiet "rsync-daemon" ; then

        dnf remove -y "rsync-daemon"

    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    - name: Ensure rsync-daemon is removed
      package:
        name: rsync-daemon
        state: absent
      tags:
      - CCE-86336-5
      - disable_strategy
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - package_rsync_removed

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    include remove_rsync-daemon

    class remove_rsync-daemon {
      package { 'rsync-daemon':
        ensure => 'purged',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    package --remove=rsync-daemon

OVAL definition:

Definition ID:

oval:ssg-package_rsync_removed:def:1

Class:

compliance

Title:

Uninstall rsync Package

Version:

1

Description:

The RPM package rsync-daemon should be removed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_rsync_removed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Ensure rsyslog is Installed medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_package_rsyslog_installed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:49+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84063-7

References:

BP28(R5), NT28(R46), 1, 14, 15, 16, 3, 5, 6, APO11.04, BAI03.05, DSS05.04, DSS05.07, MEA02.01, CCI-001311, CCI-001312, CCI-000366, 164.312(a)(2)(ii), 4.3.3.3.9, 4.3.3.5.8, 4.3.4.4.7, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 2.10, SR 2.11, SR 2.12, SR 2.8, SR 2.9, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, CM-6(a), PR.PT-1, FTP_ITC_EXT.1.1, SRG-OS-000479-GPOS-00224, SRG-OS-000051-GPOS-00024, SRG-OS-000480-GPOS-00227, 4.2.1.1
Description:
Rsyslog is installed by default. The `rsyslog` package can be installed with the following command:

     $ sudo dnf install rsyslog

Rationale:

The rsyslog package provides the rsyslog daemon, which provides system logging services.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | enable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    if ! rpm -q --quiet "rsyslog" ; then
        dnf install -y "rsyslog"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    - name: Ensure rsyslog is installed
      package:
        name: rsyslog
        state: present
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84063-7
      - NIST-800-53-CM-6(a)
      - enable_strategy
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - package_rsyslog_installed

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    include install_rsyslog

    class install_rsyslog {
      package { 'rsyslog':
        ensure => 'installed',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    package --add=rsyslog

Remediation OSBuild Blueprint snippet

    [[packages]]
    name = "rsyslog"
    version = "*"

OVAL definition:

Definition ID:

oval:ssg-package_rsyslog_installed:def:1

Class:

compliance

Title:

Ensure rsyslog is Installed

Version:

1

Description:

The RPM package rsyslog should be installed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_rsyslog_installed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Uninstall Samba Package unknown pass

Rule ID: | xccdf_org.ssgproject.content_rule_package_samba_removed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

unknown

Identifiers:

CCE-85979-3

References:

2.2.10
Description:
The `samba` package can be removed with the following command:

     $ sudo dnf erase samba

Rationale:

If there is no need to make the Samba software available, removing it provides a safeguard against its activation.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | disable

    # CAUTION: This remediation script will remove samba
    #	   from the system, and may remove any packages
    #	   that depend on samba. Execute this
    #	   remediation AFTER testing on a non-production
    #	   system!

    if rpm -q --quiet "samba" ; then

        dnf remove -y "samba"

    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    - name: Ensure samba is removed
      package:
        name: samba
        state: absent
      tags:
      - CCE-85979-3
      - disable_strategy
      - low_complexity
      - low_disruption
      - no_reboot_needed
      - package_samba_removed
      - unknown_severity

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    include remove_samba

    class remove_samba {
      package { 'samba':
        ensure => 'purged',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    package --remove=samba

OVAL definition:

Definition ID:

oval:ssg-package_samba_removed:def:1

Class:

compliance

Title:

Uninstall Samba Package

Version:

1

Description:

The RPM package samba should be removed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_samba_removed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Uninstall squid Package unknown pass

Rule ID: | xccdf_org.ssgproject.content_rule_package_squid_removed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

unknown

Identifiers:

CCE-84238-5

References:

2.2.11
Description:
The `squid` package can be removed with the following command:

     $ sudo dnf erase squid

Rationale:

If there is no need to make the proxy server software available, removing it provides a safeguard against its activation.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | disable

    # CAUTION: This remediation script will remove squid
    #	   from the system, and may remove any packages
    #	   that depend on squid. Execute this
    #	   remediation AFTER testing on a non-production
    #	   system!

    if rpm -q --quiet "squid" ; then

        dnf remove -y "squid"

    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    - name: Ensure squid is removed
      package:
        name: squid
        state: absent
      tags:
      - CCE-84238-5
      - disable_strategy
      - low_complexity
      - low_disruption
      - no_reboot_needed
      - package_squid_removed
      - unknown_severity

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    include remove_squid

    class remove_squid {
      package { 'squid':
        ensure => 'purged',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    package --remove=squid

OVAL definition:

Definition ID:

oval:ssg-package_squid_removed:def:1

Class:

compliance

Title:

Uninstall squid Package

Version:

1

Description:

The RPM package squid should be removed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_squid_removed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Install sudo Package medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_package_sudo_installed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83523-1

References:

BP28(R19), 1382, 1384, 1386, CM-6(a), FMT_MOF_EXT.1, Req-10.2.1.5, SRG-OS-000324-GPOS-00125, 5.3.1
Description:
The `sudo` package can be installed with the following command:

    $ sudo dnf install sudo

Rationale:

`sudo` is a program designed to allow a system administrator to give limited root privileges to users and log root activity. The basic philosophy is to give as few privileges as possible but still allow system users to get their work done.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | enable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    if ! rpm -q --quiet "sudo" ; then
        dnf install -y "sudo"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    - name: Ensure sudo is installed
      package:
        name: sudo
        state: present
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83523-1
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-10.2.1.5
      - enable_strategy
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - package_sudo_installed

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    include install_sudo

    class install_sudo {
      package { 'sudo':
        ensure => 'installed',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    package --add=sudo

Remediation OSBuild Blueprint snippet

    [[packages]]
    name = "sudo"
    version = "*"

OVAL definition:

Definition ID:

oval:ssg-package_sudo_installed:def:1

Class:

compliance

Title:

Install sudo Package

Version:

1

Description:

The RPM package sudo should be installed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_sudo_installed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Uninstall telnet-server Package high pass

Rule ID: | xccdf_org.ssgproject.content_rule_package_telnet-server_removed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

high

Identifiers:

CCE-84149-4

References:

BP28(R1), 11, 12, 14, 15, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.04, DSS05.02, DSS05.03, DSS05.05, DSS06.06, CCI-000381, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 7.1, SR 7.6, A.11.2.6, A.12.1.2, A.12.5.1, A.12.6.2, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.6.2.1, A.6.2.2, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.AC-3, PR.IP-1, PR.PT-3, PR.PT-4, Req-2.2.4, SRG-OS-000095-GPOS-00049, 2.2.13
Description:
The `telnet-server` package can be removed with the following command:

    $ sudo dnf erase telnet-server

Rationale:

It is detrimental for operating systems to provide, or install by default, functionality exceeding requirements or mission objectives. These unnecessary capabilities are often overlooked and therefore may remain unsecure. They increase the risk to the platform by providing additional attack vectors.
The telnet service provides an unencrypted remote access service which does not provide for the confidentiality and integrity of user passwords or the remote session. If a privileged user were to login using this service, the privileged user password could be compromised.
Removing the `telnet-server` package decreases the risk of the telnet service's accidental (or intentional) activation.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | disable

    # CAUTION: This remediation script will remove telnet-server
    #	   from the system, and may remove any packages
    #	   that depend on telnet-server. Execute this
    #	   remediation AFTER testing on a non-production
    #	   system!

    if rpm -q --quiet "telnet-server" ; then

        dnf remove -y "telnet-server"

    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    - name: Ensure telnet-server is removed
      package:
        name: telnet-server
        state: absent
      tags:
      - CCE-84149-4
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - PCI-DSS-Req-2.2.4
      - disable_strategy
      - high_severity
      - low_complexity
      - low_disruption
      - no_reboot_needed
      - package_telnet-server_removed

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    include remove_telnet-server

    class remove_telnet-server {
      package { 'telnet-server':
        ensure => 'purged',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    package --remove=telnet-server

OVAL definition:

Definition ID:

oval:ssg-package_telnet-server_removed:def:1

Class:

compliance

Title:

Uninstall telnet-server Package

Version:

1

Description:

The RPM package telnet-server should be removed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_telnet-server_removed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Remove telnet Clients low pass

Rule ID: | xccdf_org.ssgproject.content_rule_package_telnet_removed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

low

Identifiers:

CCE-84146-0

References:

BP28(R1), 3.1.13, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), A.8.2.3, A.13.1.1, A.13.2.1, A.13.2.3, A.14.1.2, A.14.1.3, 2.3.1
Description:
The telnet client allows users to start connections to other systems via the telnet protocol.
Rationale:

The `telnet` protocol is insecure and unencrypted. The use of an unencrypted transmission medium could allow an unauthorized user to steal credentials. The `ssh` package provides an encrypted session and stronger security and is included in Red Hat Enterprise Linux 9.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | disable

    # CAUTION: This remediation script will remove telnet
    #	   from the system, and may remove any packages
    #	   that depend on telnet. Execute this
    #	   remediation AFTER testing on a non-production
    #	   system!

    if rpm -q --quiet "telnet" ; then

        dnf remove -y "telnet"

    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    - name: Ensure telnet is removed
      package:
        name: telnet
        state: absent
      tags:
      - CCE-84146-0
      - NIST-800-171-3.1.13
      - disable_strategy
      - low_complexity
      - low_disruption
      - low_severity
      - no_reboot_needed
      - package_telnet_removed

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    include remove_telnet

    class remove_telnet {
      package { 'telnet':
        ensure => 'purged',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    package --remove=telnet

OVAL definition:

Definition ID:

oval:ssg-package_telnet_removed:def:1

Class:

compliance

Title:

Remove telnet Clients

Version:

1

Description:

The RPM package telnet should be removed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_telnet_removed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Uninstall tftp-server Package high pass

Rule ID: | xccdf_org.ssgproject.content_rule_package_tftp-server_removed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

high

Identifiers:

CCE-84154-4

References:

BP28(R1), 11, 12, 14, 15, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.04, DSS05.02, DSS05.03, DSS05.05, DSS06.06, CCI-000318, CCI-000366, CCI-000368, CCI-001812, CCI-001813, CCI-001814, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 7.1, SR 7.6, A.11.2.6, A.12.1.2, A.12.5.1, A.12.6.2, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.6.2.1, A.6.2.2, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.AC-3, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000480-GPOS-00227, 2.2.7
Description:
The `tftp-server` package can be removed with the following command:

     $ sudo dnf erase tftp-server

Rationale:

Removing the `tftp-server` package decreases the risk of the accidental (or intentional) activation of tftp services.
If TFTP is required for operational support (such as transmission of router configurations), its use must be documented with the Information Systems Securty Manager (ISSM), restricted to only authorized personnel, and have access control rules established.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | disable

    # CAUTION: This remediation script will remove tftp-server
    #	   from the system, and may remove any packages
    #	   that depend on tftp-server. Execute this
    #	   remediation AFTER testing on a non-production
    #	   system!

    if rpm -q --quiet "tftp-server" ; then

        dnf remove -y "tftp-server"

    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    - name: Ensure tftp-server is removed
      package:
        name: tftp-server
        state: absent
      tags:
      - CCE-84154-4
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - high_severity
      - low_complexity
      - low_disruption
      - no_reboot_needed
      - package_tftp-server_removed

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    include remove_tftp-server

    class remove_tftp-server {
      package { 'tftp-server':
        ensure => 'purged',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    package --remove=tftp-server

OVAL definition:

Definition ID:

oval:ssg-package_tftp-server_removed:def:1

Class:

compliance

Title:

Uninstall tftp-server Package

Version:

1

Description:

The RPM package tftp-server should be removed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_tftp-server_removed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Remove tftp Daemon low pass

Rule ID: | xccdf_org.ssgproject.content_rule_package_tftp_removed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

low

Identifiers:

CCE-84153-6

References:

BP28(R1), 2.3.3
Description:
Trivial File Transfer Protocol (TFTP) is a simple file transfer protocol, typically used to automatically transfer configuration or boot files between systems. TFTP does not support authentication and can be easily hacked. The package `tftp` is a client program that allows for connections to a `tftp` server.
Rationale:

It is recommended that TFTP be removed, unless there is a specific need for TFTP (such as a boot server). In that case, use extreme caution when configuring the services.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | disable

    # CAUTION: This remediation script will remove tftp
    #	   from the system, and may remove any packages
    #	   that depend on tftp. Execute this
    #	   remediation AFTER testing on a non-production
    #	   system!

    if rpm -q --quiet "tftp" ; then

        dnf remove -y "tftp"

    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    - name: Ensure tftp is removed
      package:
        name: tftp
        state: absent
      tags:
      - CCE-84153-6
      - disable_strategy
      - low_complexity
      - low_disruption
      - low_severity
      - no_reboot_needed
      - package_tftp_removed

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    include remove_tftp

    class remove_tftp {
      package { 'tftp':
        ensure => 'purged',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    package --remove=tftp

OVAL definition:

Definition ID:

oval:ssg-package_tftp_removed:def:1

Class:

compliance

Title:

Remove tftp Daemon

Version:

1

Description:

The RPM package tftp should be removed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_tftp_removed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Uninstall vsftpd Package high pass

Rule ID: | xccdf_org.ssgproject.content_rule_package_vsftpd_removed
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

high

Identifiers:

CCE-84159-3

References:

11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, CCI-000197, CCI-000366, CCI-000381, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), IA-5(1)(c), IA-5(1).1(v), CM-7, CM-7.1(ii), PR.IP-1, PR.PT-3, Req-2.2.4, SRG-OS-000074-GPOS-00042, SRG-OS-000095-GPOS-00049, SRG-OS-000480-GPOS-00227, 2.2.6
Description:
The `vsftpd` package can be removed with the following command:

     $ sudo dnf erase vsftpd

Rationale:

Removing the `vsftpd` package decreases the risk of its accidental activation.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | disable

    # CAUTION: This remediation script will remove vsftpd
    #	   from the system, and may remove any packages
    #	   that depend on vsftpd. Execute this
    #	   remediation AFTER testing on a non-production
    #	   system!

    if rpm -q --quiet "vsftpd" ; then

        dnf remove -y "vsftpd"

    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    - name: Ensure vsftpd is removed
      package:
        name: vsftpd
        state: absent
      tags:
      - CCE-84159-3
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-CM-7.1(ii)
      - NIST-800-53-IA-5(1)(c)
      - NIST-800-53-IA-5(1).1(v)
      - PCI-DSS-Req-2.2.4
      - disable_strategy
      - high_severity
      - low_complexity
      - low_disruption
      - no_reboot_needed
      - package_vsftpd_removed

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    include remove_vsftpd

    class remove_vsftpd {
      package { 'vsftpd':
        ensure => 'purged',
      }
    }

Remediation Anaconda snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    package --remove=vsftpd

OVAL definition:

Definition ID:

oval:ssg-package_vsftpd_removed:def:1

Class:

compliance

Title:

Uninstall vsftpd Package

Version:

1

Description:

The RPM package vsftpd should be removed.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-package_vsftpd_removed:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Ensure /tmp Located On Separate Partition low fail

Rule ID: | xccdf_org.ssgproject.content_rule_partition_for_tmp
Result: | fail
Multi-check rule: | no
Time: | 2023-03-16T13:57:15+01:00
Weight: | 1.0
Severity:

low

Identifiers:

CCE-90845-9

References:

BP28(R12), 12, 15, 8, APO13.01, DSS05.02, CCI-000366, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 7.1, SR 7.6, A.13.1.1, A.13.2.1, A.14.1.3, CM-6(a), SC-5(2), PR.PT-4, SRG-OS-000480-GPOS-00227, 1.1.2.1
Description:
The `/tmp` directory is a world-writable directory used for temporary file storage. Ensure it has its own partition or logical volume at installation time, or migrate it using LVM.
Rationale:

The `/tmp` partition is used as temporary storage by many programs. Placing `/tmp` in its own partition enables the setting of more restrictive mount options, which can help protect programs which use it.

Messages:

Message: Message:

    No suitable fix found.

Remediation Anaconda snippet

Complexity: | low
Disruption: | high
Strategy: | enable

    part /tmp

Remediation OSBuild Blueprint snippet

    [[customizations.filesystem]]
    mountpoint = "/tmp"
    size = 1073741824

OVAL definition:

Definition ID:

oval:ssg-partition_for_tmp:def:1

Class:

compliance

Title:

Ensure /tmp Located On Separate Partition

Version:

1

Description:

If stored locally, create a separate partition for /tmp. If /tmp will be mounted from another system such as an NFS server, then creating a separate partition is not necessary at this time, and the mountpoint can instead be configured later.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-partition_for_tmp:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Disable Postfix Network Listening medium notapplicable

Rule ID: | xccdf_org.ssgproject.content_rule_postfix_network_listening_disabled
Result: | notapplicable
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90825-1

References:

BP28(R48), 11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, CCI-000382, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3, Req-2.2.4, 2.2.15
Description:
Edit the file `/etc/postfix/main.cf` to ensure that only the following `inet_interfaces` line appears:

    inet_interfaces = loopback-only

Rationale:

This ensures `postfix` accepts mail messages (such as cron job reports) from the local system only, and not from the network, which protects it from network attack.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q postfix; }; then

    var_postfix_inet_interfaces='loopback-only'

    if [ -e "/etc/postfix/main.cf" ] ; then

        LC_ALL=C sed -i "/^\s*inet_interfaces\s\+=\s\+/Id" "/etc/postfix/main.cf"
    else
        touch "/etc/postfix/main.cf"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/postfix/main.cf"

    cp "/etc/postfix/main.cf" "/etc/postfix/main.cf.bak"
    # Insert at the end of the file
    printf '%s\n' "inet_interfaces=$var_postfix_inet_interfaces" >> "/etc/postfix/main.cf"
    # Clean up after ourselves.
    rm "/etc/postfix/main.cf.bak"

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: XCCDF Value var_postfix_inet_interfaces # promote to variable
      set_fact:
        var_postfix_inet_interfaces: !!str loopback-only
      tags:
        - always

    - name: Gather list of packages
      package_facts:
        manager: auto
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - ''
      tags:
      - CCE-90825-1
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - PCI-DSS-Req-2.2.4
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - postfix_network_listening_disabled
      - restrict_strategy

    - name: Make changes to Postfix configuration file
      lineinfile:
        path: /etc/postfix/main.cf
        create: false
        regexp: ^inet_interfaces\s*=\s.*
        line: inet_interfaces = {{ var_postfix_inet_interfaces }}
        state: present
        insertafter: ^inet_interfaces\s*=\s.*
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - '"postfix" in ansible_facts.packages'
      - '"postfix" in ansible_facts.packages'
      tags:
      - CCE-90825-1
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - PCI-DSS-Req-2.2.4
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - postfix_network_listening_disabled
      - restrict_strategy

OVAL definition:

Definition ID:

oval:ssg-postfix_network_listening_disabled:def:1

Class:

compliance

Title:

Disable Postfix Network Listening

Version:

2

Description:

Postfix network listening should be disabled

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-postfix_network_listening_disabled:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
CPE platform required by rule:
#package_postfix
Ensure that Root's Path Does Not Include Relative Paths or Null Directories unknown pass

Rule ID: | xccdf_org.ssgproject.content_rule_root_path_no_dot
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:49+01:00
Weight: | 1.0
Severity:

unknown

Identifiers:

CCE-88059-1

References:

11, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, CCI-000366, 4.3.4.3.2, 4.3.4.3.3, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, CM-6(a), CM-6(a), PR.IP-1, 6.2.8
Description:
Ensure that none of the directories in root's path is equal to a single `.` character, or that it contains any instances that lead to relative path traversal, such as `..` or beginning a path without the slash (`/`) character. Also ensure that there are no "empty" elements in the path, such as in these examples:

    PATH=:/bin
    PATH=/bin:
    PATH=/bin::/sbin

These empty elements have the same effect as a single `.` character.
Rationale:

Including these entries increases the risk that root could execute code from an untrusted location.

OVAL definition:

Definition ID:

oval:ssg-root_path_no_dot:def:1

Class:

compliance

Title:

Ensure that Root's Path Does Not Include Relative Paths or Null Directories

Version:

2

Description:

The environment variable PATH should be set correctly for the root user.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-root_path_no_dot:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Ensure System Log Files Have Correct Permissions medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_rsyslog_files_permissions
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:49+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83689-0

References:

BP28(R36), CCI-001314, 0988, 1405, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), Req-10.5.1, Req-10.5.2, 4.2.3
Description:
The file permissions for all log files written by `rsyslog` should be set to 600, or more restrictive. These log files are determined by the second part of each Rule line in `/etc/rsyslog.conf` and typically all appear in `/var/log`. For each log file LOGFILE referenced in `/etc/rsyslog.conf`, run the following command to inspect the file's permissions:

    $ ls -l LOGFILE

If the permissions are not 600 or more restrictive, run the following command to correct this:

    $ sudo chmod 600 LOGFILE

"
Rationale:

Log files can contain valuable information regarding system configuration. If the system log files are not protected unauthorized users could change the logged data, eliminating their forensic value.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # List of log file paths to be inspected for correct permissions
    # * Primarily inspect log file paths listed in /etc/rsyslog.conf
    RSYSLOG_ETC_CONFIG="/etc/rsyslog.conf"
    # * And also the log file paths listed after rsyslog's $IncludeConfig directive
    #   (store the result into array for the case there's shell glob used as value of IncludeConfig)
    readarray -t OLD_INC < <(grep -e "\$IncludeConfig[[:space:]]\+[^[:space:];]\+" /etc/rsyslog.conf | cut -d ' ' -f 2)
    readarray -t RSYSLOG_INCLUDE_CONFIG < <(for INCPATH in "${OLD_INC[@]}"; do eval printf '%s\\n' "${INCPATH}"; done)
    readarray -t NEW_INC < <(awk '/)/{f=0} /include\(/{f=1} f{nf=gensub("^(include\\(|\\s*)file=\"(\\S+)\".*","\\2",1); if($0!=nf){print nf}}' /etc/rsyslog.conf)
    readarray -t RSYSLOG_INCLUDE < <(for INCPATH in "${NEW_INC[@]}"; do eval printf '%s\\n' "${INCPATH}"; done)

    # Declare an array to hold the final list of different log file paths
    declare -a LOG_FILE_PATHS

    # Array to hold all rsyslog config entries
    RSYSLOG_CONFIGS=()
    RSYSLOG_CONFIGS=("${RSYSLOG_ETC_CONFIG}" "${RSYSLOG_INCLUDE_CONFIG[@]}" "${RSYSLOG_INCLUDE[@]}")

    # Get full list of files to be checked
    # RSYSLOG_CONFIGS may contain globs such as
    # /etc/rsyslog.d/*.conf /etc/rsyslog.d/*.frule
    # So, loop over the entries in RSYSLOG_CONFIGS and use find to get the list of included files.
    RSYSLOG_CONFIG_FILES=()
    for ENTRY in "${RSYSLOG_CONFIGS[@]}"
    do
    	# If directory, rsyslog will search for config files in recursively.
    	# However, files in hidden sub-directories or hidden files will be ignored.
    	if [ -d "${ENTRY}" ]
    	then
    		readarray -t FINDOUT < <(find "${ENTRY}" -not -path '*/.*' -type f)
    		RSYSLOG_CONFIG_FILES+=("${FINDOUT[@]}")
    	elif [ -f "${ENTRY}" ]
    	then
    		RSYSLOG_CONFIG_FILES+=("${ENTRY}")
    	else
    		echo "Invalid include object: ${ENTRY}"
    	fi
    done

    # Browse each file selected above as containing paths of log files
    # ('/etc/rsyslog.conf' and '/etc/rsyslog.d/*.conf' in the default configuration)
    for LOG_FILE in "${RSYSLOG_CONFIG_FILES[@]}"
    do
    	# From each of these files extract just particular log file path(s), thus:
    	# * Ignore lines starting with space (' '), comment ('#"), or variable syntax ('$') characters,
    	# * Ignore empty lines,
    	# * Strip quotes and closing brackets from paths.
    	# * Ignore paths that match /dev|/etc.*\.conf, as those are paths, but likely not log files
    	# * From the remaining valid rows select only fields constituting a log file path
    	# Text file column is understood to represent a log file path if and only if all of the
    	# following are met:
    	# * it contains at least one slash '/' character,
    	# * it is preceded by space
    	# * it doesn't contain space (' '), colon (':'), and semicolon (';') characters
    	# Search log file for path(s) only in case it exists!
    	if [[ -f "${LOG_FILE}" ]]
    	then
    		NORMALIZED_CONFIG_FILE_LINES=$(sed -e "/^[#|$]/d" "${LOG_FILE}")
    		LINES_WITH_PATHS=$(grep '[^/]*\s\+\S*/\S\+$' <<< "${NORMALIZED_CONFIG_FILE_LINES}")
    		FILTERED_PATHS=$(awk '{if(NF>=2&&($NF~/^\//||$NF~/^-\//)){sub(/^-\//,"/",$NF);print $NF}}' <<< "${LINES_WITH_PATHS}")
    		CLEANED_PATHS=$(sed -e "s/[\"')]//g; /\\/etc.*\.conf/d; /\\/dev\\//d" <<< "${FILTERED_PATHS}")
    		MATCHED_ITEMS=$(sed -e "/^$/d" <<< "${CLEANED_PATHS}")
    		# Since above sed command might return more than one item (delimited by newline), split
    		# the particular matches entries into new array specific for this log file
    		readarray -t ARRAY_FOR_LOG_FILE <<< "$MATCHED_ITEMS"
    		# Concatenate the two arrays - previous content of $LOG_FILE_PATHS array with
    		# items from newly created array for this log file
    		LOG_FILE_PATHS+=("${ARRAY_FOR_LOG_FILE[@]}")
    		# Delete the temporary array
    		unset ARRAY_FOR_LOG_FILE
    	fi
    done

    # Check for RainerScript action log format which might be also multiline so grep regex is a bit
    # curly:
    # extract possibly multiline action omfile expressions
    # extract File="logfile" expression
    # match only "logfile" expression
    for LOG_FILE in "${RSYSLOG_CONFIG_FILES[@]}"
    do
    	ACTION_OMFILE_LINES=$(grep -ozP "action\s*\(\s*type\s*=\s*\"omfile\"[^\)]*\)" "${LOG_FILE}")
    	OMFILE_LINES=$(echo "${ACTION_OMFILE_LINES}"| grep -aoP "File\s*=\s*\"([/[:alnum:][:punct:]]*)\"\s*\)")
    	LOG_FILE_PATHS+=("$(echo "${OMFILE_LINES}"| grep -oE "\"([/[:alnum:][:punct:]]*)\""|tr -d "\"")")
    done

    # Ensure the correct attribute if file exists
    FILE_CMD="chmod"
    for LOG_FILE_PATH in "${LOG_FILE_PATHS[@]}"
    do
    	# Sanity check - if particular $LOG_FILE_PATH is empty string, skip it from further processing
    	if [ -z "$LOG_FILE_PATH" ]
    	then
    		continue
    	fi
    	$FILE_CMD "0600" "$LOG_FILE_PATH"
    done

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | configure

    - name: Ensure System Log Files Have Correct Permissions - Set rsyslog logfile configuration
        facts
      ansible.builtin.set_fact:
        rsyslog_etc_config: /etc/rsyslog.conf
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83689-0
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-10.5.1
      - PCI-DSS-Req-10.5.2
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - rsyslog_files_permissions

    - name: Ensure System Log Files Have Correct Permissions - Get IncludeConfig directive
      ansible.builtin.shell: |
        set -o pipefail
        grep -e '$IncludeConfig' {{ rsyslog_etc_config }} | cut -d ' ' -f 2 || true
      register: rsyslog_old_inc
      changed_when: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83689-0
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-10.5.1
      - PCI-DSS-Req-10.5.2
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - rsyslog_files_permissions

    - name: Ensure System Log Files Have Correct Permissions - Get include files directives
      ansible.builtin.shell: |
        set -o pipefail
        awk '/)/{f=0} /include\(/{f=1} f{nf=gensub("^(include\\(|\\s*)file=\"(\\S+)\".*","\\2",1); if($0!=nf){print nf}}' {{ rsyslog_etc_config }} || true
      register: rsyslog_new_inc
      changed_when: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83689-0
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-10.5.1
      - PCI-DSS-Req-10.5.2
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - rsyslog_files_permissions

    - name: Ensure System Log Files Have Correct Permissions - Aggregate rsyslog includes
      ansible.builtin.set_fact:
        include_config_output: '{{ rsyslog_old_inc.stdout_lines + rsyslog_new_inc.stdout_lines
          }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83689-0
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-10.5.1
      - PCI-DSS-Req-10.5.2
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - rsyslog_files_permissions

    - name: Ensure System Log Files Have Correct Permissions - List all config files
      ansible.builtin.find:
        paths: '{{ include_config_output | list | map(''dirname'') }}'
        patterns: '{{ include_config_output | list | map(''basename'') }}'
        hidden: false
        follow: true
      register: rsyslog_config_files
      failed_when: false
      changed_when: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83689-0
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-10.5.1
      - PCI-DSS-Req-10.5.2
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - rsyslog_files_permissions

    - name: Ensure System Log Files Have Correct Permissions - Extract log files old format
      ansible.builtin.shell: |
        set -o pipefail
        grep -oP '^[^(\s|#|\$)]+[\s]+.*[\s]+-?(/+[^:;\s]+);*\.*$' {{ item }}  |awk '{print $NF}'|sed -e 's/^-//' || true
      loop: '{{ rsyslog_config_files.files|map(attribute=''path'')|list|flatten|unique
        + [ rsyslog_etc_config ] }}'
      register: log_files_old
      changed_when: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83689-0
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-10.5.1
      - PCI-DSS-Req-10.5.2
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - rsyslog_files_permissions

    - name: Ensure System Log Files Have Correct Permissions - Extract log files new format
      ansible.builtin.shell: |
        set -o pipefail
        grep -ozP "action\s*\(\s*type\s*=\s*\"omfile\"[^\)]*\)" {{ item }} | grep -aoP "File\s*=\s*\"([/[:alnum:][:punct:]]*)\"\s*\)"|grep -oE "\"([/[:alnum:][:punct:]]*)\"" |tr -d "\""|| true
      loop: '{{ rsyslog_config_files.files|map(attribute=''path'')|list|flatten|unique
        + [ rsyslog_etc_config ] }}'
      register: log_files_new
      changed_when: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83689-0
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-10.5.1
      - PCI-DSS-Req-10.5.2
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - rsyslog_files_permissions

    - name: Ensure System Log Files Have Correct Permissions - Sum all log files found
      ansible.builtin.set_fact:
        log_files: '{{ log_files_new.results|map(attribute=''stdout_lines'')|list|flatten|unique
          + log_files_old.results|map(attribute=''stdout_lines'')|list|flatten|unique  }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83689-0
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-10.5.1
      - PCI-DSS-Req-10.5.2
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - rsyslog_files_permissions

    - name: Ensure System Log Files Have Correct Permissions -Setup log files attribute
      ansible.builtin.file:
        path: '{{ item }}'
        mode: 384
        state: file
      loop: '{{ log_files | list | flatten | unique }}'
      failed_when: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83689-0
      - NIST-800-53-AC-6(1)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-10.5.1
      - PCI-DSS-Req-10.5.2
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - rsyslog_files_permissions

OVAL definition:

Definition ID:

oval:ssg-rsyslog_files_permissions:def:1

Class:

compliance

Title:

Ensure System Log Files Have Correct Permissions

Version:

1

Description:

All syslog log files should have appropriate ownership.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-rsyslog_files_permissions:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_rsyslog_nolisten
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:49+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83995-1

References:

1, 11, 12, 13, 14, 15, 16, 18, 3, 4, 5, 6, 8, 9, APO01.06, APO11.04, APO13.01, BAI03.05, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.05, DSS03.01, DSS05.02, DSS05.04, DSS05.07, DSS06.02, MEA02.01, CCI-000318, CCI-000366, CCI-000368, CCI-001812, CCI-001813, CCI-001814, 4.2.3.4, 4.3.3.3.9, 4.3.3.4, 4.3.3.5.8, 4.3.4.3.2, 4.3.4.3.3, 4.3.4.4.7, 4.4.2.1, 4.4.2.2, 4.4.2.4, 4.4.3.3, SR 2.10, SR 2.11, SR 2.12, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 7.1, SR 7.6, 0988, 1405, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.5.1, A.12.6.2, A.12.7.1, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-7(a), CM-7(b), CM-6(a), DE.AE-1, ID.AM-3, PR.AC-5, PR.DS-5, PR.IP-1, PR.PT-1, PR.PT-4, SRG-OS-000480-GPOS-00227, 4.2.1.7
Description:
The `rsyslog` daemon should not accept remote messages unless the system acts as a log server. To ensure that it is not listening on the network, ensure the following lines are not found in `/etc/rsyslog.conf`:

    $ModLoad imtcp
    $InputTCPServerRun port
    $ModLoad imudp
    $UDPServerRun port
    $ModLoad imrelp
    $InputRELPServerRun port

Rationale:

Any process which receives messages from the network incurs some risk of receiving malicious messages. This risk can be eliminated for rsyslog by configuring it not to listen on the network.

OVAL definition:

Definition ID:

oval:ssg-rsyslog_nolisten:def:1

Class:

compliance

Title:

Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server

Version:

2

Description:

rsyslogd should reject remote messages

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-rsyslog_nolisten:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Ensure No Daemons are Unconfined by SELinux medium fail

Rule ID: | xccdf_org.ssgproject.content_rule_selinux_confinement_of_daemons
Result: | fail
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84075-1

References:

1, 11, 12, 13, 14, 15, 16, 18, 3, 5, 6, 9, APO01.06, APO11.04, BAI03.05, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.06, MEA02.01, 3.1.2, 3.1.5, 3.7.2, 164.308(a)(1)(ii)(D), 164.308(a)(3), 164.308(a)(4), 164.310(b), 164.310(c), 164.312(a), 164.312(e), 4.3.3.3.9, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, 4.3.4.4.7, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.10, SR 2.11, SR 2.12, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 2.8, SR 2.9, SR 5.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.2, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.5.1, A.12.6.2, A.12.7.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-3(3)(a), AC-6, PR.AC-4, PR.DS-5, PR.IP-1, PR.PT-1, PR.PT-3, 1.6.1.6
Description:
Daemons for which the SELinux policy does not contain rules will inherit the context of the parent process. Because daemons are launched during startup and descend from the `init` process, they inherit the `unconfined_service_t` context.
To check for unconfined daemons, run the following command:

    $ sudo ps -eZ | grep "unconfined_service_t"

It should produce no output in a well-configured system.
Rationale:

Daemons which run with the `unconfined_service_t` context may cause AVC denials, or allow privileges that the daemon does not require.

Warnings:

General warning
Automatic remediation of this control is not available. Remediation can be achieved by amending SELinux policy or stopping the unconfined daemons as outlined above.

Messages:

Message: Message:

    No suitable fix found.

OVAL definition:

Definition ID:

oval:ssg-selinux_confinement_of_daemons:def:1

Class:

compliance

Title:

Ensure No Daemons are Unconfined by SELinux

Version:

1

Description:

All pids in /proc should be assigned an SELinux security context other than 'unconfined_service_t'.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-selinux_confinement_of_daemons:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Configure SELinux Policy medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_selinux_policytype
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84074-4

References:

BP28(R66), 1, 11, 12, 13, 14, 15, 16, 18, 3, 4, 5, 6, 8, 9, APO01.06, APO11.04, APO13.01, BAI03.05, DSS01.05, DSS03.01, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.03, DSS06.06, MEA02.01, 3.1.2, 3.7.2, CCI-002165, CCI-002696, 164.308(a)(1)(ii)(D), 164.308(a)(3), 164.308(a)(4), 164.310(b), 164.310(c), 164.312(a), 164.312(e), 4.2.3.4, 4.3.3.2.2, 4.3.3.3.9, 4.3.3.4, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.4.7, 4.4.2.1, 4.4.2.2, 4.4.2.4, 4.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.10, SR 2.11, SR 2.12, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 7.1, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.1, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.2, CIP-003-8 R5.3, CIP-004-6 R2.2.3, CIP-004-6 R2.3, CIP-004-6 R3.3, CIP-007-3 R5.1, CIP-007-3 R5.1.2, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, CIP-007-3 R6.5, AC-3, AC-3(3)(a), AU-9, SC-7(21), DE.AE-1, ID.AM-3, PR.AC-4, PR.AC-5, PR.AC-6, PR.DS-5, PR.PT-1, PR.PT-3, PR.PT-4, SRG-OS-000445-GPOS-00199, SRG-OS-000445-VMM-001780, 1.6.1.3
Description:
The SELinux `targeted` policy is appropriate for general-purpose desktops and servers, as well as systems in many other roles. To configure the system to use this policy, add or correct the following line in `/etc/selinux/config`:

    SELINUXTYPE=targeted

Other policies, such as `mls`, provide additional security labeling and greater confinement but are not compatible with many general-purpose use cases.
Rationale:

Setting the SELinux policy to `targeted` or a more specialized policy ensures the system will confine processes that are likely to be targeted for exploitation, such as network or system services.
Note: During the development or debugging of SELinux modules, it is common to temporarily place non-production systems in `permissive` mode. In such temporary cases, SELinux policies should be developed, and once work is completed, the system should be reconfigured to `targeted`.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    var_selinux_policy_name='targeted'

    if [ -e "/etc/selinux/config" ] ; then

        LC_ALL=C sed -i "/^SELINUXTYPE=/Id" "/etc/selinux/config"
    else
        touch "/etc/selinux/config"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/selinux/config"

    cp "/etc/selinux/config" "/etc/selinux/config.bak"
    # Insert at the end of the file
    printf '%s\n' "SELINUXTYPE=$var_selinux_policy_name" >> "/etc/selinux/config"
    # Clean up after ourselves.
    rm "/etc/selinux/config.bak"

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: XCCDF Value var_selinux_policy_name # promote to variable
      set_fact:
        var_selinux_policy_name: !!str targeted
      tags:
        - always

    - name: Configure SELinux Policy
      block:

      - name: Check for duplicate values
        lineinfile:
          path: /etc/selinux/config
          create: false
          regexp: ^SELINUXTYPE=
          state: absent
        check_mode: true
        changed_when: false
        register: dupes

      - name: Deduplicate values from /etc/selinux/config
        lineinfile:
          path: /etc/selinux/config
          create: false
          regexp: ^SELINUXTYPE=
          state: absent
        when: dupes.found is defined and dupes.found > 1

      - name: Insert correct line to /etc/selinux/config
        lineinfile:
          path: /etc/selinux/config
          create: true
          regexp: ^SELINUXTYPE=
          line: SELINUXTYPE={{ var_selinux_policy_name }}
          state: present
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84074-4
      - NIST-800-171-3.1.2
      - NIST-800-171-3.7.2
      - NIST-800-53-AC-3
      - NIST-800-53-AC-3(3)(a)
      - NIST-800-53-AU-9
      - NIST-800-53-SC-7(21)
      - low_complexity
      - low_disruption
      - medium_severity
      - reboot_required
      - restrict_strategy
      - selinux_policytype

OVAL definition:

Definition ID:

oval:ssg-selinux_policytype:def:1

Class:

compliance

Title:

Configure SELinux Policy

Version:

1

Description:

The SELinux policy should be set appropriately.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-selinux_policytype:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Enable cron Service medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_service_crond_enabled
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84163-5

References:

11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-6(a), PR.IP-1, PR.PT-3, 5.1.1
Description:
The `crond` service is used to execute commands at preconfigured times. It is required by almost all systems to perform necessary maintenance tasks, such as notifying root of system activity. The `crond` service can be enabled with the following command:

    $ sudo systemctl enable crond.service

Rationale:

Due to its usage for maintenance and security-supporting tasks, enabling the cron daemon is essential.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | enable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    SYSTEMCTL_EXEC='/usr/bin/systemctl'
    "$SYSTEMCTL_EXEC" unmask 'crond.service'
    "$SYSTEMCTL_EXEC" start 'crond.service'
    "$SYSTEMCTL_EXEC" enable 'crond.service'

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    - name: Enable service crond
      block:

      - name: Gather the package facts
        package_facts:
          manager: auto

      - name: Enable service crond
        service:
          name: crond
          enabled: 'yes'
          state: started
          masked: 'no'
        when:
        - '"cronie" in ansible_facts.packages'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84163-5
      - NIST-800-53-CM-6(a)
      - enable_strategy
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - service_crond_enabled

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    include enable_crond

    class enable_crond {
      service {'crond':
        enable => true,
        ensure => 'running',
      }
    }

Remediation OSBuild Blueprint snippet

    [customizations.services]
    enabled = ["crond"]

OVAL definition:

Definition ID:

oval:ssg-service_crond_enabled:def:1

Class:

compliance

Title:

Enable cron Service

Version:

1

Description:

The crond service should be enabled if possible.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-service_crond_enabled:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Verify firewalld Enabled medium fixed

Rule ID: | xccdf_org.ssgproject.content_rule_service_firewalld_enabled
Result: | fixed
Multi-check rule: | no
Time: | 2023-03-16T13:57:21+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90833-5

References:

11, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, 3.1.3, 3.4.7, CCI-000366, CCI-000382, CCI-002314, 4.3.4.3.2, 4.3.4.3.3, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, CIP-003-8 R4, CIP-003-8 R5, CIP-004-6 R3, AC-4, CM-7(b), CA-3(5), SC-7(21), CM-6(a), PR.IP-1, FMT_SMF_EXT.1, SRG-OS-000096-GPOS-00050, SRG-OS-000297-GPOS-00115, SRG-OS-000480-GPOS-00227, SRG-OS-000480-GPOS-00231, SRG-OS-000480-GPOS-00232, 3.4.1.2
Description:
The `firewalld` service can be enabled with the following command:

    $ sudo systemctl enable firewalld.service

Rationale:

Access control methods provide the ability to enhance system security posture by restricting services and known good IP addresses and address ranges. This prevents connections from unknown hosts and protocols.

Messages:

Message: Message:

    Fix execution completed and returned: 0

Message: Message:

    Created symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service → /usr/lib/systemd/system/firewalld.service.
    Created symlink /etc/systemd/system/multi-user.target.wants/firewalld.service → /usr/lib/systemd/system/firewalld.service.

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | enable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    SYSTEMCTL_EXEC='/usr/bin/systemctl'
    "$SYSTEMCTL_EXEC" unmask 'firewalld.service'
    "$SYSTEMCTL_EXEC" start 'firewalld.service'
    "$SYSTEMCTL_EXEC" enable 'firewalld.service'

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    - name: Enable service firewalld
      block:

      - name: Gather the package facts
        package_facts:
          manager: auto

      - name: Enable service firewalld
        service:
          name: firewalld
          enabled: 'yes'
          state: started
          masked: 'no'
        when:
        - '"firewalld" in ansible_facts.packages'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90833-5
      - NIST-800-171-3.1.3
      - NIST-800-171-3.4.7
      - NIST-800-53-AC-4
      - NIST-800-53-CA-3(5)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-7(21)
      - enable_strategy
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - service_firewalld_enabled

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    include enable_firewalld

    class enable_firewalld {
      service {'firewalld':
        enable => true,
        ensure => 'running',
      }
    }

Remediation OSBuild Blueprint snippet

    [customizations.services]
    enabled = ["firewalld"]

OVAL definition:

Definition ID:

oval:ssg-service_firewalld_enabled:def:1

Class:

compliance

Title:

Verify firewalld Enabled

Version:

1

Description:

The firewalld service should be enabled if possible.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-service_firewalld_enabled:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Disable Network File System (nfs) unknown pass

Rule ID: | xccdf_org.ssgproject.content_rule_service_nfs_disabled
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

unknown

Identifiers:

CCE-90850-9

References:

11, 12, 14, 15, 16, 18, 3, 5, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.03, DSS06.06, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, A.6.1.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-7(a), CM-7(b), CM-6(a), PR.AC-4, PR.AC-6, PR.PT-3, 2.2.16
Description:
The Network File System (NFS) service allows remote hosts to mount and interact with shared filesystems on the local system. If the local system is not designated as a NFS server then this service should be disabled. The `nfs-server` service can be disabled with the following command:

    $ sudo systemctl mask --now nfs-server.service

Rationale:

Unnecessary services should be disabled to decrease the attack surface of the system.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    SYSTEMCTL_EXEC='/usr/bin/systemctl'
    "$SYSTEMCTL_EXEC" stop 'nfs-server.service'
    "$SYSTEMCTL_EXEC" disable 'nfs-server.service'
    "$SYSTEMCTL_EXEC" mask 'nfs-server.service'
    # Disable socket activation if we have a unit file for it
    if "$SYSTEMCTL_EXEC" -q list-unit-files nfs-server.socket; then
        "$SYSTEMCTL_EXEC" stop 'nfs-server.socket'
        "$SYSTEMCTL_EXEC" mask 'nfs-server.socket'
    fi
    # The service may not be running because it has been started and failed,
    # so let's reset the state so OVAL checks pass.
    # Service should be 'inactive', not 'failed' after reboot though.
    "$SYSTEMCTL_EXEC" reset-failed 'nfs-server.service' || true

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    - name: Disable service nfs-server
      block:

      - name: Disable service nfs-server
        systemd:
          name: nfs-server.service
          enabled: 'no'
          state: stopped
          masked: 'yes'
        ignore_errors: 'yes'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90850-9
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - low_disruption
      - no_reboot_needed
      - service_nfs_disabled
      - unknown_severity

    - name: Unit Socket Exists - nfs-server.socket
      command: systemctl list-unit-files nfs-server.socket
      register: socket_file_exists
      changed_when: false
      ignore_errors: true
      check_mode: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90850-9
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - low_disruption
      - no_reboot_needed
      - service_nfs_disabled
      - unknown_severity

    - name: Disable socket nfs-server
      systemd:
        name: nfs-server.socket
        enabled: 'no'
        state: stopped
        masked: 'yes'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - '"nfs-server.socket" in socket_file_exists.stdout_lines[1]'
      tags:
      - CCE-90850-9
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - low_disruption
      - no_reboot_needed
      - service_nfs_disabled
      - unknown_severity

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    include disable_nfs-server

    class disable_nfs-server {
      service {'nfs-server':
        enable => false,
        ensure => 'stopped',
      }
    }

Remediation Kubernetes snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        systemd:
          units:
          - name: nfs-server.service
            enabled: false
            mask: true
          - name: nfs-server.socket
            enabled: false
            mask: true

Remediation OSBuild Blueprint snippet

    [customizations.services]
    disabled = ["nfs-server"]

OVAL definition:

Definition ID:

oval:ssg-service_nfs_disabled:def:1

Class:

compliance

Title:

Disable Network File System (nfs)

Version:

1

Description:

The nfs-server service should be disabled if possible.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-service_nfs_disabled:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Disable rpcbind Service low pass

Rule ID: | xccdf_org.ssgproject.content_rule_service_rpcbind_disabled
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

low

Identifiers:

CCE-84245-0

References:

2.2.17
Description:
The rpcbind utility maps RPC services to the ports on which they listen. RPC processes notify rpcbind when they start, registering the ports they are listening on and the RPC program numbers they expect to serve. The rpcbind service redirects the client to the proper port number so it can communicate with the requested service. If the system does not require RPC (such as for NFS servers) then this service should be disabled. The `rpcbind` service can be disabled with the following command:

    $ sudo systemctl mask --now rpcbind.service

Rationale:

If the system does not require rpc based services, it is recommended that rpcbind be disabled to reduce the attack surface.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    SYSTEMCTL_EXEC='/usr/bin/systemctl'
    "$SYSTEMCTL_EXEC" stop 'rpcbind.service'
    "$SYSTEMCTL_EXEC" disable 'rpcbind.service'
    "$SYSTEMCTL_EXEC" mask 'rpcbind.service'
    # Disable socket activation if we have a unit file for it
    if "$SYSTEMCTL_EXEC" -q list-unit-files rpcbind.socket; then
        "$SYSTEMCTL_EXEC" stop 'rpcbind.socket'
        "$SYSTEMCTL_EXEC" mask 'rpcbind.socket'
    fi
    # The service may not be running because it has been started and failed,
    # so let's reset the state so OVAL checks pass.
    # Service should be 'inactive', not 'failed' after reboot though.
    "$SYSTEMCTL_EXEC" reset-failed 'rpcbind.service' || true

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | disable

    - name: Disable service rpcbind
      block:

      - name: Disable service rpcbind
        systemd:
          name: rpcbind.service
          enabled: 'no'
          state: stopped
          masked: 'yes'
        ignore_errors: 'yes'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84245-0
      - disable_strategy
      - low_complexity
      - low_disruption
      - low_severity
      - no_reboot_needed
      - service_rpcbind_disabled

    - name: Unit Socket Exists - rpcbind.socket
      command: systemctl list-unit-files rpcbind.socket
      register: socket_file_exists
      changed_when: false
      ignore_errors: true
      check_mode: false
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84245-0
      - disable_strategy
      - low_complexity
      - low_disruption
      - low_severity
      - no_reboot_needed
      - service_rpcbind_disabled

    - name: Disable socket rpcbind
      systemd:
        name: rpcbind.socket
        enabled: 'no'
        state: stopped
        masked: 'yes'
      when:
      - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      - '"rpcbind.socket" in socket_file_exists.stdout_lines[1]'
      tags:
      - CCE-84245-0
      - disable_strategy
      - low_complexity
      - low_disruption
      - low_severity
      - no_reboot_needed
      - service_rpcbind_disabled

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    include disable_rpcbind

    class disable_rpcbind {
      service {'rpcbind':
        enable => false,
        ensure => 'stopped',
      }
    }

Remediation Kubernetes snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        systemd:
          units:
          - name: rpcbind.service
            enabled: false
            mask: true
          - name: rpcbind.socket
            enabled: false
            mask: true

Remediation OSBuild Blueprint snippet

    [customizations.services]
    disabled = ["rpcbind"]

OVAL definition:

Definition ID:

oval:ssg-service_rpcbind_disabled:def:1

Class:

compliance

Title:

Disable rpcbind Service

Version:

1

Description:

The rpcbind service should be disabled if possible.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-service_rpcbind_disabled:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Enable rsyslog Service medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_service_rsyslog_enabled
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:49+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83989-4

References:

BP28(R5), NT28(R46), 1, 12, 13, 14, 15, 16, 2, 3, 5, 6, 7, 8, 9, APO10.01, APO10.03, APO10.04, APO10.05, APO11.04, APO13.01, BAI03.05, BAI04.04, DSS01.03, DSS03.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, MEA01.01, MEA01.02, MEA01.03, MEA01.04, MEA01.05, MEA02.01, CCI-001311, CCI-001312, CCI-001557, CCI-001851, CCI-000366, 164.312(a)(2)(ii), 4.3.2.6.7, 4.3.3.3.9, 4.3.3.5.8, 4.3.4.4.7, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 2.10, SR 2.11, SR 2.12, SR 2.8, SR 2.9, SR 6.1, SR 6.2, SR 7.1, SR 7.2, A.12.1.3, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.14.2.7, A.15.2.1, A.15.2.2, A.17.2.1, CM-6(a), AU-4(1), DE.CM-1, DE.CM-3, DE.CM-7, ID.SC-4, PR.DS-4, PR.PT-1, SRG-OS-000480-GPOS-00227, 4.2.1.2
Description:
The `rsyslog` service provides syslog-style logging by default on Red Hat Enterprise Linux 9. The `rsyslog` service can be enabled with the following command:

    $ sudo systemctl enable rsyslog.service

Rationale:

The `rsyslog` service must be running in order to provide logging services, which are essential to system administration.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | enable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    SYSTEMCTL_EXEC='/usr/bin/systemctl'
    "$SYSTEMCTL_EXEC" unmask 'rsyslog.service'
    "$SYSTEMCTL_EXEC" start 'rsyslog.service'
    "$SYSTEMCTL_EXEC" enable 'rsyslog.service'

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    - name: Enable service rsyslog
      block:

      - name: Gather the package facts
        package_facts:
          manager: auto

      - name: Enable service rsyslog
        service:
          name: rsyslog
          enabled: 'yes'
          state: started
          masked: 'no'
        when:
        - '"rsyslog" in ansible_facts.packages'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83989-4
      - NIST-800-53-AU-4(1)
      - NIST-800-53-CM-6(a)
      - enable_strategy
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - service_rsyslog_enabled

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    include enable_rsyslog

    class enable_rsyslog {
      service {'rsyslog':
        enable => true,
        ensure => 'running',
      }
    }

Remediation OSBuild Blueprint snippet

    [customizations.services]
    enabled = ["rsyslog"]

OVAL definition:

Definition ID:

oval:ssg-service_rsyslog_enabled:def:1

Class:

compliance

Title:

Enable rsyslog Service

Version:

1

Description:

The rsyslog service should be enabled if possible.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-service_rsyslog_enabled:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Enable systemd-journald Service medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_service_systemd-journald_enabled
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:49+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-85941-3

References:

CCI-001665, SC-24, SRG-OS-000269-GPOS-00103, 4.2.2.2
Description:
The `systemd-journald` service is an essential component of systemd. The `systemd-journald` service can be enabled with the following command:

    $ sudo systemctl enable systemd-journald.service

Rationale:

In the event of a system failure, Red Hat Enterprise Linux 9 must preserve any information necessary to determine cause of failure and any information necessary to return to operations with least disruption to system processes.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | enable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    SYSTEMCTL_EXEC='/usr/bin/systemctl'
    "$SYSTEMCTL_EXEC" unmask 'systemd-journald.service'
    "$SYSTEMCTL_EXEC" start 'systemd-journald.service'
    "$SYSTEMCTL_EXEC" enable 'systemd-journald.service'

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    - name: Enable service systemd-journald
      block:

      - name: Gather the package facts
        package_facts:
          manager: auto

      - name: Enable service systemd-journald
        service:
          name: systemd-journald
          enabled: 'yes'
          state: started
          masked: 'no'
        when:
        - '"systemd" in ansible_facts.packages'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-85941-3
      - NIST-800-53-SC-24
      - enable_strategy
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - service_systemd-journald_enabled

Remediation Puppet snippet

Complexity: | low
Disruption: | low
Strategy: | enable

    include enable_systemd-journald

    class enable_systemd-journald {
      service {'systemd-journald':
        enable => true,
        ensure => 'running',
      }
    }

Remediation OSBuild Blueprint snippet

    [customizations.services]
    enabled = ["systemd-journald"]

OVAL definition:

Definition ID:

oval:ssg-service_systemd-journald_enabled:def:1

Class:

compliance

Title:

Enable systemd-journald Service

Version:

1

Description:

The systemd-journald service should be enabled if possible.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-service_systemd-journald_enabled:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Set Default firewalld Zone for Incoming Packets medium fail

Rule ID: | xccdf_org.ssgproject.content_rule_set_firewalld_default_zone
Result: | fail
Multi-check rule: | no
Time: | 2023-03-16T13:57:21+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84023-1

References:

11, 14, 3, 9, 5.10.1, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 3.1.3, 3.4.7, 3.13.6, CCI-000366, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, 1416, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CA-3(5), CM-7(b), SC-7(23), CM-6(a), PR.IP-1, PR.PT-3, FMT_MOF_EXT.1, Req-1.4, SRG-OS-000480-GPOS-00227, SRG-OS-000480-VMM-002000, 3.4.2.1
Description:
To set the default zone to `drop` for the built-in default zone which processes incoming IPv4 and IPv6 packets, modify the following line in `/etc/firewalld/firewalld.conf` to be:

    DefaultZone=drop

Rationale:

In `firewalld` the default zone is applied only after all the applicable rules in the table are examined for a match. Setting the default zone to `drop` implements proper design for a firewall, i.e. any packets which are not explicitly permitted should not be accepted.

Warnings:

General warning
To prevent denying any access to the system, automatic remediation of this control is not available. Remediation must be automated as a component of machine provisioning, or followed manually as outlined above.

Messages:

Message: Message:

    No suitable fix found.

OVAL definition:

Definition ID:

oval:ssg-set_firewalld_default_zone:def:1

Class:

compliance

Title:

Set Default firewalld Zone for Incoming Packets

Version:

2

Description:

Change the default firewalld zone to drop.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-set_firewalld_default_zone:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Set PAM''s Password Hashing Algorithm - password-auth medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_set_password_hashing_algorithm_passwordauth
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-85946-2

References:

BP28(R32), 1, 12, 15, 16, 5, 5.6.2.2, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 3.13.11, CCI-000196, CCI-000803, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.2, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, 0418, 1055, 1402, A.18.1.4, A.7.1.1, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.2, A.9.4.3, IA-5(c), IA-5(1)(c), CM-6(a), PR.AC-1, PR.AC-6, PR.AC-7, Req-8.2.1, SRG-OS-000073-GPOS-00041, SRG-OS-000120-GPOS-00061, SRG-OS-000480-VMM-002000, 5.5.4
Description:
The PAM system service can be configured to only store encrypted representations of passwords. In `/etc/pam.d/password-auth`, the `password` section of the file controls which PAM modules execute during a password change. Set the `pam_unix.so` module in the `password` section to include the argument `sha512`, as shown below:

    password    sufficient    pam_unix.so sha512 other arguments...

This will help ensure when local users change their passwords, hashes for the new passwords will be generated using the SHA-512 algorithm. This is the default.
Rationale:

Passwords need to be protected at all times, and encryption is the standard method for protecting passwords. If passwords are not encrypted, they can be plainly read (i.e., clear text) and easily compromised. Passwords that are encrypted with a weak algorithm are no more protected than if they are kepy in plain text.
This setting ensures user and group account administration utilities are configured to store only encrypted representations of passwords. Additionally, the `crypt_style` configuration option ensures the use of a strong hashing algorithm that makes password cracking attacks more difficult.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q pam; then

    if [ -e "/etc/pam.d/password-auth" ] ; then
        PAM_FILE_PATH="/etc/pam.d/password-auth"
        if [ -f /usr/bin/authselect ]; then

            if ! authselect check; then
            echo "
            authselect integrity check failed. Remediation aborted!
            This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
            It is not recommended to manually edit the PAM files when authselect tool is available.
            In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
            exit 1
            fi

            CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
            # If not already in use, a custom profile is created preserving the enabled features.
            if [[ ! $CURRENT_PROFILE == custom/* ]]; then
                ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
                authselect create-profile hardening -b $CURRENT_PROFILE
                CURRENT_PROFILE="custom/hardening"

                authselect apply-changes -b --backup=before-hardening-custom-profile
                authselect select $CURRENT_PROFILE
                for feature in $ENABLED_FEATURES; do
                    authselect enable-feature $feature;
                done

                authselect apply-changes -b --backup=after-hardening-custom-profile
            fi
            PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth")
            PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"

            authselect apply-changes -b
        fi
        if ! grep -qP '^\s*password\s+'"sufficient"'\s+pam_unix.so\s*.*' "$PAM_FILE_PATH"; then
                # Line matching group + control + module was not found. Check group + module.
                if [ "$(grep -cP '^\s*password\s+.*\s+pam_unix.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then
                    # The control is updated only if one single line matches.
                    sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_unix.so.*)/\1'"sufficient"' \2/' "$PAM_FILE_PATH"
                else
                    echo 'password    '"sufficient"'    pam_unix.so' >> "$PAM_FILE_PATH"
                fi
            fi
            # Check the option
            if ! grep -qP '^\s*password\s+'"sufficient"'\s+pam_unix.so\s*.*\ssha512\b' "$PAM_FILE_PATH"; then
                sed -i -E --follow-symlinks '/\s*password\s+'"sufficient"'\s+pam_unix.so.*/ s/$/ sha512/' "$PAM_FILE_PATH"
            fi
        if [ -f /usr/bin/authselect ]; then

            authselect apply-changes -b
        fi
    else
        echo "/etc/pam.d/password-auth was not found" >&2
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | configure

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-85946-2
      - CJIS-5.6.2.2
      - NIST-800-171-3.13.11
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(1)(c)
      - NIST-800-53-IA-5(c)
      - PCI-DSS-Req-8.2.1
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - set_password_hashing_algorithm_passwordauth

    - name: Set PAM's Password Hashing Algorithm - password-auth - Check if /etc/pam.d/password-auth
        file is present
      ansible.builtin.stat:
        path: /etc/pam.d/password-auth
      register: result_pam_file_present
      when: '"pam" in ansible_facts.packages'
      tags:
      - CCE-85946-2
      - CJIS-5.6.2.2
      - NIST-800-171-3.13.11
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(1)(c)
      - NIST-800-53-IA-5(c)
      - PCI-DSS-Req-8.2.1
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - set_password_hashing_algorithm_passwordauth

    - name: Set PAM's Password Hashing Algorithm - password-auth - Check the proper remediation
        for the system
      block:

      - name: Set PAM's Password Hashing Algorithm - password-auth - Define the PAM file
          to be edited as a local fact
        ansible.builtin.set_fact:
          pam_file_path: /etc/pam.d/password-auth

      - name: Set PAM's Password Hashing Algorithm - password-auth - Check if system relies
          on authselect tool
        ansible.builtin.stat:
          path: /usr/bin/authselect
        register: result_authselect_present

      - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure authselect
          custom profile is used if authselect is present
        block:

        - name: Set PAM's Password Hashing Algorithm - password-auth - Check integrity
            of authselect current profile
          ansible.builtin.command:
            cmd: authselect check
          register: result_authselect_check_cmd
          changed_when: false
          ignore_errors: true

        - name: Set PAM's Password Hashing Algorithm - password-auth - Informative message
            based on the authselect integrity check result
          ansible.builtin.assert:
            that:
            - result_authselect_check_cmd is success
            fail_msg:
            - authselect integrity check failed. Remediation aborted!
            - This remediation could not be applied because an authselect profile was
              not selected or the selected profile is not intact.
            - It is not recommended to manually edit the PAM files when authselect tool
              is available.
            - In cases where the default authselect profile does not cover a specific
              demand, a custom authselect profile is recommended.
            success_msg:
            - authselect integrity check passed

        - name: Set PAM's Password Hashing Algorithm - password-auth - Get authselect
            current profile
          ansible.builtin.shell:
            cmd: authselect current -r | awk '{ print $1 }'
          register: result_authselect_profile
          changed_when: false
          when:
          - result_authselect_check_cmd is success

        - name: Set PAM's Password Hashing Algorithm - password-auth - Define the current
            authselect profile as a local fact
          ansible.builtin.set_fact:
            authselect_current_profile: '{{ result_authselect_profile.stdout }}'
            authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
          when:
          - result_authselect_profile is not skipped
          - result_authselect_profile.stdout is match("custom/")

        - name: Set PAM's Password Hashing Algorithm - password-auth - Define the new
            authselect custom profile as a local fact
          ansible.builtin.set_fact:
            authselect_current_profile: '{{ result_authselect_profile.stdout }}'
            authselect_custom_profile: custom/hardening
          when:
          - result_authselect_profile is not skipped
          - result_authselect_profile.stdout is not match("custom/")

        - name: Set PAM's Password Hashing Algorithm - password-auth - Get authselect
            current features to also enable them in the custom profile
          ansible.builtin.shell:
            cmd: authselect current | tail -n+3 | awk '{ print $2 }'
          register: result_authselect_features
          changed_when: false
          when:
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")

        - name: Set PAM's Password Hashing Algorithm - password-auth - Check if any custom
            profile with the same name was already created
          ansible.builtin.stat:
            path: /etc/authselect/{{ authselect_custom_profile }}
          register: result_authselect_custom_profile_present
          changed_when: false
          when:
          - authselect_current_profile is not match("custom/")

        - name: Set PAM's Password Hashing Algorithm - password-auth - Create an authselect
            custom profile based on the current profile
          ansible.builtin.command:
            cmd: authselect create-profile hardening -b {{ authselect_current_profile
              }}
          when:
          - result_authselect_check_cmd is success
          - authselect_current_profile is not match("custom/")
          - not result_authselect_custom_profile_present.stat.exists

        - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure authselect
            changes are applied
          ansible.builtin.command:
            cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")
          - authselect_custom_profile is not match(authselect_current_profile)

        - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure the authselect
            custom profile is selected
          ansible.builtin.command:
            cmd: authselect select {{ authselect_custom_profile }}
          register: result_pam_authselect_select_profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")
          - authselect_custom_profile is not match(authselect_current_profile)

        - name: Set PAM's Password Hashing Algorithm - password-auth - Restore the authselect
            features in the custom profile
          ansible.builtin.command:
            cmd: authselect enable-feature {{ item }}
          loop: '{{ result_authselect_features.stdout_lines }}'
          register: result_pam_authselect_restore_features
          when:
          - result_authselect_profile is not skipped
          - result_authselect_features is not skipped
          - result_pam_authselect_select_profile is not skipped

        - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure authselect
            changes are applied
          ansible.builtin.command:
            cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - result_pam_authselect_restore_features is not skipped

        - name: Set PAM's Password Hashing Algorithm - password-auth - Change the PAM
            file to be edited according to the custom authselect profile
          ansible.builtin.set_fact:
            pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
              | basename }}
        when:
        - result_authselect_present.stat.exists

      - name: Set PAM's Password Hashing Algorithm - password-auth - Check if expected
          PAM module line is present in {{ pam_file_path }}
        ansible.builtin.lineinfile:
          path: '{{ pam_file_path }}'
          regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.*
          state: absent
        check_mode: true
        changed_when: false
        register: result_pam_line_present

      - name: Set PAM's Password Hashing Algorithm - password-auth - Include or update
          the PAM module line in {{ pam_file_path }}
        block:

        - name: Set PAM's Password Hashing Algorithm - password-auth - Check if required
            PAM module line is present in {{ pam_file_path }} with different control
          ansible.builtin.lineinfile:
            path: '{{ pam_file_path }}'
            regexp: ^\s*password\s+.*\s+pam_unix.so\s*
            state: absent
          check_mode: true
          changed_when: false
          register: result_pam_line_other_control_present

        - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure the correct
            control for the required PAM module line in {{ pam_file_path }}
          ansible.builtin.replace:
            dest: '{{ pam_file_path }}'
            regexp: ^(\s*password\s+).*(\bpam_unix.so.*)
            replace: \1sufficient \2
          register: result_pam_module_edit
          when:
          - result_pam_line_other_control_present.found == 1

        - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure the required
            PAM module line is included in {{ pam_file_path }}
          ansible.builtin.lineinfile:
            dest: '{{ pam_file_path }}'
            line: password    sufficient    pam_unix.so
          register: result_pam_module_add
          when:
          - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found
            > 1

        - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure authselect
            changes are applied
          ansible.builtin.command:
            cmd: authselect apply-changes -b
          when: |
            result_authselect_present is defined and result_authselect_present.stat.exists and ((result_pam_module_add is defined and result_pam_module_add.changed) or (result_pam_module_edit is defined and result_pam_module_edit.changed))
        when:
        - result_pam_line_present.found is defined
        - result_pam_line_present.found == 0

      - name: Set PAM's Password Hashing Algorithm - password-auth - Check if the required
          PAM module option is present in {{ pam_file_path }}
        ansible.builtin.lineinfile:
          path: '{{ pam_file_path }}'
          regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.*\ssha512\b
          state: absent
        check_mode: true
        changed_when: false
        register: result_pam_module_sha512_option_present

      - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure the "sha512"
          PAM option for "pam_unix.so" is included in {{ pam_file_path }}
        ansible.builtin.lineinfile:
          path: '{{ pam_file_path }}'
          backrefs: true
          regexp: ^(\s*password\s+sufficient\s+pam_unix.so.*)
          line: \1 sha512
          state: present
        register: result_pam_sha512_add
        when:
        - result_pam_module_sha512_option_present.found == 0

      - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure authselect
          changes are applied
        ansible.builtin.command:
          cmd: authselect apply-changes -b
        when:
        - result_authselect_present.stat.exists
        - (result_pam_sha512_add is defined and result_pam_sha512_add.changed) or (result_pam_sha512_edit
          is defined and result_pam_sha512_edit.changed)
      when:
      - '"pam" in ansible_facts.packages'
      - result_pam_file_present.stat.exists
      tags:
      - CCE-85946-2
      - CJIS-5.6.2.2
      - NIST-800-171-3.13.11
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(1)(c)
      - NIST-800-53-IA-5(c)
      - PCI-DSS-Req-8.2.1
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - set_password_hashing_algorithm_passwordauth

OVAL definition:

Definition ID:

oval:ssg-set_password_hashing_algorithm_passwordauth:def:1

Class:

compliance

Title:

Set PAM''s Password Hashing Algorithm - password-auth

Version:

1

Description:

The password hashing algorithm should be set correctly in /etc/pam.d/password-auth.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-set_password_hashing_algorithm_passwordauth:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#package_pam
Set PAM''s Password Hashing Algorithm medium pass

Rule ID: | xccdf_org.ssgproject.content_rule_set_password_hashing_algorithm_systemauth
Result: | pass
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83581-9

References:

BP28(R32), 1, 12, 15, 16, 5, 5.6.2.2, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 3.13.11, CCI-000196, CCI-000803, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.2, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, 0418, 1055, 1402, A.18.1.4, A.7.1.1, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.2, A.9.4.3, IA-5(c), IA-5(1)(c), CM-6(a), PR.AC-1, PR.AC-6, PR.AC-7, Req-8.2.1, SRG-OS-000073-GPOS-00041, SRG-OS-000120-GPOS-00061, SRG-OS-000480-VMM-002000, 5.5.4
Description:
The PAM system service can be configured to only store encrypted representations of passwords. In "/etc/pam.d/system-auth", the `password` section of the file controls which PAM modules execute during a password change. Set the `pam_unix.so` module in the `password` section to include the argument `sha512`, as shown below:

    password    sufficient    pam_unix.so sha512 other arguments...

This will help ensure when local users change their passwords, hashes for the new passwords will be generated using the SHA-512 algorithm. This is the default.
Rationale:

Passwords need to be protected at all times, and encryption is the standard method for protecting passwords. If passwords are not encrypted, they can be plainly read (i.e., clear text) and easily compromised. Passwords that are encrypted with a weak algorithm are no more protected than if they are kepy in plain text.
This setting ensures user and group account administration utilities are configured to store only encrypted representations of passwords. Additionally, the `crypt_style` configuration option ensures the use of a strong hashing algorithm that makes password cracking attacks more difficult.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if rpm --quiet -q pam; then

    if [ -e "/etc/pam.d/system-auth" ] ; then
        PAM_FILE_PATH="/etc/pam.d/system-auth"
        if [ -f /usr/bin/authselect ]; then

            if ! authselect check; then
            echo "
            authselect integrity check failed. Remediation aborted!
            This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
            It is not recommended to manually edit the PAM files when authselect tool is available.
            In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
            exit 1
            fi

            CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
            # If not already in use, a custom profile is created preserving the enabled features.
            if [[ ! $CURRENT_PROFILE == custom/* ]]; then
                ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
                authselect create-profile hardening -b $CURRENT_PROFILE
                CURRENT_PROFILE="custom/hardening"

                authselect apply-changes -b --backup=before-hardening-custom-profile
                authselect select $CURRENT_PROFILE
                for feature in $ENABLED_FEATURES; do
                    authselect enable-feature $feature;
                done

                authselect apply-changes -b --backup=after-hardening-custom-profile
            fi
            PAM_FILE_NAME=$(basename "/etc/pam.d/system-auth")
            PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"

            authselect apply-changes -b
        fi
        if ! grep -qP '^\s*password\s+'"sufficient"'\s+pam_unix.so\s*.*' "$PAM_FILE_PATH"; then
                # Line matching group + control + module was not found. Check group + module.
                if [ "$(grep -cP '^\s*password\s+.*\s+pam_unix.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then
                    # The control is updated only if one single line matches.
                    sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_unix.so.*)/\1'"sufficient"' \2/' "$PAM_FILE_PATH"
                else
                    echo 'password    '"sufficient"'    pam_unix.so' >> "$PAM_FILE_PATH"
                fi
            fi
            # Check the option
            if ! grep -qP '^\s*password\s+'"sufficient"'\s+pam_unix.so\s*.*\ssha512\b' "$PAM_FILE_PATH"; then
                sed -i -E --follow-symlinks '/\s*password\s+'"sufficient"'\s+pam_unix.so.*/ s/$/ sha512/' "$PAM_FILE_PATH"
            fi
        if [ -f /usr/bin/authselect ]; then

            authselect apply-changes -b
        fi
    else
        echo "/etc/pam.d/system-auth was not found" >&2
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | configure

    - name: Gather the package facts
      package_facts:
        manager: auto
      tags:
      - CCE-83581-9
      - CJIS-5.6.2.2
      - NIST-800-171-3.13.11
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(1)(c)
      - NIST-800-53-IA-5(c)
      - PCI-DSS-Req-8.2.1
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - set_password_hashing_algorithm_systemauth

    - name: Set PAM's Password Hashing Algorithm - Check if /etc/pam.d/system-auth file
        is present
      ansible.builtin.stat:
        path: /etc/pam.d/system-auth
      register: result_pam_file_present
      when: '"pam" in ansible_facts.packages'
      tags:
      - CCE-83581-9
      - CJIS-5.6.2.2
      - NIST-800-171-3.13.11
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(1)(c)
      - NIST-800-53-IA-5(c)
      - PCI-DSS-Req-8.2.1
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - set_password_hashing_algorithm_systemauth

    - name: Set PAM's Password Hashing Algorithm - Check the proper remediation for the
        system
      block:

      - name: Set PAM's Password Hashing Algorithm - Define the PAM file to be edited
          as a local fact
        ansible.builtin.set_fact:
          pam_file_path: /etc/pam.d/system-auth

      - name: Set PAM's Password Hashing Algorithm - Check if system relies on authselect
          tool
        ansible.builtin.stat:
          path: /usr/bin/authselect
        register: result_authselect_present

      - name: Set PAM's Password Hashing Algorithm - Ensure authselect custom profile
          is used if authselect is present
        block:

        - name: Set PAM's Password Hashing Algorithm - Check integrity of authselect current
            profile
          ansible.builtin.command:
            cmd: authselect check
          register: result_authselect_check_cmd
          changed_when: false
          ignore_errors: true

        - name: Set PAM's Password Hashing Algorithm - Informative message based on the
            authselect integrity check result
          ansible.builtin.assert:
            that:
            - result_authselect_check_cmd is success
            fail_msg:
            - authselect integrity check failed. Remediation aborted!
            - This remediation could not be applied because an authselect profile was
              not selected or the selected profile is not intact.
            - It is not recommended to manually edit the PAM files when authselect tool
              is available.
            - In cases where the default authselect profile does not cover a specific
              demand, a custom authselect profile is recommended.
            success_msg:
            - authselect integrity check passed

        - name: Set PAM's Password Hashing Algorithm - Get authselect current profile
          ansible.builtin.shell:
            cmd: authselect current -r | awk '{ print $1 }'
          register: result_authselect_profile
          changed_when: false
          when:
          - result_authselect_check_cmd is success

        - name: Set PAM's Password Hashing Algorithm - Define the current authselect profile
            as a local fact
          ansible.builtin.set_fact:
            authselect_current_profile: '{{ result_authselect_profile.stdout }}'
            authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
          when:
          - result_authselect_profile is not skipped
          - result_authselect_profile.stdout is match("custom/")

        - name: Set PAM's Password Hashing Algorithm - Define the new authselect custom
            profile as a local fact
          ansible.builtin.set_fact:
            authselect_current_profile: '{{ result_authselect_profile.stdout }}'
            authselect_custom_profile: custom/hardening
          when:
          - result_authselect_profile is not skipped
          - result_authselect_profile.stdout is not match("custom/")

        - name: Set PAM's Password Hashing Algorithm - Get authselect current features
            to also enable them in the custom profile
          ansible.builtin.shell:
            cmd: authselect current | tail -n+3 | awk '{ print $2 }'
          register: result_authselect_features
          changed_when: false
          when:
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")

        - name: Set PAM's Password Hashing Algorithm - Check if any custom profile with
            the same name was already created
          ansible.builtin.stat:
            path: /etc/authselect/{{ authselect_custom_profile }}
          register: result_authselect_custom_profile_present
          changed_when: false
          when:
          - authselect_current_profile is not match("custom/")

        - name: Set PAM's Password Hashing Algorithm - Create an authselect custom profile
            based on the current profile
          ansible.builtin.command:
            cmd: authselect create-profile hardening -b {{ authselect_current_profile
              }}
          when:
          - result_authselect_check_cmd is success
          - authselect_current_profile is not match("custom/")
          - not result_authselect_custom_profile_present.stat.exists

        - name: Set PAM's Password Hashing Algorithm - Ensure authselect changes are applied
          ansible.builtin.command:
            cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")
          - authselect_custom_profile is not match(authselect_current_profile)

        - name: Set PAM's Password Hashing Algorithm - Ensure the authselect custom profile
            is selected
          ansible.builtin.command:
            cmd: authselect select {{ authselect_custom_profile }}
          register: result_pam_authselect_select_profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - authselect_current_profile is not match("custom/")
          - authselect_custom_profile is not match(authselect_current_profile)

        - name: Set PAM's Password Hashing Algorithm - Restore the authselect features
            in the custom profile
          ansible.builtin.command:
            cmd: authselect enable-feature {{ item }}
          loop: '{{ result_authselect_features.stdout_lines }}'
          register: result_pam_authselect_restore_features
          when:
          - result_authselect_profile is not skipped
          - result_authselect_features is not skipped
          - result_pam_authselect_select_profile is not skipped

        - name: Set PAM's Password Hashing Algorithm - Ensure authselect changes are applied
          ansible.builtin.command:
            cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
          when:
          - result_authselect_check_cmd is success
          - result_authselect_profile is not skipped
          - result_pam_authselect_restore_features is not skipped

        - name: Set PAM's Password Hashing Algorithm - Change the PAM file to be edited
            according to the custom authselect profile
          ansible.builtin.set_fact:
            pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
              | basename }}
        when:
        - result_authselect_present.stat.exists

      - name: Set PAM's Password Hashing Algorithm - Check if expected PAM module line
          is present in {{ pam_file_path }}
        ansible.builtin.lineinfile:
          path: '{{ pam_file_path }}'
          regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.*
          state: absent
        check_mode: true
        changed_when: false
        register: result_pam_line_present

      - name: Set PAM's Password Hashing Algorithm - Include or update the PAM module
          line in {{ pam_file_path }}
        block:

        - name: Set PAM's Password Hashing Algorithm - Check if required PAM module line
            is present in {{ pam_file_path }} with different control
          ansible.builtin.lineinfile:
            path: '{{ pam_file_path }}'
            regexp: ^\s*password\s+.*\s+pam_unix.so\s*
            state: absent
          check_mode: true
          changed_when: false
          register: result_pam_line_other_control_present

        - name: Set PAM's Password Hashing Algorithm - Ensure the correct control for
            the required PAM module line in {{ pam_file_path }}
          ansible.builtin.replace:
            dest: '{{ pam_file_path }}'
            regexp: ^(\s*password\s+).*(\bpam_unix.so.*)
            replace: \1sufficient \2
          register: result_pam_module_edit
          when:
          - result_pam_line_other_control_present.found == 1

        - name: Set PAM's Password Hashing Algorithm - Ensure the required PAM module
            line is included in {{ pam_file_path }}
          ansible.builtin.lineinfile:
            dest: '{{ pam_file_path }}'
            line: password    sufficient    pam_unix.so
          register: result_pam_module_add
          when:
          - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found
            > 1

        - name: Set PAM's Password Hashing Algorithm - Ensure authselect changes are applied
          ansible.builtin.command:
            cmd: authselect apply-changes -b
          when: |
            result_authselect_present is defined and result_authselect_present.stat.exists and ((result_pam_module_add is defined and result_pam_module_add.changed) or (result_pam_module_edit is defined and result_pam_module_edit.changed))
        when:
        - result_pam_line_present.found is defined
        - result_pam_line_present.found == 0

      - name: Set PAM's Password Hashing Algorithm - Check if the required PAM module
          option is present in {{ pam_file_path }}
        ansible.builtin.lineinfile:
          path: '{{ pam_file_path }}'
          regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.*\ssha512\b
          state: absent
        check_mode: true
        changed_when: false
        register: result_pam_module_sha512_option_present

      - name: Set PAM's Password Hashing Algorithm - Ensure the "sha512" PAM option for
          "pam_unix.so" is included in {{ pam_file_path }}
        ansible.builtin.lineinfile:
          path: '{{ pam_file_path }}'
          backrefs: true
          regexp: ^(\s*password\s+sufficient\s+pam_unix.so.*)
          line: \1 sha512
          state: present
        register: result_pam_sha512_add
        when:
        - result_pam_module_sha512_option_present.found == 0

      - name: Set PAM's Password Hashing Algorithm - Ensure authselect changes are applied
        ansible.builtin.command:
          cmd: authselect apply-changes -b
        when:
        - result_authselect_present.stat.exists
        - (result_pam_sha512_add is defined and result_pam_sha512_add.changed) or (result_pam_sha512_edit
          is defined and result_pam_sha512_edit.changed)
      when:
      - '"pam" in ansible_facts.packages'
      - result_pam_file_present.stat.exists
      tags:
      - CCE-83581-9
      - CJIS-5.6.2.2
      - NIST-800-171-3.13.11
      - NIST-800-53-CM-6(a)
      - NIST-800-53-IA-5(1)(c)
      - NIST-800-53-IA-5(c)
      - PCI-DSS-Req-8.2.1
      - configure_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - no_reboot_needed
      - set_password_hashing_algorithm_systemauth

OVAL definition:

Definition ID:

oval:ssg-set_password_hashing_algorithm_systemauth:def:1

Class:

compliance

Title:

Set PAM''s Password Hashing Algorithm

Version:

1

Description:

The password hashing algorithm should be set correctly in /etc/pam.d/system-auth.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-set_password_hashing_algorithm_systemauth:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#package_pam
Disable SSH Access via Empty Passwords high error

Rule ID: | xccdf_org.ssgproject.content_rule_sshd_disable_empty_passwords
Result: | error
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

high

Identifiers:

CCE-90799-8

References:

NT007(R17), 11, 12, 13, 14, 15, 16, 18, 3, 5, 9, 5.5.6, APO01.06, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.03, DSS06.06, 3.1.1, 3.1.5, CCI-000366, CCI-000766, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 5.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.2, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.1, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, AC-17(a), CM-7(a), CM-7(b), CM-6(a), PR.AC-4, PR.AC-6, PR.DS-5, PR.IP-1, PR.PT-3, FIA_UAU.1, Req-2.2.6, SRG-OS-000106-GPOS-00053, SRG-OS-000480-GPOS-00229, SRG-OS-000480-GPOS-00227, SRG-OS-000480-VMM-002000, 5.2.9
Description:
Disallow SSH login with empty passwords. The default SSH configuration disables logins with empty passwords. The appropriate configuration is used if no value is set for `PermitEmptyPasswords`.
To explicitly disallow SSH login from accounts with empty passwords, add or correct the following line in `/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf`:

    PermitEmptyPasswords no

Any accounts with empty passwords should be disabled immediately, and PAM configuration should prevent users from being able to assign themselves empty passwords.
Rationale:

Configuring this setting for the SSH daemon provides additional assurance that remote login via SSH will require a password, even in the event of misconfiguration elsewhere.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    mkdir -p /etc/ssh/sshd_config.d
    touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf

    LC_ALL=C sed -i "/^\s*PermitEmptyPasswords\s\+/Id" "/etc/ssh/sshd_config"
    LC_ALL=C sed -i "/^\s*PermitEmptyPasswords\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf
    if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then

        LC_ALL=C sed -i "/^\s*PermitEmptyPasswords\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    else
        touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"

    cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak"
    # Insert before the line matching the regex '^Match'.
    line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" | LC_ALL=C sed 's/:.*//g')"
    if [ -z "$line_number" ]; then
        # There was no match of '^Match', insert at
        # the end of the file.
        printf '%s\n' "PermitEmptyPasswords no" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    else
        head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
        printf '%s\n' "PermitEmptyPasswords no" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
        tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    fi
    # Clean up after ourselves.
    rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak"

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Disable SSH Access via Empty Passwords
      block:

      - name: Deduplicate values from /etc/ssh/sshd_config
        lineinfile:
          path: /etc/ssh/sshd_config
          create: false
          regexp: (?i)^\s*{{ "PermitEmptyPasswords"| regex_escape }}\s+
          state: absent

      - name: Check if /etc/ssh/sshd_config.d exists
        stat:
          path: /etc/ssh/sshd_config.d
        register: _etc_ssh_sshd_config_d_exists

      - name: Check if the parameter PermitEmptyPasswords is present in /etc/ssh/sshd_config.d
        find:
          paths: /etc/ssh/sshd_config.d
          recurse: 'yes'
          follow: 'no'
          contains: (?i)^\s*{{ "PermitEmptyPasswords"| regex_escape }}\s+
        register: _etc_ssh_sshd_config_d_has_parameter
        when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir

      - name: Remove parameter from files in /etc/ssh/sshd_config.d
        lineinfile:
          path: '{{ item.path }}'
          create: false
          regexp: (?i)^\s*{{ "PermitEmptyPasswords"| regex_escape }}\s+
          state: absent
        with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}'
        when: _etc_ssh_sshd_config_d_has_parameter.matched

      - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf
        lineinfile:
          path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf
          create: true
          regexp: (?i)^\s*{{ "PermitEmptyPasswords"| regex_escape }}\s+
          line: PermitEmptyPasswords no
          state: present
          insertbefore: ^[#\s]*Match
          validate: /usr/sbin/sshd -t -f %s
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90799-8
      - CJIS-5.5.6
      - NIST-800-171-3.1.1
      - NIST-800-171-3.1.5
      - NIST-800-53-AC-17(a)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - PCI-DSS-Req-2.2.6
      - high_severity
      - low_complexity
      - low_disruption
      - no_reboot_needed
      - restrict_strategy
      - sshd_disable_empty_passwords

OVAL definition:

Definition ID:

oval:ssg-sshd_disable_empty_passwords:def:1

Class:

compliance

Title:

Disable SSH Access via Empty Passwords

Version:

1

Description:

Ensure 'PermitEmptyPasswords' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sshd_disable_empty_passwords:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Disable SSH Support for .rhosts Files medium error

Rule ID: | xccdf_org.ssgproject.content_rule_sshd_disable_rhosts
Result: | error
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90797-2

References:

11, 12, 14, 15, 16, 18, 3, 5, 9, 5.5.6, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.03, DSS06.06, 3.1.12, CCI-000366, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.6.1.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, AC-17(a), CM-7(a), CM-7(b), CM-6(a), PR.AC-4, PR.AC-6, PR.IP-1, PR.PT-3, FIA_UAU.1, SRG-OS-000480-GPOS-00227, SRG-OS-000107-VMM-000530, 5.2.11
Description:
SSH can emulate the behavior of the obsolete rsh command in allowing users to enable insecure access to their accounts via `.rhosts` files.
The default SSH configuration disables support for `.rhosts`. The appropriate configuration is used if no value is set for `IgnoreRhosts`.
To explicitly disable support for .rhosts files, add or correct the following line in `/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf`:

    IgnoreRhosts yes

Rationale:

SSH trust relationships mean a compromise on one host can allow an attacker to move trivially to other hosts.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    mkdir -p /etc/ssh/sshd_config.d
    touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf

    LC_ALL=C sed -i "/^\s*IgnoreRhosts\s\+/Id" "/etc/ssh/sshd_config"
    LC_ALL=C sed -i "/^\s*IgnoreRhosts\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf
    if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then

        LC_ALL=C sed -i "/^\s*IgnoreRhosts\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    else
        touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"

    cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak"
    # Insert before the line matching the regex '^Match'.
    line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" | LC_ALL=C sed 's/:.*//g')"
    if [ -z "$line_number" ]; then
        # There was no match of '^Match', insert at
        # the end of the file.
        printf '%s\n' "IgnoreRhosts yes" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    else
        head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
        printf '%s\n' "IgnoreRhosts yes" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
        tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    fi
    # Clean up after ourselves.
    rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak"

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Disable SSH Support for .rhosts Files
      block:

      - name: Deduplicate values from /etc/ssh/sshd_config
        lineinfile:
          path: /etc/ssh/sshd_config
          create: false
          regexp: (?i)^\s*{{ "IgnoreRhosts"| regex_escape }}\s+
          state: absent

      - name: Check if /etc/ssh/sshd_config.d exists
        stat:
          path: /etc/ssh/sshd_config.d
        register: _etc_ssh_sshd_config_d_exists

      - name: Check if the parameter IgnoreRhosts is present in /etc/ssh/sshd_config.d
        find:
          paths: /etc/ssh/sshd_config.d
          recurse: 'yes'
          follow: 'no'
          contains: (?i)^\s*{{ "IgnoreRhosts"| regex_escape }}\s+
        register: _etc_ssh_sshd_config_d_has_parameter
        when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir

      - name: Remove parameter from files in /etc/ssh/sshd_config.d
        lineinfile:
          path: '{{ item.path }}'
          create: false
          regexp: (?i)^\s*{{ "IgnoreRhosts"| regex_escape }}\s+
          state: absent
        with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}'
        when: _etc_ssh_sshd_config_d_has_parameter.matched

      - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf
        lineinfile:
          path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf
          create: true
          regexp: (?i)^\s*{{ "IgnoreRhosts"| regex_escape }}\s+
          line: IgnoreRhosts yes
          state: present
          insertbefore: ^[#\s]*Match
          validate: /usr/sbin/sshd -t -f %s
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90797-2
      - CJIS-5.5.6
      - NIST-800-171-3.1.12
      - NIST-800-53-AC-17(a)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
      - sshd_disable_rhosts

OVAL definition:

Definition ID:

oval:ssg-sshd_disable_rhosts:def:1

Class:

compliance

Title:

Disable SSH Support for .rhosts Files

Version:

1

Description:

Ensure 'IgnoreRhosts' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sshd_disable_rhosts:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Disable SSH Root Login medium error

Rule ID: | xccdf_org.ssgproject.content_rule_sshd_disable_root_login
Result: | error
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90800-4

References:

BP28(R19), NT007(R21), 1, 11, 12, 13, 14, 15, 16, 18, 3, 5, 5.5.6, APO01.06, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.02, DSS06.03, DSS06.06, DSS06.10, 3.1.1, 3.1.5, CCI-000366, CCI-000770, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.18.1.4, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.2.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, AC-6(2), AC-17(a), IA-2, IA-2(5), CM-7(a), CM-7(b), CM-6(a), PR.AC-1, PR.AC-4, PR.AC-6, PR.AC-7, PR.DS-5, PR.PT-3, FAU_GEN.1, Req-2.2.6, SRG-OS-000109-GPOS-00056, SRG-OS-000480-GPOS-00227, SRG-OS-000480-VMM-002000, 5.2.7
Description:
The root user should never be allowed to login to a system directly over a network. To disable root login via SSH, add or correct the following line in `/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf`:

    PermitRootLogin no

Rationale:

Even though the communications channel may be encrypted, an additional layer of security is gained by extending the policy of not logging directly on as root. In addition, logging in with a user-specific account provides individual accountability of actions performed on the system and also helps to minimize direct attack attempts on root's password.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    mkdir -p /etc/ssh/sshd_config.d
    touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf

    LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config"
    LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf
    if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then

        LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    else
        touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"

    cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"
    # Insert before the line matching the regex '^Match'.
    line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" | LC_ALL=C sed 's/:.*//g')"
    if [ -z "$line_number" ]; then
        # There was no match of '^Match', insert at
        # the end of the file.
        printf '%s\n' "PermitRootLogin no" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    else
        head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
        printf '%s\n' "PermitRootLogin no" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
        tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    fi
    # Clean up after ourselves.
    rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Disable SSH Root Login
      block:

      - name: Deduplicate values from /etc/ssh/sshd_config
        lineinfile:
          path: /etc/ssh/sshd_config
          create: false
          regexp: (?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+
          state: absent

      - name: Check if /etc/ssh/sshd_config.d exists
        stat:
          path: /etc/ssh/sshd_config.d
        register: _etc_ssh_sshd_config_d_exists

      - name: Check if the parameter PermitRootLogin is present in /etc/ssh/sshd_config.d
        find:
          paths: /etc/ssh/sshd_config.d
          recurse: 'yes'
          follow: 'no'
          contains: (?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+
        register: _etc_ssh_sshd_config_d_has_parameter
        when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir

      - name: Remove parameter from files in /etc/ssh/sshd_config.d
        lineinfile:
          path: '{{ item.path }}'
          create: false
          regexp: (?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+
          state: absent
        with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}'
        when: _etc_ssh_sshd_config_d_has_parameter.matched

      - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
        lineinfile:
          path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
          create: true
          regexp: (?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+
          line: PermitRootLogin no
          state: present
          insertbefore: ^[#\s]*Match
          validate: /usr/sbin/sshd -t -f %s
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90800-4
      - CJIS-5.5.6
      - NIST-800-171-3.1.1
      - NIST-800-171-3.1.5
      - NIST-800-53-AC-17(a)
      - NIST-800-53-AC-6(2)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-IA-2
      - NIST-800-53-IA-2(5)
      - PCI-DSS-Req-2.2.6
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
      - sshd_disable_root_login

OVAL definition:

Definition ID:

oval:ssg-sshd_disable_root_login:def:1

Class:

compliance

Title:

Disable SSH Root Login

Version:

1

Description:

Ensure 'PermitRootLogin' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sshd_disable_root_login:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Disable X11 Forwarding medium error

Rule ID: | xccdf_org.ssgproject.content_rule_sshd_disable_x11_forwarding
Result: | error
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90798-0

References:

CCI-000366, CM-6(b), SRG-OS-000480-GPOS-00227, 5.2.12
Description:
The X11Forwarding parameter provides the ability to tunnel X11 traffic through the connection to enable remote graphic connections. SSH has the capability to encrypt remote X11 connections when SSH's `X11Forwarding` option is enabled.
The default SSH configuration disables X11Forwarding. The appropriate configuration is used if no value is set for `X11Forwarding`.
To explicitly disable X11 Forwarding, add or correct the following line in `/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf`:

    X11Forwarding no

Rationale:

Disable X11 forwarding unless there is an operational requirement to use X11 applications directly. There is a small risk that the remote X11 servers of users who are logged in via SSH with X11 forwarding could be compromised by other users on the X11 server. Note that even if X11 forwarding is disabled, users can always install their own forwarders.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    mkdir -p /etc/ssh/sshd_config.d
    touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf

    LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config"
    LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf
    if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then

        LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    else
        touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"

    cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak"
    # Insert before the line matching the regex '^Match'.
    line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" | LC_ALL=C sed 's/:.*//g')"
    if [ -z "$line_number" ]; then
        # There was no match of '^Match', insert at
        # the end of the file.
        printf '%s\n' "X11Forwarding no" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    else
        head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
        printf '%s\n' "X11Forwarding no" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
        tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    fi
    # Clean up after ourselves.
    rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak"

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Disable X11 Forwarding
      block:

      - name: Deduplicate values from /etc/ssh/sshd_config
        lineinfile:
          path: /etc/ssh/sshd_config
          create: false
          regexp: (?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+
          state: absent

      - name: Check if /etc/ssh/sshd_config.d exists
        stat:
          path: /etc/ssh/sshd_config.d
        register: _etc_ssh_sshd_config_d_exists

      - name: Check if the parameter X11Forwarding is present in /etc/ssh/sshd_config.d
        find:
          paths: /etc/ssh/sshd_config.d
          recurse: 'yes'
          follow: 'no'
          contains: (?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+
        register: _etc_ssh_sshd_config_d_has_parameter
        when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir

      - name: Remove parameter from files in /etc/ssh/sshd_config.d
        lineinfile:
          path: '{{ item.path }}'
          create: false
          regexp: (?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+
          state: absent
        with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}'
        when: _etc_ssh_sshd_config_d_has_parameter.matched

      - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf
        lineinfile:
          path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf
          create: true
          regexp: (?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+
          line: X11Forwarding no
          state: present
          insertbefore: ^[#\s]*Match
          validate: /usr/sbin/sshd -t -f %s
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90798-0
      - NIST-800-53-CM-6(b)
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
      - sshd_disable_x11_forwarding

OVAL definition:

Definition ID:

oval:ssg-sshd_disable_x11_forwarding:def:1

Class:

compliance

Title:

Disable X11 Forwarding

Version:

1

Description:

Ensure 'X11Forwarding' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sshd_disable_x11_forwarding:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Do Not Allow SSH Environment Options medium error

Rule ID: | xccdf_org.ssgproject.content_rule_sshd_do_not_permit_user_env
Result: | error
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90803-8

References:

11, 3, 9, 5.5.6, BAI10.01, BAI10.02, BAI10.03, BAI10.05, 3.1.12, CCI-000366, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.4.3.2, 4.3.4.3.3, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, AC-17(a), CM-7(a), CM-7(b), CM-6(a), PR.IP-1, Req-2.2.6, SRG-OS-000480-GPOS-00229, SRG-OS-000480-VMM-002000, 5.2.10
Description:
Ensure that users are not able to override environment variables of the SSH daemon.
The default SSH configuration disables environment processing. The appropriate configuration is used if no value is set for `PermitUserEnvironment`.
To explicitly disable Environment options, add or correct the following `/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf`:

    PermitUserEnvironment no

Rationale:

SSH environment options potentially allow users to bypass access restriction in some configurations.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    mkdir -p /etc/ssh/sshd_config.d
    touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf

    LC_ALL=C sed -i "/^\s*PermitUserEnvironment\s\+/Id" "/etc/ssh/sshd_config"
    LC_ALL=C sed -i "/^\s*PermitUserEnvironment\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf
    if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then

        LC_ALL=C sed -i "/^\s*PermitUserEnvironment\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    else
        touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"

    cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak"
    # Insert before the line matching the regex '^Match'.
    line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" | LC_ALL=C sed 's/:.*//g')"
    if [ -z "$line_number" ]; then
        # There was no match of '^Match', insert at
        # the end of the file.
        printf '%s\n' "PermitUserEnvironment no" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    else
        head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
        printf '%s\n' "PermitUserEnvironment no" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
        tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf"
    fi
    # Clean up after ourselves.
    rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak"

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Do Not Allow SSH Environment Options
      block:

      - name: Deduplicate values from /etc/ssh/sshd_config
        lineinfile:
          path: /etc/ssh/sshd_config
          create: false
          regexp: (?i)^\s*{{ "PermitUserEnvironment"| regex_escape }}\s+
          state: absent

      - name: Check if /etc/ssh/sshd_config.d exists
        stat:
          path: /etc/ssh/sshd_config.d
        register: _etc_ssh_sshd_config_d_exists

      - name: Check if the parameter PermitUserEnvironment is present in /etc/ssh/sshd_config.d
        find:
          paths: /etc/ssh/sshd_config.d
          recurse: 'yes'
          follow: 'no'
          contains: (?i)^\s*{{ "PermitUserEnvironment"| regex_escape }}\s+
        register: _etc_ssh_sshd_config_d_has_parameter
        when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir

      - name: Remove parameter from files in /etc/ssh/sshd_config.d
        lineinfile:
          path: '{{ item.path }}'
          create: false
          regexp: (?i)^\s*{{ "PermitUserEnvironment"| regex_escape }}\s+
          state: absent
        with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}'
        when: _etc_ssh_sshd_config_d_has_parameter.matched

      - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf
        lineinfile:
          path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf
          create: true
          regexp: (?i)^\s*{{ "PermitUserEnvironment"| regex_escape }}\s+
          line: PermitUserEnvironment no
          state: present
          insertbefore: ^[#\s]*Match
          validate: /usr/sbin/sshd -t -f %s
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90803-8
      - CJIS-5.5.6
      - NIST-800-171-3.1.12
      - NIST-800-53-AC-17(a)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - PCI-DSS-Req-2.2.6
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
      - sshd_do_not_permit_user_env

OVAL definition:

Definition ID:

oval:ssg-sshd_do_not_permit_user_env:def:1

Class:

compliance

Title:

Do Not Allow SSH Environment Options

Version:

1

Description:

Ensure 'PermitUserEnvironment' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sshd_do_not_permit_user_env:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Enable PAM medium error

Rule ID: | xccdf_org.ssgproject.content_rule_sshd_enable_pam
Result: | error
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86722-6

References:

CCI-000877, SRG-OS-000125-GPOS-00065, 5.2.6
Description:
UsePAM Enables the Pluggable Authentication Module interface. If set to “yes” this will enable PAM authentication using ChallengeResponseAuthentication and PasswordAuthentication in addition to PAM account and session module processing for all authentication types. To enable PAM authentication, add or correct the following line in `/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf`:

    UsePAM yes

Rationale:

When UsePAM is set to yes, PAM runs through account and session types properly. This is important if you want to restrict access to services based off of IP, time or other factors of the account. Additionally, you can make sure users inherit certain environment variables on login or disallow access to the server.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    mkdir -p /etc/ssh/sshd_config.d
    touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf

    LC_ALL=C sed -i "/^\s*UsePAM\s\+/Id" "/etc/ssh/sshd_config"
    LC_ALL=C sed -i "/^\s*UsePAM\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf
    if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then

        LC_ALL=C sed -i "/^\s*UsePAM\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    else
        touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"

    cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"
    # Insert before the line matching the regex '^Match'.
    line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" | LC_ALL=C sed 's/:.*//g')"
    if [ -z "$line_number" ]; then
        # There was no match of '^Match', insert at
        # the end of the file.
        printf '%s\n' "UsePAM yes" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    else
        head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
        printf '%s\n' "UsePAM yes" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
        tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    fi
    # Clean up after ourselves.
    rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Enable PAM
      block:

      - name: Deduplicate values from /etc/ssh/sshd_config
        lineinfile:
          path: /etc/ssh/sshd_config
          create: false
          regexp: (?i)^\s*{{ "UsePAM"| regex_escape }}\s+
          state: absent

      - name: Check if /etc/ssh/sshd_config.d exists
        stat:
          path: /etc/ssh/sshd_config.d
        register: _etc_ssh_sshd_config_d_exists

      - name: Check if the parameter UsePAM is present in /etc/ssh/sshd_config.d
        find:
          paths: /etc/ssh/sshd_config.d
          recurse: 'yes'
          follow: 'no'
          contains: (?i)^\s*{{ "UsePAM"| regex_escape }}\s+
        register: _etc_ssh_sshd_config_d_has_parameter
        when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir

      - name: Remove parameter from files in /etc/ssh/sshd_config.d
        lineinfile:
          path: '{{ item.path }}'
          create: false
          regexp: (?i)^\s*{{ "UsePAM"| regex_escape }}\s+
          state: absent
        with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}'
        when: _etc_ssh_sshd_config_d_has_parameter.matched

      - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
        lineinfile:
          path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
          create: true
          regexp: (?i)^\s*{{ "UsePAM"| regex_escape }}\s+
          line: UsePAM yes
          state: present
          insertbefore: ^[#\s]*Match
          validate: /usr/sbin/sshd -t -f %s
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-86722-6
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
      - sshd_enable_pam

OVAL definition:

Definition ID:

oval:ssg-sshd_enable_pam:def:1

Class:

compliance

Title:

Enable PAM

Version:

1

Description:

Ensure 'UsePAM' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sshd_enable_pam:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Enable SSH Warning Banner medium error

Rule ID: | xccdf_org.ssgproject.content_rule_sshd_enable_warning_banner
Result: | error
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90807-9

References:

1, 12, 15, 16, 5.5.6, DSS05.04, DSS05.10, DSS06.10, 3.1.9, CCI-000048, CCI-000050, CCI-001384, CCI-001385, CCI-001386, CCI-001387, CCI-001388, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, AC-8(a), AC-8(c), AC-17(a), CM-6(a), PR.AC-7, FTA_TAB.1, Req-2.2.6, SRG-OS-000023-GPOS-00006, SRG-OS-000228-GPOS-00088, SRG-OS-000023-VMM-000060, SRG-OS-000024-VMM-000070, 5.2.15
Description:
To enable the warning banner and ensure it is consistent across the system, add or correct the following line in `/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf`:

    Banner /etc/issue

Another section contains information on how to create an appropriate system-wide warning banner.
Rationale:

The warning message reinforces policy awareness during the logon process and facilitates possible legal action against attackers. Alternatively, systems whose ownership should not be obvious should ensure usage of a banner that does not provide easy attribution.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    mkdir -p /etc/ssh/sshd_config.d
    touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf

    LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config"
    LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf
    if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then

        LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    else
        touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"

    cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"
    # Insert before the line matching the regex '^Match'.
    line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" | LC_ALL=C sed 's/:.*//g')"
    if [ -z "$line_number" ]; then
        # There was no match of '^Match', insert at
        # the end of the file.
        printf '%s\n' "Banner /etc/issue" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    else
        head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
        printf '%s\n' "Banner /etc/issue" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
        tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    fi
    # Clean up after ourselves.
    rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Enable SSH Warning Banner
      block:

      - name: Deduplicate values from /etc/ssh/sshd_config
        lineinfile:
          path: /etc/ssh/sshd_config
          create: false
          regexp: (?i)^\s*{{ "Banner"| regex_escape }}\s+
          state: absent

      - name: Check if /etc/ssh/sshd_config.d exists
        stat:
          path: /etc/ssh/sshd_config.d
        register: _etc_ssh_sshd_config_d_exists

      - name: Check if the parameter Banner is present in /etc/ssh/sshd_config.d
        find:
          paths: /etc/ssh/sshd_config.d
          recurse: 'yes'
          follow: 'no'
          contains: (?i)^\s*{{ "Banner"| regex_escape }}\s+
        register: _etc_ssh_sshd_config_d_has_parameter
        when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir

      - name: Remove parameter from files in /etc/ssh/sshd_config.d
        lineinfile:
          path: '{{ item.path }}'
          create: false
          regexp: (?i)^\s*{{ "Banner"| regex_escape }}\s+
          state: absent
        with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}'
        when: _etc_ssh_sshd_config_d_has_parameter.matched

      - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
        lineinfile:
          path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
          create: true
          regexp: (?i)^\s*{{ "Banner"| regex_escape }}\s+
          line: Banner /etc/issue
          state: present
          insertbefore: ^[#\s]*Match
          validate: /usr/sbin/sshd -t -f %s
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90807-9
      - CJIS-5.5.6
      - NIST-800-171-3.1.9
      - NIST-800-53-AC-17(a)
      - NIST-800-53-AC-8(a)
      - NIST-800-53-AC-8(c)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-2.2.6
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
      - sshd_enable_warning_banner

OVAL definition:

Definition ID:

oval:ssg-sshd_enable_warning_banner:def:1

Class:

compliance

Title:

Enable SSH Warning Banner

Version:

1

Description:

Ensure 'Banner' is configured with value '/etc/issue' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sshd_enable_warning_banner:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Set SSH Client Alive Count Max medium error

Rule ID: | xccdf_org.ssgproject.content_rule_sshd_set_keepalive
Result: | error
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90805-3

References:

BP28(R29), 1, 12, 13, 14, 15, 16, 18, 3, 5, 7, 8, 5.5.6, APO13.01, BAI03.01, BAI03.02, BAI03.03, DSS01.03, DSS03.05, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 3.1.11, CCI-000879, CCI-001133, CCI-002361, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 6.2, A.12.4.1, A.12.4.3, A.14.1.1, A.14.2.1, A.14.2.5, A.18.1.4, A.6.1.2, A.6.1.5, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, CIP-004-6 R2.2.3, CIP-007-3 R5.1, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, AC-2(5), AC-12, AC-17(a), SC-10, CM-6(a), DE.CM-1, DE.CM-3, PR.AC-1, PR.AC-4, PR.AC-6, PR.AC-7, PR.IP-2, Req-8.1.8, SRG-OS-000163-GPOS-00072, SRG-OS-000279-GPOS-00109, SRG-OS-000480-VMM-002000, 5.2.20
Description:
The SSH server sends at most `ClientAliveCountMax` messages during a SSH session and waits for a response from the SSH client. The option `ClientAliveInterval` configures timeout after each `ClientAliveCountMax` message. If the SSH server does not receive a response from the client, then the connection is considered unresponsive and terminated. For SSH earlier than v8.2, a `ClientAliveCountMax` value of `0` causes a timeout precisely when the `ClientAliveInterval` is set. Starting with v8.2, a value of `0` disables the timeout functionality completely. If the option is set to a number greater than `0`, then the session will be disconnected after `ClientAliveInterval * ClientAliveCountMax` seconds without receiving a keep alive message.
Rationale:

This ensures a user login will be terminated as soon as the `ClientAliveInterval` is reached.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    var_sshd_set_keepalive='0'

    if [ -e "/etc/ssh/sshd_config" ] ; then

        LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config"
    else
        touch "/etc/ssh/sshd_config"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/ssh/sshd_config"

    cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
    # Insert before the line matching the regex '^Match'.
    line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')"
    if [ -z "$line_number" ]; then
        # There was no match of '^Match', insert at
        # the end of the file.
        printf '%s\n' "ClientAliveCountMax $var_sshd_set_keepalive" >> "/etc/ssh/sshd_config"
    else
        head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config"
        printf '%s\n' "ClientAliveCountMax $var_sshd_set_keepalive" >> "/etc/ssh/sshd_config"
        tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
    fi
    # Clean up after ourselves.
    rm "/etc/ssh/sshd_config.bak"

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: XCCDF Value var_sshd_set_keepalive # promote to variable
      set_fact:
        var_sshd_set_keepalive: !!str 0
      tags:
        - always

    - name: Set SSH Client Alive Count Max
      block:

      - name: Check for duplicate values
        lineinfile:
          path: /etc/ssh/sshd_config
          create: false
          regexp: (?i)^\s*ClientAliveCountMax\s+
          state: absent
        check_mode: true
        changed_when: false
        register: dupes

      - name: Deduplicate values from /etc/ssh/sshd_config
        lineinfile:
          path: /etc/ssh/sshd_config
          create: false
          regexp: (?i)^\s*ClientAliveCountMax\s+
          state: absent
        when: dupes.found is defined and dupes.found > 1

      - name: Insert correct line to /etc/ssh/sshd_config
        lineinfile:
          path: /etc/ssh/sshd_config
          create: true
          regexp: (?i)^\s*ClientAliveCountMax\s+
          line: ClientAliveCountMax {{ var_sshd_set_keepalive }}
          state: present
          insertbefore: ^[#\s]*Match
          validate: /usr/sbin/sshd -t -f %s
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90805-3
      - CJIS-5.5.6
      - NIST-800-171-3.1.11
      - NIST-800-53-AC-12
      - NIST-800-53-AC-17(a)
      - NIST-800-53-AC-2(5)
      - NIST-800-53-CM-6(a)
      - NIST-800-53-SC-10
      - PCI-DSS-Req-8.1.8
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
      - sshd_set_keepalive

OVAL definition:

Definition ID:

oval:ssg-sshd_set_keepalive:def:1

Class:

compliance

Title:

Set SSH Client Alive Count Max

Version:

1

Description:

The SSH ClientAliveCountMax should be set to an appropriate value (and dependencies are met)

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sshd_set_keepalive:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Ensure SSH LoginGraceTime is configured medium error

Rule ID: | xccdf_org.ssgproject.content_rule_sshd_set_login_grace_time
Result: | error
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86552-7

References:

5.2.19
Description:
The `LoginGraceTime` parameter to the SSH server specifies the time allowed for successful authentication to the SSH server. The longer the Grace period is the more open unauthenticated connections can exist. Like other session controls in this session the Grace Period should be limited to appropriate limits to ensure the service is available for needed access.
Rationale:

Setting the `LoginGraceTime` parameter to a low number will minimize the risk of successful brute force attacks to the SSH server. It will also limit the number of concurrent unauthenticated connections.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    var_sshd_set_login_grace_time='60'

    if [ -e "/etc/ssh/sshd_config" ] ; then

        LC_ALL=C sed -i "/^\s*LoginGraceTime\s\+/Id" "/etc/ssh/sshd_config"
    else
        touch "/etc/ssh/sshd_config"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/ssh/sshd_config"

    cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
    # Insert before the line matching the regex '^Match'.
    line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')"
    if [ -z "$line_number" ]; then
        # There was no match of '^Match', insert at
        # the end of the file.
        printf '%s\n' "LoginGraceTime $var_sshd_set_login_grace_time" >> "/etc/ssh/sshd_config"
    else
        head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config"
        printf '%s\n' "LoginGraceTime $var_sshd_set_login_grace_time" >> "/etc/ssh/sshd_config"
        tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
    fi
    # Clean up after ourselves.
    rm "/etc/ssh/sshd_config.bak"

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: XCCDF Value var_sshd_set_login_grace_time # promote to variable
      set_fact:
        var_sshd_set_login_grace_time: !!str 60
      tags:
        - always

    - name: Ensure SSH LoginGraceTime is configured
      block:

      - name: Check for duplicate values
        lineinfile:
          path: /etc/ssh/sshd_config
          create: false
          regexp: (?i)^\s*LoginGraceTime\s+
          state: absent
        check_mode: true
        changed_when: false
        register: dupes

      - name: Deduplicate values from /etc/ssh/sshd_config
        lineinfile:
          path: /etc/ssh/sshd_config
          create: false
          regexp: (?i)^\s*LoginGraceTime\s+
          state: absent
        when: dupes.found is defined and dupes.found > 1

      - name: Insert correct line to /etc/ssh/sshd_config
        lineinfile:
          path: /etc/ssh/sshd_config
          create: true
          regexp: (?i)^\s*LoginGraceTime\s+
          line: LoginGraceTime {{ var_sshd_set_login_grace_time }}
          state: present
          insertbefore: ^[#\s]*Match
          validate: /usr/sbin/sshd -t -f %s
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-86552-7
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
      - sshd_set_login_grace_time

OVAL definition:

Definition ID:

oval:ssg-sshd_set_login_grace_time:def:1

Class:

compliance

Title:

Ensure SSH LoginGraceTime is configured

Version:

1

Description:

The SSH number seconds for login grace time should be set to an appropriate value.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sshd_set_login_grace_time:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Set SSH Daemon LogLevel to VERBOSE medium error

Rule ID: | xccdf_org.ssgproject.content_rule_sshd_set_loglevel_verbose
Result: | error
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-86923-0

References:

CCI-000067, CIP-007-3 R7.1, AC-17(a), AC-17(1), CM-6(a), Req-2.2.6, SRG-OS-000032-GPOS-00013, 5.2.5
Description:
The `VERBOSE` parameter configures the SSH daemon to record login and logout activity. To specify the log level in SSH, add or correct the following line in `/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf`:

    LogLevel VERBOSE

Rationale:

SSH provides several logging levels with varying amounts of verbosity. `DEBUG` is specifically not recommended other than strictly for debugging SSH communications since it provides so much data that it is difficult to identify important security information. `INFO` or `VERBOSE` level is the basic level that only records login activity of SSH users. In many situations, such as Incident Response, it is important to determine when a particular user was active on a system. The logout record can eliminate those users who disconnected, which helps narrow the field.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    mkdir -p /etc/ssh/sshd_config.d
    touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf

    LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config"
    LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf
    if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then

        LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    else
        touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"

    cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"
    # Insert before the line matching the regex '^Match'.
    line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" | LC_ALL=C sed 's/:.*//g')"
    if [ -z "$line_number" ]; then
        # There was no match of '^Match', insert at
        # the end of the file.
        printf '%s\n' "LogLevel VERBOSE" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    else
        head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
        printf '%s\n' "LogLevel VERBOSE" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
        tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    fi
    # Clean up after ourselves.
    rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Set SSH Daemon LogLevel to VERBOSE
      block:

      - name: Deduplicate values from /etc/ssh/sshd_config
        lineinfile:
          path: /etc/ssh/sshd_config
          create: false
          regexp: (?i)^\s*{{ "LogLevel"| regex_escape }}\s+
          state: absent

      - name: Check if /etc/ssh/sshd_config.d exists
        stat:
          path: /etc/ssh/sshd_config.d
        register: _etc_ssh_sshd_config_d_exists

      - name: Check if the parameter LogLevel is present in /etc/ssh/sshd_config.d
        find:
          paths: /etc/ssh/sshd_config.d
          recurse: 'yes'
          follow: 'no'
          contains: (?i)^\s*{{ "LogLevel"| regex_escape }}\s+
        register: _etc_ssh_sshd_config_d_has_parameter
        when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir

      - name: Remove parameter from files in /etc/ssh/sshd_config.d
        lineinfile:
          path: '{{ item.path }}'
          create: false
          regexp: (?i)^\s*{{ "LogLevel"| regex_escape }}\s+
          state: absent
        with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}'
        when: _etc_ssh_sshd_config_d_has_parameter.matched

      - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
        lineinfile:
          path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
          create: true
          regexp: (?i)^\s*{{ "LogLevel"| regex_escape }}\s+
          line: LogLevel VERBOSE
          state: present
          insertbefore: ^[#\s]*Match
          validate: /usr/sbin/sshd -t -f %s
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-86923-0
      - NIST-800-53-AC-17(1)
      - NIST-800-53-AC-17(a)
      - NIST-800-53-CM-6(a)
      - PCI-DSS-Req-2.2.6
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
      - sshd_set_loglevel_verbose

OVAL definition:

Definition ID:

oval:ssg-sshd_set_loglevel_verbose:def:1

Class:

compliance

Title:

Set SSH Daemon LogLevel to VERBOSE

Version:

1

Description:

Ensure 'LogLevel' is configured with value 'VERBOSE' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sshd_set_loglevel_verbose:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Set SSH authentication attempt limit medium error

Rule ID: | xccdf_org.ssgproject.content_rule_sshd_set_max_auth_tries
Result: | error
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90810-3

References:

0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, 5.2.16
Description:
The `MaxAuthTries` parameter specifies the maximum number of authentication attempts permitted per connection. Once the number of failures reaches half this value, additional failures are logged. to set MaxAUthTries edit `/etc/ssh/sshd_config` as follows:

    MaxAuthTries 4

Rationale:

Setting the MaxAuthTries parameter to a low number will minimize the risk of successful brute force attacks to the SSH server.

Remediation Shell script

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    sshd_max_auth_tries_value='4'

    if [ -e "/etc/ssh/sshd_config" ] ; then

        LC_ALL=C sed -i "/^\s*MaxAuthTries\s\+/Id" "/etc/ssh/sshd_config"
    else
        touch "/etc/ssh/sshd_config"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/ssh/sshd_config"

    cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
    # Insert before the line matching the regex '^Match'.
    line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')"
    if [ -z "$line_number" ]; then
        # There was no match of '^Match', insert at
        # the end of the file.
        printf '%s\n' "MaxAuthTries $sshd_max_auth_tries_value" >> "/etc/ssh/sshd_config"
    else
        head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config"
        printf '%s\n' "MaxAuthTries $sshd_max_auth_tries_value" >> "/etc/ssh/sshd_config"
        tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
    fi
    # Clean up after ourselves.
    rm "/etc/ssh/sshd_config.bak"

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: XCCDF Value sshd_max_auth_tries_value # promote to variable
      set_fact:
        sshd_max_auth_tries_value: !!str 4
      tags:
        - always

    - name: Set SSH authentication attempt limit
      block:

      - name: Check for duplicate values
        lineinfile:
          path: /etc/ssh/sshd_config
          create: false
          regexp: (?i)^\s*MaxAuthTries\s+
          state: absent
        check_mode: true
        changed_when: false
        register: dupes

      - name: Deduplicate values from /etc/ssh/sshd_config
        lineinfile:
          path: /etc/ssh/sshd_config
          create: false
          regexp: (?i)^\s*MaxAuthTries\s+
          state: absent
        when: dupes.found is defined and dupes.found > 1

      - name: Insert correct line to /etc/ssh/sshd_config
        lineinfile:
          path: /etc/ssh/sshd_config
          create: true
          regexp: (?i)^\s*MaxAuthTries\s+
          line: MaxAuthTries {{ sshd_max_auth_tries_value }}
          state: present
          insertbefore: ^[#\s]*Match
          validate: /usr/sbin/sshd -t -f %s
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-90810-3
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
      - sshd_set_max_auth_tries

OVAL definition:

Definition ID:

oval:ssg-sshd_set_max_auth_tries:def:1

Class:

compliance

Title:

Set SSH authentication attempt limit

Version:

1

Description:

The SSH MaxAuthTries should be set to an appropriate value.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sshd_set_max_auth_tries:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Set SSH MaxSessions limit medium error

Rule ID: | xccdf_org.ssgproject.content_rule_sshd_set_max_sessions
Result: | error
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84103-1

References:

5.2.18
Description:
The `MaxSessions` parameter specifies the maximum number of open sessions permitted from a given connection. To set MaxSessions edit `/etc/ssh/sshd_config` as follows:

    MaxSessions 10

Rationale:

To protect a system from denial of service due to a large number of concurrent sessions, use the rate limiting function of MaxSessions to protect availability of sshd logins and prevent overwhelming the daemon.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | configure

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    var_sshd_max_sessions='10'

    if [ -e "/etc/ssh/sshd_config" ] ; then

        LC_ALL=C sed -i "/^\s*MaxSessions\s\+/Id" "/etc/ssh/sshd_config"
    else
        touch "/etc/ssh/sshd_config"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/ssh/sshd_config"

    cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
    # Insert before the line matching the regex '^Match'.
    line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')"
    if [ -z "$line_number" ]; then
        # There was no match of '^Match', insert at
        # the end of the file.
        printf '%s\n' "MaxSessions $var_sshd_max_sessions" >> "/etc/ssh/sshd_config"
    else
        head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config"
        printf '%s\n' "MaxSessions $var_sshd_max_sessions" >> "/etc/ssh/sshd_config"
        tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
    fi
    # Clean up after ourselves.
    rm "/etc/ssh/sshd_config.bak"

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | configure

    - name: XCCDF Value var_sshd_max_sessions # promote to variable
      set_fact:
        var_sshd_max_sessions: !!str 10
      tags:
        - always

    - name: Set SSH MaxSessions limit
      block:

      - name: Check for duplicate values
        lineinfile:
          path: /etc/ssh/sshd_config
          create: false
          regexp: (?i)^\s*MaxSessions\s+
          state: absent
        check_mode: true
        changed_when: false
        register: dupes

      - name: Deduplicate values from /etc/ssh/sshd_config
        lineinfile:
          path: /etc/ssh/sshd_config
          create: false
          regexp: (?i)^\s*MaxSessions\s+
          state: absent
        when: dupes.found is defined and dupes.found > 1

      - name: Insert correct line to /etc/ssh/sshd_config
        lineinfile:
          path: /etc/ssh/sshd_config
          create: true
          regexp: (?i)^\s*MaxSessions\s+
          line: MaxSessions {{ var_sshd_max_sessions }}
          state: present
          insertbefore: ^[#\s]*Match
          validate: /usr/sbin/sshd -t -f %s
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84103-1
      - configure_strategy
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - sshd_set_max_sessions

OVAL definition:

Definition ID:

oval:ssg-sshd_set_max_sessions:def:1

Class:

compliance

Title:

Set SSH MaxSessions limit

Version:

1

Description:

The SSH number of max sessions should be set to an appropriate value.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sshd_set_max_sessions:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Ensure SSH MaxStartups is configured medium error

Rule ID: | xccdf_org.ssgproject.content_rule_sshd_set_maxstartups
Result: | error
Multi-check rule: | no
Time: | 2023-03-16T13:57:05+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-87872-8

References:

5.2.17
Description:
The MaxStartups parameter specifies the maximum number of concurrent unauthenticated connections to the SSH daemon. Additional connections will be dropped until authentication succeeds or the LoginGraceTime expires for a connection. To confgure MaxStartups, you should add or correct the following line in the `/etc/ssh/sshd_config` file:

    MaxStartups 10:30:60

CIS recommends a MaxStartups value of '10:30:60', or more restrictive where dictated by site policy.
Rationale:

To protect a system from denial of service due to a large number of pending authentication connection attempts, use the rate limiting function of MaxStartups to protect availability of sshd logins and prevent overwhelming the daemon.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    var_sshd_set_maxstartups='10:30:60'

    if [ -e "/etc/ssh/sshd_config" ] ; then

        LC_ALL=C sed -i "/^\s*MaxStartups\s\+/Id" "/etc/ssh/sshd_config"
    else
        touch "/etc/ssh/sshd_config"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/ssh/sshd_config"

    cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
    # Insert before the line matching the regex '^Match'.
    line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')"
    if [ -z "$line_number" ]; then
        # There was no match of '^Match', insert at
        # the end of the file.
        printf '%s\n' "MaxStartups $var_sshd_set_maxstartups" >> "/etc/ssh/sshd_config"
    else
        head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config"
        printf '%s\n' "MaxStartups $var_sshd_set_maxstartups" >> "/etc/ssh/sshd_config"
        tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
    fi
    # Clean up after ourselves.
    rm "/etc/ssh/sshd_config.bak"

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: XCCDF Value var_sshd_set_maxstartups # promote to variable
      set_fact:
        var_sshd_set_maxstartups: !!str 10:30:60
      tags:
        - always

    - name: Ensure SSH MaxStartups is configured
      block:

      - name: Check for duplicate values
        lineinfile:
          path: /etc/ssh/sshd_config
          create: false
          regexp: (?i)^\s*MaxStartups\s+
          state: absent
        check_mode: true
        changed_when: false
        register: dupes

      - name: Deduplicate values from /etc/ssh/sshd_config
        lineinfile:
          path: /etc/ssh/sshd_config
          create: false
          regexp: (?i)^\s*MaxStartups\s+
          state: absent
        when: dupes.found is defined and dupes.found > 1

      - name: Insert correct line to /etc/ssh/sshd_config
        lineinfile:
          path: /etc/ssh/sshd_config
          create: true
          regexp: (?i)^\s*MaxStartups\s+
          line: MaxStartups {{ var_sshd_set_maxstartups }}
          state: present
          insertbefore: ^[#\s]*Match
          validate: /usr/sbin/sshd -t -f %s
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-87872-8
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
      - sshd_set_maxstartups

OVAL definition:

Definition ID:

oval:ssg-sshd_set_maxstartups:def:1

Class:

compliance

Title:

Ensure SSH MaxStartups is configured

Version:

1

Description:

Ensure 'MaxStartups' is configured in '/etc/ssh/sshd_config'

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sshd_set_maxstartups:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo use_pty medium error

Rule ID: | xccdf_org.ssgproject.content_rule_sudo_add_use_pty
Result: | error
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83538-9

References:

BP28(R58), Req-10.2.1.5, 5.3.2
Description:
The sudo `use_pty` tag, when specified, will only execute sudo commands from users logged in to a real tty. This should be enabled by making sure that the `use_pty` tag exists in `/etc/sudoers` configuration file or any sudo configuration snippets in `/etc/sudoers.d/`.
Rationale:

Requiring that sudo commands be run in a pseudo-terminal can prevent an attacker from retaining access to the user's terminal after the main program has finished executing.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    if /usr/sbin/visudo -qcf /etc/sudoers; then
        cp /etc/sudoers /etc/sudoers.bak
        if ! grep -P '^[\s]*Defaults[\s]*\buse_pty\b.*$' /etc/sudoers; then
            # sudoers file doesn't define Option use_pty
            echo "Defaults use_pty" >> /etc/sudoers
        fi

        # Check validity of sudoers and cleanup bak
        if /usr/sbin/visudo -qcf /etc/sudoers; then
            rm -f /etc/sudoers.bak
        else
            echo "Fail to validate remediated /etc/sudoers, reverting to original file."
            mv /etc/sudoers.bak /etc/sudoers
            false
        fi
    else
        echo "Skipping remediation, /etc/sudoers failed to validate"
        false
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: Ensure use_pty is enabled in /etc/sudoers
      lineinfile:
        path: /etc/sudoers
        regexp: ^[\s]*Defaults.*\buse_pty\b.*$
        line: Defaults use_pty
        validate: /usr/sbin/visudo -cf %s
      tags:
      - CCE-83538-9
      - PCI-DSS-Req-10.2.1.5
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
      - sudo_add_use_pty

OVAL definition:

Definition ID:

oval:ssg-sudo_add_use_pty:def:1

Class:

compliance

Title:

Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo use_pty

Version:

1

Description:

Checks sudoers Defaults {{ OPTION }} configuration

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sudo_add_use_pty:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Ensure Sudo Logfile Exists - sudo logfile low error

Rule ID: | xccdf_org.ssgproject.content_rule_sudo_custom_logfile
Result: | error
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

low

Identifiers:

CCE-83527-2

References:

Req-10.2.1.5, 5.3.3
Description:
A custom log sudo file can be configured with the 'logfile' tag. This rule configures a sudo custom logfile at the default location suggested by CIS, which uses /var/log/sudo.log.
Rationale:

A sudo log file simplifies auditing of sudo commands.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    var_sudo_logfile='/var/log/sudo.log'

    if /usr/sbin/visudo -qcf /etc/sudoers; then
        cp /etc/sudoers /etc/sudoers.bak
        if ! grep -P '^[\s]*Defaults[\s]*\blogfile=("(?:\\"|\\\\|[^"\\\n])*"\B|[^"](?:(?:\\,|\\"|\\ |\\\\|[^", \\\n])*)\b)\b.*$' /etc/sudoers; then
            # sudoers file doesn't define Option logfile
            echo "Defaults logfile=${var_sudo_logfile}" >> /etc/sudoers
        else
            # sudoers file defines Option logfile, remediate if appropriate value is not set
            if ! grep -P "^[\s]*Defaults.*\blogfile=${var_sudo_logfile}\b.*$" /etc/sudoers; then

                escaped_variable=${var_sudo_logfile//$'/'/$'\/'}
                sed -Ei "s/(^[\s]*Defaults.*\blogfile=)[-]?.+(\b.*$)/\1$escaped_variable\2/" /etc/sudoers
            fi
        fi

        # Check validity of sudoers and cleanup bak
        if /usr/sbin/visudo -qcf /etc/sudoers; then
            rm -f /etc/sudoers.bak
        else
            echo "Fail to validate remediated /etc/sudoers, reverting to original file."
            mv /etc/sudoers.bak /etc/sudoers
            false
        fi
    else
        echo "Skipping remediation, /etc/sudoers failed to validate"
        false
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: XCCDF Value var_sudo_logfile # promote to variable
      set_fact:
        var_sudo_logfile: !!str /var/log/sudo.log
      tags:
        - always

    - name: Ensure logfile is enabled with the appropriate value in /etc/sudoers
      lineinfile:
        path: /etc/sudoers
        regexp: ^[\s]*Defaults\s(.*)\blogfile=[-]?.+\b(.*)$
        line: Defaults \1logfile={{ var_sudo_logfile }}\2
        validate: /usr/sbin/visudo -cf %s
        backrefs: true
      register: edit_sudoers_logfile_option
      tags:
      - CCE-83527-2
      - PCI-DSS-Req-10.2.1.5
      - low_complexity
      - low_disruption
      - low_severity
      - no_reboot_needed
      - restrict_strategy
      - sudo_custom_logfile

    - name: Enable logfile option with appropriate value in /etc/sudoers
      lineinfile:
        path: /etc/sudoers
        line: Defaults logfile={{ var_sudo_logfile }}
        validate: /usr/sbin/visudo -cf %s
      when: edit_sudoers_logfile_option is defined and not edit_sudoers_logfile_option.changed
      tags:
      - CCE-83527-2
      - PCI-DSS-Req-10.2.1.5
      - low_complexity
      - low_disruption
      - low_severity
      - no_reboot_needed
      - restrict_strategy
      - sudo_custom_logfile

OVAL definition:

Definition ID:

oval:ssg-sudo_custom_logfile:def:1

Class:

compliance

Title:

Ensure Sudo Logfile Exists - sudo logfile

Version:

1

Description:

Checks sudoers Defaults {{ OPTION }} configuration

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sudo_custom_logfile:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
The operating system must require Re-Authentication when using the sudo command. Ensure sudo timestamp_timeout is appropriate - sudo timestamp_timeout medium error

Rule ID: | xccdf_org.ssgproject.content_rule_sudo_require_reauthentication
Result: | error
Multi-check rule: | no
Time: | 2023-03-16T13:56:45+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90029-0

References:

CCI-002038, IA-11, SRG-OS-000373-GPOS-00156, SRG-OS-000373-GPOS-00157, SRG-OS-000373-GPOS-00158, 5.3.5, 5.3.6
Description:
The sudo `timestamp_timeout` tag sets the amount of time sudo password prompt waits. The default `timestamp_timeout` value is 5 minutes. The timestamp_timeout should be configured by making sure that the `timestamp_timeout` tag exists in `/etc/sudoers` configuration file or any sudo configuration snippets in `/etc/sudoers.d/`. If the value is set to an integer less than 0, the user's time stamp will not expire and the user will not have to re-authenticate for privileged actions until the user's session is terminated.
Rationale:

Without re-authentication, users may access resources or perform tasks for which they do not have authorization.
When operating systems provide the capability to escalate a functional capability, it is critical that the user re-authenticate.

Remediation Shell script

Complexity: | low
Disruption: | low
Strategy: | restrict

    var_sudo_timestamp_timeout='5'

    if grep -Px '^[\s]*Defaults.*timestamp_timeout[\s]*=.*' /etc/sudoers.d/*; then
        find /etc/sudoers.d/ -type f -exec sed -Ei "/^[[:blank:]]*Defaults.*timestamp_timeout[[:blank:]]*=.*/d" {} \;
    fi

    if /usr/sbin/visudo -qcf /etc/sudoers; then
        cp /etc/sudoers /etc/sudoers.bak
        if ! grep -P '^[\s]*Defaults.*timestamp_timeout[\s]*=[\s]*[-]?\w+.*$' /etc/sudoers; then
            # sudoers file doesn't define Option timestamp_timeout
            echo "Defaults timestamp_timeout=${var_sudo_timestamp_timeout}" >> /etc/sudoers
        else
            # sudoers file defines Option timestamp_timeout, remediate if appropriate value is not set
            if ! grep -P "^[\s]*Defaults.*timestamp_timeout[\s]*=[\s]*${var_sudo_timestamp_timeout}.*$" /etc/sudoers; then

                sed -Ei "s/(^[[:blank:]]*Defaults.*timestamp_timeout[[:blank:]]*=)[[:blank:]]*[-]?\w+(.*$)/\1${var_sudo_timestamp_timeout}\2/" /etc/sudoers
            fi
        fi

        # Check validity of sudoers and cleanup bak
        if /usr/sbin/visudo -qcf /etc/sudoers; then
            rm -f /etc/sudoers.bak
        else
            echo "Fail to validate remediated /etc/sudoers, reverting to original file."
            mv /etc/sudoers.bak /etc/sudoers
            false
        fi
    else
        echo "Skipping remediation, /etc/sudoers failed to validate"
        false
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: XCCDF Value var_sudo_timestamp_timeout # promote to variable
      set_fact:
        var_sudo_timestamp_timeout: !!str 5
      tags:
        - always

    - name: Find out if /etc/sudoers.d/* files contain 'Defaults timestamp_timeout' to
        be deduplicated
      find:
        path: /etc/sudoers.d
        patterns: '*'
        contains: ^[\s]*Defaults\s.*\btimestamp_timeout[\s]*=.*
      register: sudoers_d_defaults_timestamp_timeout
      tags:
      - CCE-90029-0
      - NIST-800-53-IA-11
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
      - sudo_require_reauthentication

    - name: Remove found occurrences of 'Defaults timestamp_timeout' from /etc/sudoers.d/*
        files
      lineinfile:
        path: '{{ item.path }}'
        regexp: ^[\s]*Defaults\s.*\btimestamp_timeout[\s]*=.*
        state: absent
      with_items: '{{ sudoers_d_defaults_timestamp_timeout.files }}'
      tags:
      - CCE-90029-0
      - NIST-800-53-IA-11
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
      - sudo_require_reauthentication

    - name: Ensure timestamp_timeout is enabled with the appropriate value in /etc/sudoers
      lineinfile:
        path: /etc/sudoers
        regexp: ^[\s]*Defaults\s(.*)\btimestamp_timeout[\s]*=[\s]*[-]?\w+\b(.*)$
        line: Defaults \1timestamp_timeout={{ var_sudo_timestamp_timeout }}\2
        validate: /usr/sbin/visudo -cf %s
        backrefs: true
      register: edit_sudoers_timestamp_timeout_option
      tags:
      - CCE-90029-0
      - NIST-800-53-IA-11
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
      - sudo_require_reauthentication

    - name: Enable timestamp_timeout option with appropriate value in /etc/sudoers
      lineinfile:
        path: /etc/sudoers
        line: Defaults timestamp_timeout={{ var_sudo_timestamp_timeout }}
        validate: /usr/sbin/visudo -cf %s
      when: edit_sudoers_timestamp_timeout_option is defined and not edit_sudoers_timestamp_timeout_option.changed
      tags:
      - CCE-90029-0
      - NIST-800-53-IA-11
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
      - sudo_require_reauthentication

OVAL definition:

Definition ID:

oval:ssg-sudo_require_reauthentication:def:1

Class:

compliance

Title:

The operating system must require Re-Authentication when using the sudo command. Ensure sudo timestamp_timeout is appropriate - sudo timestamp_timeout

Version:

1

Description:

'Ensure sudo timestamp_timeout is appropriate - sudo timestamp_timeout

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sudo_require_reauthentication:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Enable Randomized Layout of Virtual Address Space medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_kernel_randomize_va_space
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83971-2

References:

BP28(R23), 3.1.7, CCI-000366, CCI-002824, 164.308(a)(1)(ii)(D), 164.308(a)(3), 164.308(a)(4), 164.310(b), 164.310(c), 164.312(a), 164.312(e), CIP-002-5 R1.1, CIP-002-5 R1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 4.1, CIP-004-6 4.2, CIP-004-6 R2.2.3, CIP-004-6 R2.2.4, CIP-004-6 R2.3, CIP-004-6 R4, CIP-005-6 R1, CIP-005-6 R1.1, CIP-005-6 R1.2, CIP-007-3 R3, CIP-007-3 R3.1, CIP-007-3 R5.1, CIP-007-3 R5.1.2, CIP-007-3 R5.1.3, CIP-007-3 R5.2.1, CIP-007-3 R5.2.3, CIP-007-3 R8.4, CIP-009-6 R.1.1, CIP-009-6 R4, SC-30, SC-30(2), CM-6(a), Req-2.2.1, SRG-OS-000433-GPOS-00193, SRG-OS-000480-GPOS-00227, 1.5.3
Description:
To set the runtime status of the `kernel.randomize_va_space` kernel parameter, run the following command:

    $ sudo sysctl -w kernel.randomize_va_space=2

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    kernel.randomize_va_space = 2

Rationale:

Address space layout randomization (ASLR) makes it more difficult for an attacker to predict the location of attack code they have introduced into a process's address space during an attempt at exploitation. Additionally, ASLR makes it more difficult for an attacker to know the location of existing code in order to re-purpose it using return oriented programming (ROP) techniques.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "kernel.randomize_va_space"
    /tmp/oscap.GySYMU/fix-XXUzc16U: line 50: /etc/sysctl.conf: Permission denied
    /tmp/oscap.GySYMU/fix-XXUzc16U: line 51: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of kernel.randomize_va_space from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*kernel.randomize_va_space.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "kernel.randomize_va_space" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done

    #
    # Set runtime for kernel.randomize_va_space
    #
    /sbin/sysctl -q -n -w kernel.randomize_va_space="2"

    #
    # If kernel.randomize_va_space present in /etc/sysctl.conf, change value to "2"
    #	else, add "kernel.randomize_va_space = 2" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.randomize_va_space")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "2"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^kernel.randomize_va_space\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^kernel.randomize_va_space\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-83971-2"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*kernel.randomize_va_space.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83971-2
      - NIST-800-171-3.1.7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-SC-30
      - NIST-800-53-SC-30(2)
      - PCI-DSS-Req-2.2.1
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_kernel_randomize_va_space

    - name: Comment out any occurrences of kernel.randomize_va_space from config files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*kernel.randomize_va_space
        replace: '#kernel.randomize_va_space'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83971-2
      - NIST-800-171-3.1.7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-SC-30
      - NIST-800-53-SC-30(2)
      - PCI-DSS-Req-2.2.1
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_kernel_randomize_va_space

    - name: Ensure sysctl kernel.randomize_va_space is set to 2
      sysctl:
        name: kernel.randomize_va_space
        value: '2'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83971-2
      - NIST-800-171-3.1.7
      - NIST-800-53-CM-6(a)
      - NIST-800-53-SC-30
      - NIST-800-53-SC-30(2)
      - PCI-DSS-Req-2.2.1
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_kernel_randomize_va_space

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,kernel.randomize_va_space%3D2%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_kernel_randomize_va_space.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_kernel_randomize_va_space:def:1

Class:

compliance

Title:

Enable Randomized Layout of Virtual Address Space

Version:

3

Description:

The 'kernel.randomize_va_space' kernel parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_kernel_randomize_va_space:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Disable Accepting ICMP Redirects for All IPv4 Interfaces medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_all_accept_redirects
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:21+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84011-6

References:

BP28(R22), 1, 11, 12, 13, 14, 15, 16, 2, 3, 7, 8, 9, 5.10.1.1, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS03.05, DSS05.02, DSS05.05, DSS05.07, DSS06.06, 3.1.20, CCI-000366, CCI-001503, CCI-001551, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 6.2, SR 7.1, SR 7.2, SR 7.6, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), SC-7(a), DE.CM-1, PR.DS-4, PR.IP-1, PR.PT-3, SRG-OS-000480-GPOS-00227, 3.3.2
Description:
To set the runtime status of the `net.ipv4.conf.all.accept_redirects` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv4.conf.all.accept_redirects=0

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv4.conf.all.accept_redirects = 0

Rationale:

ICMP redirect messages are used by routers to inform hosts that a more direct route exists for a particular destination. These messages modify the host's route table and are unauthenticated. An illicit ICMP redirect message could result in a man-in-the-middle attack.
This feature of the IPv4 protocol has few legitimate uses. It should be disabled unless absolutely required."

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv4.conf.all.accept_redirects"
    /tmp/oscap.iAdibX/fix-XXn1ktBt: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.iAdibX/fix-XXn1ktBt: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv4.conf.all.accept_redirects from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.accept_redirects.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv4.conf.all.accept_redirects" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv4_conf_all_accept_redirects_value='0'

    #
    # Set runtime for net.ipv4.conf.all.accept_redirects
    #
    /sbin/sysctl -q -n -w net.ipv4.conf.all.accept_redirects="$sysctl_net_ipv4_conf_all_accept_redirects_value"

    #
    # If net.ipv4.conf.all.accept_redirects present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv4.conf.all.accept_redirects = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.accept_redirects")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_accept_redirects_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.accept_redirects\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv4.conf.all.accept_redirects\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84011-6"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv4.conf.all.accept_redirects.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84011-6
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_all_accept_redirects

    - name: Comment out any occurrences of net.ipv4.conf.all.accept_redirects from config
        files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv4.conf.all.accept_redirects
        replace: '#net.ipv4.conf.all.accept_redirects'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84011-6
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_all_accept_redirects
    - name: XCCDF Value sysctl_net_ipv4_conf_all_accept_redirects_value # promote to variable
      set_fact:
        sysctl_net_ipv4_conf_all_accept_redirects_value: !!str 0
      tags:
        - always

    - name: Ensure sysctl net.ipv4.conf.all.accept_redirects is set
      sysctl:
        name: net.ipv4.conf.all.accept_redirects
        value: '{{ sysctl_net_ipv4_conf_all_accept_redirects_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84011-6
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_all_accept_redirects

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv4.conf.all.accept_redirects%3D0%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_all_accept_redirects.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv4_conf_all_accept_redirects:def:1

Class:

compliance

Title:

Disable Accepting ICMP Redirects for All IPv4 Interfaces

Version:

3

Description:

The 'net.ipv4.conf.all.accept_redirects' kernel parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv4_conf_all_accept_redirects:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_all_accept_source_route
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:21+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84001-7

References:

BP28(R22), 1, 11, 12, 13, 14, 15, 16, 18, 2, 3, 4, 6, 7, 8, 9, APO01.06, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.06, 3.1.20, CCI-000366, 4.2.3.4, 4.3.3.4, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, 4.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-007-3 R4, CIP-007-3 R4.1, CIP-007-3 R4.2, CIP-007-3 R5.1, CM-7(a), CM-7(b), SC-5, CM-6(a), SC-7(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000480-GPOS-00227, 3.3.1
Description:
To set the runtime status of the `net.ipv4.conf.all.accept_source_route` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv4.conf.all.accept_source_route=0

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv4.conf.all.accept_source_route = 0

Rationale:

Source-routed packets allow the source of the packet to suggest routers forward the packet along a different path than configured on the router, which can be used to bypass network security measures. This requirement applies only to the forwarding of source-routerd traffic, such as when IPv4 forwarding is enabled and the system is functioning as a router.
Accepting source-routed packets in the IPv4 protocol has few legitimate uses. It should be disabled unless it is absolutely required.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv4.conf.all.accept_source_route"
    /tmp/oscap.15O4m1/fix-XXVyGF4i: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.15O4m1/fix-XXVyGF4i: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv4.conf.all.accept_source_route from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.accept_source_route.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv4.conf.all.accept_source_route" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv4_conf_all_accept_source_route_value='0'

    #
    # Set runtime for net.ipv4.conf.all.accept_source_route
    #
    /sbin/sysctl -q -n -w net.ipv4.conf.all.accept_source_route="$sysctl_net_ipv4_conf_all_accept_source_route_value"

    #
    # If net.ipv4.conf.all.accept_source_route present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv4.conf.all.accept_source_route = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.accept_source_route")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_accept_source_route_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.accept_source_route\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv4.conf.all.accept_source_route\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84001-7"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv4.conf.all.accept_source_route.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84001-7
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_all_accept_source_route

    - name: Comment out any occurrences of net.ipv4.conf.all.accept_source_route from
        config files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv4.conf.all.accept_source_route
        replace: '#net.ipv4.conf.all.accept_source_route'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84001-7
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_all_accept_source_route
    - name: XCCDF Value sysctl_net_ipv4_conf_all_accept_source_route_value # promote to variable
      set_fact:
        sysctl_net_ipv4_conf_all_accept_source_route_value: !!str 0
      tags:
        - always

    - name: Ensure sysctl net.ipv4.conf.all.accept_source_route is set
      sysctl:
        name: net.ipv4.conf.all.accept_source_route
        value: '{{ sysctl_net_ipv4_conf_all_accept_source_route_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84001-7
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_all_accept_source_route

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv4.conf.all.accept_source_route%3D0%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_all_accept_source_route.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv4_conf_all_accept_source_route:def:1

Class:

compliance

Title:

Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces

Version:

3

Description:

The 'net.ipv4.conf.all.accept_source_route' kernel parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv4_conf_all_accept_source_route:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces unknown fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_all_log_martians
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:21+01:00
Weight: | 1.0
Severity:

unknown

Identifiers:

CCE-84000-9

References:

BP28(R22), 1, 11, 12, 13, 14, 15, 16, 2, 3, 7, 8, 9, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.04, DSS03.05, DSS05.02, DSS05.03, DSS05.05, DSS05.07, DSS06.06, 3.1.20, CCI-000126, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.2, SR 7.1, SR 7.2, SR 7.6, A.11.2.6, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.6.2.1, A.6.2.2, A.9.1.2, CM-7(a), CM-7(b), SC-5(3)(a), DE.CM-1, PR.AC-3, PR.DS-4, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000480-GPOS-00227, 3.3.4
Description:
To set the runtime status of the `net.ipv4.conf.all.log_martians` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv4.conf.all.log_martians=1

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv4.conf.all.log_martians = 1

Rationale:

The presence of "martian" packets (which have impossible addresses) as well as spoofed packets, source-routed packets, and redirects could be a sign of nefarious network activity. Logging these packets enables this activity to be detected.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv4.conf.all.log_martians"
    /tmp/oscap.B2lMFA/fix-XXAREgI1: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.B2lMFA/fix-XXAREgI1: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv4.conf.all.log_martians from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.log_martians.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv4.conf.all.log_martians" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv4_conf_all_log_martians_value='1'

    #
    # Set runtime for net.ipv4.conf.all.log_martians
    #
    /sbin/sysctl -q -n -w net.ipv4.conf.all.log_martians="$sysctl_net_ipv4_conf_all_log_martians_value"

    #
    # If net.ipv4.conf.all.log_martians present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv4.conf.all.log_martians = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.log_martians")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_log_martians_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.log_martians\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv4.conf.all.log_martians\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84000-9"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv4.conf.all.log_martians.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84000-9
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5(3)(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - reboot_required
      - sysctl_net_ipv4_conf_all_log_martians
      - unknown_severity

    - name: Comment out any occurrences of net.ipv4.conf.all.log_martians from config
        files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv4.conf.all.log_martians
        replace: '#net.ipv4.conf.all.log_martians'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84000-9
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5(3)(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - reboot_required
      - sysctl_net_ipv4_conf_all_log_martians
      - unknown_severity
    - name: XCCDF Value sysctl_net_ipv4_conf_all_log_martians_value # promote to variable
      set_fact:
        sysctl_net_ipv4_conf_all_log_martians_value: !!str 1
      tags:
        - always

    - name: Ensure sysctl net.ipv4.conf.all.log_martians is set
      sysctl:
        name: net.ipv4.conf.all.log_martians
        value: '{{ sysctl_net_ipv4_conf_all_log_martians_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84000-9
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5(3)(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - reboot_required
      - sysctl_net_ipv4_conf_all_log_martians
      - unknown_severity

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv4.conf.all.log_martians%3D1%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_all_log_martians.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv4_conf_all_log_martians:def:1

Class:

compliance

Title:

Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces

Version:

3

Description:

The 'net.ipv4.conf.all.log_martians' kernel parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv4_conf_all_log_martians:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_all_rp_filter
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:21+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84008-2

References:

BP28(R22), 1, 12, 13, 14, 15, 16, 18, 2, 4, 6, 7, 8, 9, APO01.06, APO13.01, BAI04.04, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.07, DSS06.02, 3.1.20, CCI-000366, CCI-001551, 4.2.3.4, 4.3.3.4, 4.4.3.3, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-7(a), CM-7(b), CM-6(a), SC-7(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.PT-4, Req-1.4.3, SRG-OS-000480-GPOS-00227, 3.3.7
Description:
To set the runtime status of the `net.ipv4.conf.all.rp_filter` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv4.conf.all.rp_filter=1

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv4.conf.all.rp_filter = 1

Rationale:

Enabling reverse path filtering drops packets with source addresses that should not have been able to be received on the interface they were received on. It should not be used on systems which are routers for complicated networks, but is helpful for end hosts and routers serving small networks.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv4.conf.all.rp_filter"
    /tmp/oscap.T8QjoC/fix-XXS8yYey: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.T8QjoC/fix-XXS8yYey: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv4.conf.all.rp_filter from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.rp_filter.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv4.conf.all.rp_filter" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv4_conf_all_rp_filter_value='1'

    #
    # Set runtime for net.ipv4.conf.all.rp_filter
    #
    /sbin/sysctl -q -n -w net.ipv4.conf.all.rp_filter="$sysctl_net_ipv4_conf_all_rp_filter_value"

    #
    # If net.ipv4.conf.all.rp_filter present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv4.conf.all.rp_filter = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.rp_filter")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_rp_filter_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.rp_filter\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv4.conf.all.rp_filter\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84008-2"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv4.conf.all.rp_filter.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84008-2
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-7(a)
      - PCI-DSS-Req-1.4.3
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_all_rp_filter

    - name: Comment out any occurrences of net.ipv4.conf.all.rp_filter from config files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv4.conf.all.rp_filter
        replace: '#net.ipv4.conf.all.rp_filter'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84008-2
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-7(a)
      - PCI-DSS-Req-1.4.3
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_all_rp_filter
    - name: XCCDF Value sysctl_net_ipv4_conf_all_rp_filter_value # promote to variable
      set_fact:
        sysctl_net_ipv4_conf_all_rp_filter_value: !!str 1
      tags:
        - always

    - name: Ensure sysctl net.ipv4.conf.all.rp_filter is set
      sysctl:
        name: net.ipv4.conf.all.rp_filter
        value: '{{ sysctl_net_ipv4_conf_all_rp_filter_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84008-2
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-7(a)
      - PCI-DSS-Req-1.4.3
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_all_rp_filter

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv4.conf.all.rp_filter%3D1%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_all_rp_filter.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv4_conf_all_rp_filter:def:1

Class:

compliance

Title:

Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces

Version:

3

Description:

The 'net.ipv4.conf.all.rp_filter' kernel parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv4_conf_all_rp_filter:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_all_secure_redirects
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:21+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84016-5

References:

BP28(R22), 1, 11, 12, 13, 14, 15, 16, 18, 2, 3, 4, 6, 7, 8, 9, APO01.06, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.06, 3.1.20, CCI-001503, CCI-001551, 4.2.3.4, 4.3.3.4, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, 4.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-7(a), CM-7(b), CM-6(a), SC-7(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.IP-1, PR.PT-3, PR.PT-4, Req-1.4.3, SRG-OS-000480-GPOS-00227, 3.3.3
Description:
To set the runtime status of the `net.ipv4.conf.all.secure_redirects` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv4.conf.all.secure_redirects=0

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv4.conf.all.secure_redirects = 0

Rationale:

Accepting "secure" ICMP redirects (from those gateways listed as default gateways) has few legitimate uses. It should be disabled unless it is absolutely required.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv4.conf.all.secure_redirects"
    /tmp/oscap.8e49ea/fix-XXgk7FVg: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.8e49ea/fix-XXgk7FVg: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv4.conf.all.secure_redirects from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.secure_redirects.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv4.conf.all.secure_redirects" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv4_conf_all_secure_redirects_value='0'

    #
    # Set runtime for net.ipv4.conf.all.secure_redirects
    #
    /sbin/sysctl -q -n -w net.ipv4.conf.all.secure_redirects="$sysctl_net_ipv4_conf_all_secure_redirects_value"

    #
    # If net.ipv4.conf.all.secure_redirects present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv4.conf.all.secure_redirects = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.secure_redirects")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_secure_redirects_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.secure_redirects\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv4.conf.all.secure_redirects\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84016-5"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv4.conf.all.secure_redirects.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84016-5
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-7(a)
      - PCI-DSS-Req-1.4.3
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_all_secure_redirects

    - name: Comment out any occurrences of net.ipv4.conf.all.secure_redirects from config
        files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv4.conf.all.secure_redirects
        replace: '#net.ipv4.conf.all.secure_redirects'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84016-5
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-7(a)
      - PCI-DSS-Req-1.4.3
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_all_secure_redirects
    - name: XCCDF Value sysctl_net_ipv4_conf_all_secure_redirects_value # promote to variable
      set_fact:
        sysctl_net_ipv4_conf_all_secure_redirects_value: !!str 0
      tags:
        - always

    - name: Ensure sysctl net.ipv4.conf.all.secure_redirects is set
      sysctl:
        name: net.ipv4.conf.all.secure_redirects
        value: '{{ sysctl_net_ipv4_conf_all_secure_redirects_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84016-5
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-7(a)
      - PCI-DSS-Req-1.4.3
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_all_secure_redirects

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv4.conf.all.secure_redirects%3D0%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_all_secure_redirects.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv4_conf_all_secure_redirects:def:1

Class:

compliance

Title:

Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces

Version:

3

Description:

The 'net.ipv4.conf.all.secure_redirects' kernel parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv4_conf_all_secure_redirects:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_all_send_redirects
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83997-7

References:

BP28(R22), 1, 11, 12, 13, 14, 15, 16, 18, 2, 3, 4, 6, 7, 8, 9, 5.10.1.1, APO01.06, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.06, 3.1.20, CCI-000366, 4.2.3.4, 4.3.3.4, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, 4.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-007-3 R4, CIP-007-3 R4.1, CIP-007-3 R4.2, CIP-007-3 R5.1, CM-7(a), CM-7(b), SC-5, CM-6(a), SC-7(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000480-GPOS-00227, 3.2.2
Description:
To set the runtime status of the `net.ipv4.conf.all.send_redirects` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv4.conf.all.send_redirects=0

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv4.conf.all.send_redirects = 0

Rationale:

ICMP redirect messages are used by routers to inform hosts that a more direct route exists for a particular destination. These messages contain information from the system's route table possibly revealing portions of the network topology.
The ability to send ICMP redirects is only appropriate for systems acting as routers.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv4.conf.all.send_redirects"
    /tmp/oscap.04GEP2/fix-XXAsRksn: line 50: /etc/sysctl.conf: Permission denied
    /tmp/oscap.04GEP2/fix-XXAsRksn: line 51: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv4.conf.all.send_redirects from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.all.send_redirects.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv4.conf.all.send_redirects" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done

    #
    # Set runtime for net.ipv4.conf.all.send_redirects
    #
    /sbin/sysctl -q -n -w net.ipv4.conf.all.send_redirects="0"

    #
    # If net.ipv4.conf.all.send_redirects present in /etc/sysctl.conf, change value to "0"
    #	else, add "net.ipv4.conf.all.send_redirects = 0" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.all.send_redirects")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "0"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.all.send_redirects\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv4.conf.all.send_redirects\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-83997-7"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv4.conf.all.send_redirects.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83997-7
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_all_send_redirects

    - name: Comment out any occurrences of net.ipv4.conf.all.send_redirects from config
        files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv4.conf.all.send_redirects
        replace: '#net.ipv4.conf.all.send_redirects'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83997-7
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_all_send_redirects

    - name: Ensure sysctl net.ipv4.conf.all.send_redirects is set to 0
      sysctl:
        name: net.ipv4.conf.all.send_redirects
        value: '0'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83997-7
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_all_send_redirects

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv4.conf.all.send_redirects%3D0%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_all_send_redirects.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv4_conf_all_send_redirects:def:1

Class:

compliance

Title:

Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces

Version:

3

Description:

The 'net.ipv4.conf.all.send_redirects' kernel parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv4_conf_all_send_redirects:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_default_accept_redirects
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:21+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84003-3

References:

BP28(R22), 1, 11, 12, 13, 14, 15, 16, 18, 2, 3, 4, 6, 7, 8, 9, 5.10.1.1, APO01.06, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.06, 3.1.20, CCI-000366, CCI-001551, 4.2.3.4, 4.3.3.4, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, 4.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-7(a), CM-7(b), CM-6(a), SC-7(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.IP-1, PR.PT-3, PR.PT-4, Req-1.4.3, SRG-OS-000480-GPOS-00227, 3.3.2
Description:
To set the runtime status of the `net.ipv4.conf.default.accept_redirects` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv4.conf.default.accept_redirects=0

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv4.conf.default.accept_redirects = 0

Rationale:

ICMP redirect messages are used by routers to inform hosts that a more direct route exists for a particular destination. These messages modify the host's route table and are unauthenticated. An illicit ICMP redirect message could result in a man-in-the-middle attack.
This feature of the IPv4 protocol has few legitimate uses. It should be disabled unless absolutely required.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv4.conf.default.accept_redirects"
    /tmp/oscap.9IQOh0/fix-XXuwVm6I: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.9IQOh0/fix-XXuwVm6I: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv4.conf.default.accept_redirects from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.accept_redirects.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv4.conf.default.accept_redirects" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv4_conf_default_accept_redirects_value='0'

    #
    # Set runtime for net.ipv4.conf.default.accept_redirects
    #
    /sbin/sysctl -q -n -w net.ipv4.conf.default.accept_redirects="$sysctl_net_ipv4_conf_default_accept_redirects_value"

    #
    # If net.ipv4.conf.default.accept_redirects present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv4.conf.default.accept_redirects = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.accept_redirects")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_accept_redirects_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.accept_redirects\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv4.conf.default.accept_redirects\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84003-3"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv4.conf.default.accept_redirects.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84003-3
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-7(a)
      - PCI-DSS-Req-1.4.3
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_default_accept_redirects

    - name: Comment out any occurrences of net.ipv4.conf.default.accept_redirects from
        config files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv4.conf.default.accept_redirects
        replace: '#net.ipv4.conf.default.accept_redirects'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84003-3
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-7(a)
      - PCI-DSS-Req-1.4.3
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_default_accept_redirects
    - name: XCCDF Value sysctl_net_ipv4_conf_default_accept_redirects_value # promote to variable
      set_fact:
        sysctl_net_ipv4_conf_default_accept_redirects_value: !!str 0
      tags:
        - always

    - name: Ensure sysctl net.ipv4.conf.default.accept_redirects is set
      sysctl:
        name: net.ipv4.conf.default.accept_redirects
        value: '{{ sysctl_net_ipv4_conf_default_accept_redirects_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84003-3
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-7(a)
      - PCI-DSS-Req-1.4.3
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_default_accept_redirects

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv4.conf.default.accept_redirects%3D0%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_default_accept_redirects.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv4_conf_default_accept_redirects:def:1

Class:

compliance

Title:

Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces

Version:

3

Description:

The 'net.ipv4.conf.default.accept_redirects' kernel parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv4_conf_default_accept_redirects:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces by Default medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_default_accept_source_route
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:21+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84007-4

References:

BP28(R22), 1, 11, 12, 13, 14, 15, 16, 18, 2, 3, 4, 6, 7, 8, 9, 5.10.1.1, APO01.06, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.06, 3.1.20, CCI-000366, CCI-001551, 4.2.3.4, 4.3.3.4, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, 4.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-007-3 R4, CIP-007-3 R4.1, CIP-007-3 R4.2, CIP-007-3 R5.1, CM-7(a), CM-7(b), SC-5, SC-7(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000480-GPOS-00227, 3.3.1
Description:
To set the runtime status of the `net.ipv4.conf.default.accept_source_route` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv4.conf.default.accept_source_route=0

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv4.conf.default.accept_source_route = 0

Rationale:

Source-routed packets allow the source of the packet to suggest routers forward the packet along a different path than configured on the router, which can be used to bypass network security measures.
Accepting source-routed packets in the IPv4 protocol has few legitimate uses. It should be disabled unless it is absolutely required, such as when IPv4 forwarding is enabled and the system is legitimately functioning as a router.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv4.conf.default.accept_source_route"
    /tmp/oscap.1fqDGF/fix-XXvnPQGj: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.1fqDGF/fix-XXvnPQGj: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv4.conf.default.accept_source_route from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.accept_source_route.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv4.conf.default.accept_source_route" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv4_conf_default_accept_source_route_value='0'

    #
    # Set runtime for net.ipv4.conf.default.accept_source_route
    #
    /sbin/sysctl -q -n -w net.ipv4.conf.default.accept_source_route="$sysctl_net_ipv4_conf_default_accept_source_route_value"

    #
    # If net.ipv4.conf.default.accept_source_route present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv4.conf.default.accept_source_route = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.accept_source_route")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_accept_source_route_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.accept_source_route\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv4.conf.default.accept_source_route\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84007-4"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv4.conf.default.accept_source_route.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84007-4
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_default_accept_source_route

    - name: Comment out any occurrences of net.ipv4.conf.default.accept_source_route from
        config files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv4.conf.default.accept_source_route
        replace: '#net.ipv4.conf.default.accept_source_route'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84007-4
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_default_accept_source_route
    - name: XCCDF Value sysctl_net_ipv4_conf_default_accept_source_route_value # promote to variable
      set_fact:
        sysctl_net_ipv4_conf_default_accept_source_route_value: !!str 0
      tags:
        - always

    - name: Ensure sysctl net.ipv4.conf.default.accept_source_route is set
      sysctl:
        name: net.ipv4.conf.default.accept_source_route
        value: '{{ sysctl_net_ipv4_conf_default_accept_source_route_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84007-4
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_default_accept_source_route

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv4.conf.default.accept_source_route%3D0%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_default_accept_source_route.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv4_conf_default_accept_source_route:def:1

Class:

compliance

Title:

Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces by Default

Version:

3

Description:

The 'net.ipv4.conf.default.accept_source_route' kernel parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv4_conf_default_accept_source_route:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default unknown fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_default_log_martians
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

unknown

Identifiers:

CCE-84014-0

References:

1, 11, 12, 13, 14, 15, 16, 2, 3, 7, 8, 9, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.04, DSS03.05, DSS05.02, DSS05.03, DSS05.05, DSS05.07, DSS06.06, 3.1.20, CCI-000126, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.2, SR 7.1, SR 7.2, SR 7.6, A.11.2.6, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.6.2.1, A.6.2.2, A.9.1.2, CM-7(a), CM-7(b), SC-5(3)(a), DE.CM-1, PR.AC-3, PR.DS-4, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000480-GPOS-00227, 3.3.4
Description:
To set the runtime status of the `net.ipv4.conf.default.log_martians` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv4.conf.default.log_martians=1

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv4.conf.default.log_martians = 1

Rationale:

The presence of "martian" packets (which have impossible addresses) as well as spoofed packets, source-routed packets, and redirects could be a sign of nefarious network activity. Logging these packets enables this activity to be detected.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv4.conf.default.log_martians"
    /tmp/oscap.8SzTKG/fix-XXkYtrGZ: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.8SzTKG/fix-XXkYtrGZ: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv4.conf.default.log_martians from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.log_martians.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv4.conf.default.log_martians" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv4_conf_default_log_martians_value='1'

    #
    # Set runtime for net.ipv4.conf.default.log_martians
    #
    /sbin/sysctl -q -n -w net.ipv4.conf.default.log_martians="$sysctl_net_ipv4_conf_default_log_martians_value"

    #
    # If net.ipv4.conf.default.log_martians present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv4.conf.default.log_martians = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.log_martians")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_log_martians_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.log_martians\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv4.conf.default.log_martians\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84014-0"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv4.conf.default.log_martians.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84014-0
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5(3)(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - reboot_required
      - sysctl_net_ipv4_conf_default_log_martians
      - unknown_severity

    - name: Comment out any occurrences of net.ipv4.conf.default.log_martians from config
        files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv4.conf.default.log_martians
        replace: '#net.ipv4.conf.default.log_martians'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84014-0
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5(3)(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - reboot_required
      - sysctl_net_ipv4_conf_default_log_martians
      - unknown_severity
    - name: XCCDF Value sysctl_net_ipv4_conf_default_log_martians_value # promote to variable
      set_fact:
        sysctl_net_ipv4_conf_default_log_martians_value: !!str 1
      tags:
        - always

    - name: Ensure sysctl net.ipv4.conf.default.log_martians is set
      sysctl:
        name: net.ipv4.conf.default.log_martians
        value: '{{ sysctl_net_ipv4_conf_default_log_martians_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84014-0
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5(3)(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - reboot_required
      - sysctl_net_ipv4_conf_default_log_martians
      - unknown_severity

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv4.conf.default.log_martians%3D1%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_default_log_martians.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv4_conf_default_log_martians:def:1

Class:

compliance

Title:

Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default

Version:

3

Description:

The 'net.ipv4.conf.default.log_martians' kernel parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv4_conf_default_log_martians:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces by Default medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_default_rp_filter
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84009-0

References:

BP28(R22), 1, 12, 13, 14, 15, 16, 18, 2, 4, 6, 7, 8, 9, APO01.06, APO13.01, BAI04.04, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.07, DSS06.02, 3.1.20, CCI-000366, 4.2.3.4, 4.3.3.4, 4.4.3.3, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-7(a), CM-7(b), CM-6(a), SC-7(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.PT-4, SRG-OS-000480-GPOS-00227, 3.3.7
Description:
To set the runtime status of the `net.ipv4.conf.default.rp_filter` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv4.conf.default.rp_filter=1

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv4.conf.default.rp_filter = 1

Rationale:

Enabling reverse path filtering drops packets with source addresses that should not have been able to be received on the interface they were received on. It should not be used on systems which are routers for complicated networks, but is helpful for end hosts and routers serving small networks.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv4.conf.default.rp_filter"
    /tmp/oscap.aAWCV3/fix-XXmleTVV: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.aAWCV3/fix-XXmleTVV: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv4.conf.default.rp_filter from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.rp_filter.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv4.conf.default.rp_filter" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv4_conf_default_rp_filter_value='1'

    #
    # Set runtime for net.ipv4.conf.default.rp_filter
    #
    /sbin/sysctl -q -n -w net.ipv4.conf.default.rp_filter="$sysctl_net_ipv4_conf_default_rp_filter_value"

    #
    # If net.ipv4.conf.default.rp_filter present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv4.conf.default.rp_filter = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.rp_filter")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_rp_filter_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.rp_filter\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv4.conf.default.rp_filter\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84009-0"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv4.conf.default.rp_filter.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84009-0
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_default_rp_filter

    - name: Comment out any occurrences of net.ipv4.conf.default.rp_filter from config
        files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv4.conf.default.rp_filter
        replace: '#net.ipv4.conf.default.rp_filter'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84009-0
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_default_rp_filter
    - name: XCCDF Value sysctl_net_ipv4_conf_default_rp_filter_value # promote to variable
      set_fact:
        sysctl_net_ipv4_conf_default_rp_filter_value: !!str 1
      tags:
        - always

    - name: Ensure sysctl net.ipv4.conf.default.rp_filter is set
      sysctl:
        name: net.ipv4.conf.default.rp_filter
        value: '{{ sysctl_net_ipv4_conf_default_rp_filter_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84009-0
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_default_rp_filter

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv4.conf.default.rp_filter%3D1%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_default_rp_filter.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv4_conf_default_rp_filter:def:1

Class:

compliance

Title:

Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces by Default

Version:

3

Description:

The 'net.ipv4.conf.default.rp_filter' kernel parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv4_conf_default_rp_filter:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Configure Kernel Parameter for Accepting Secure Redirects By Default medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_default_secure_redirects
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84019-9

References:

BP28(R22), 1, 11, 12, 13, 14, 15, 16, 18, 2, 3, 4, 6, 7, 8, 9, APO01.06, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.06, 3.1.20, CCI-001551, 4.2.3.4, 4.3.3.4, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, 4.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-007-3 R4, CIP-007-3 R4.1, CIP-007-3 R4.2, CIP-007-3 R5.1, CM-7(a), CM-7(b), SC-5, SC-7(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000480-GPOS-00227, 3.3.3
Description:
To set the runtime status of the `net.ipv4.conf.default.secure_redirects` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv4.conf.default.secure_redirects=0

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv4.conf.default.secure_redirects = 0

Rationale:

Accepting "secure" ICMP redirects (from those gateways listed as default gateways) has few legitimate uses. It should be disabled unless it is absolutely required.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv4.conf.default.secure_redirects"
    /tmp/oscap.ONxWcV/fix-XXKyXDxY: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.ONxWcV/fix-XXKyXDxY: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv4.conf.default.secure_redirects from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.secure_redirects.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv4.conf.default.secure_redirects" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv4_conf_default_secure_redirects_value='0'

    #
    # Set runtime for net.ipv4.conf.default.secure_redirects
    #
    /sbin/sysctl -q -n -w net.ipv4.conf.default.secure_redirects="$sysctl_net_ipv4_conf_default_secure_redirects_value"

    #
    # If net.ipv4.conf.default.secure_redirects present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv4.conf.default.secure_redirects = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.secure_redirects")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_secure_redirects_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.secure_redirects\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv4.conf.default.secure_redirects\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84019-9"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv4.conf.default.secure_redirects.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84019-9
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_default_secure_redirects

    - name: Comment out any occurrences of net.ipv4.conf.default.secure_redirects from
        config files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv4.conf.default.secure_redirects
        replace: '#net.ipv4.conf.default.secure_redirects'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84019-9
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_default_secure_redirects
    - name: XCCDF Value sysctl_net_ipv4_conf_default_secure_redirects_value # promote to variable
      set_fact:
        sysctl_net_ipv4_conf_default_secure_redirects_value: !!str 0
      tags:
        - always

    - name: Ensure sysctl net.ipv4.conf.default.secure_redirects is set
      sysctl:
        name: net.ipv4.conf.default.secure_redirects
        value: '{{ sysctl_net_ipv4_conf_default_secure_redirects_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84019-9
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_default_secure_redirects

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv4.conf.default.secure_redirects%3D0%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_default_secure_redirects.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv4_conf_default_secure_redirects:def:1

Class:

compliance

Title:

Configure Kernel Parameter for Accepting Secure Redirects By Default

Version:

3

Description:

The 'net.ipv4.conf.default.secure_redirects' kernel parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv4_conf_default_secure_redirects:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces by Default medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_default_send_redirects
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83999-3

References:

BP28(R22), 1, 11, 12, 13, 14, 15, 16, 18, 2, 3, 4, 6, 7, 8, 9, 5.10.1.1, APO01.06, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.06, 3.1.20, CCI-000366, 4.2.3.4, 4.3.3.4, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, 4.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-007-3 R4, CIP-007-3 R4.1, CIP-007-3 R4.2, CIP-007-3 R5.1, CM-7(a), CM-7(b), SC-5, CM-6(a), SC-7(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000480-GPOS-00227, 3.2.2
Description:
To set the runtime status of the `net.ipv4.conf.default.send_redirects` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv4.conf.default.send_redirects=0

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv4.conf.default.send_redirects = 0

Rationale:

ICMP redirect messages are used by routers to inform hosts that a more direct route exists for a particular destination. These messages contain information from the system's route table possibly revealing portions of the network topology.
The ability to send ICMP redirects is only appropriate for systems acting as routers.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv4.conf.default.send_redirects"
    /tmp/oscap.8seHui/fix-XXnPo0hI: line 50: /etc/sysctl.conf: Permission denied
    /tmp/oscap.8seHui/fix-XXnPo0hI: line 51: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv4.conf.default.send_redirects from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.conf.default.send_redirects.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv4.conf.default.send_redirects" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done

    #
    # Set runtime for net.ipv4.conf.default.send_redirects
    #
    /sbin/sysctl -q -n -w net.ipv4.conf.default.send_redirects="0"

    #
    # If net.ipv4.conf.default.send_redirects present in /etc/sysctl.conf, change value to "0"
    #	else, add "net.ipv4.conf.default.send_redirects = 0" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.conf.default.send_redirects")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "0"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.conf.default.send_redirects\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv4.conf.default.send_redirects\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-83999-3"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv4.conf.default.send_redirects.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83999-3
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_default_send_redirects

    - name: Comment out any occurrences of net.ipv4.conf.default.send_redirects from config
        files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv4.conf.default.send_redirects
        replace: '#net.ipv4.conf.default.send_redirects'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83999-3
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_default_send_redirects

    - name: Ensure sysctl net.ipv4.conf.default.send_redirects is set to 0
      sysctl:
        name: net.ipv4.conf.default.send_redirects
        value: '0'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83999-3
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - NIST-800-53-SC-7(a)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_conf_default_send_redirects

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv4.conf.default.send_redirects%3D0%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_default_send_redirects.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv4_conf_default_send_redirects:def:1

Class:

compliance

Title:

Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces by Default

Version:

3

Description:

The 'net.ipv4.conf.default.send_redirects' kernel parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv4_conf_default_send_redirects:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_icmp_echo_ignore_broadcasts
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84004-1

References:

1, 11, 12, 13, 14, 15, 16, 18, 2, 3, 4, 6, 7, 8, 9, 5.10.1.1, APO01.06, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.06, 3.1.20, CCI-000366, 4.2.3.4, 4.3.3.4, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, 4.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-007-3 R4, CIP-007-3 R4.1, CIP-007-3 R4.2, CIP-007-3 R5.1, CM-7(a), CM-7(b), SC-5, DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.IP-1, PR.PT-3, PR.PT-4, Req-1.4.3, SRG-OS-000480-GPOS-00227, 3.3.5
Description:
To set the runtime status of the `net.ipv4.icmp_echo_ignore_broadcasts` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv4.icmp_echo_ignore_broadcasts = 1

Rationale:

Responding to broadcast (ICMP) echoes facilitates network mapping and provides a vector for amplification attacks.
Ignoring ICMP echo requests (pings) sent to broadcast or multicast addresses makes the system slightly more difficult to enumerate on the network.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv4.icmp_echo_ignore_broadcasts"
    /tmp/oscap.AHnTtX/fix-XXbZf2oe: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.AHnTtX/fix-XXbZf2oe: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv4.icmp_echo_ignore_broadcasts from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.icmp_echo_ignore_broadcasts.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv4.icmp_echo_ignore_broadcasts" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value='1'

    #
    # Set runtime for net.ipv4.icmp_echo_ignore_broadcasts
    #
    /sbin/sysctl -q -n -w net.ipv4.icmp_echo_ignore_broadcasts="$sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value"

    #
    # If net.ipv4.icmp_echo_ignore_broadcasts present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv4.icmp_echo_ignore_broadcasts = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.icmp_echo_ignore_broadcasts")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.icmp_echo_ignore_broadcasts\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv4.icmp_echo_ignore_broadcasts\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84004-1"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84004-1
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - PCI-DSS-Req-1.4.3
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_icmp_echo_ignore_broadcasts

    - name: Comment out any occurrences of net.ipv4.icmp_echo_ignore_broadcasts from config
        files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts
        replace: '#net.ipv4.icmp_echo_ignore_broadcasts'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84004-1
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - PCI-DSS-Req-1.4.3
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_icmp_echo_ignore_broadcasts
    - name: XCCDF Value sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value # promote to variable
      set_fact:
        sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value: !!str 1
      tags:
        - always

    - name: Ensure sysctl net.ipv4.icmp_echo_ignore_broadcasts is set
      sysctl:
        name: net.ipv4.icmp_echo_ignore_broadcasts
        value: '{{ sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84004-1
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - PCI-DSS-Req-1.4.3
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_icmp_echo_ignore_broadcasts

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv4.icmp_echo_ignore_broadcasts%3D1%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv4_icmp_echo_ignore_broadcasts.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv4_icmp_echo_ignore_broadcasts:def:1

Class:

compliance

Title:

Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces

Version:

3

Description:

The 'net.ipv4.icmp_echo_ignore_broadcasts' kernel parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv4_icmp_echo_ignore_broadcasts:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces unknown fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_icmp_ignore_bogus_error_responses
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

unknown

Identifiers:

CCE-84015-7

References:

BP28(R22), 1, 11, 12, 13, 14, 15, 16, 2, 3, 7, 8, 9, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS03.05, DSS05.02, DSS05.05, DSS05.07, DSS06.06, 3.1.20, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 6.2, SR 7.1, SR 7.2, SR 7.6, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.9.1.2, CIP-007-3 R4, CIP-007-3 R4.1, CIP-007-3 R4.2, CIP-007-3 R5.1, CM-7(a), CM-7(b), SC-5, DE.CM-1, PR.DS-4, PR.IP-1, PR.PT-3, Req-1.4.3, SRG-OS-000480-GPOS-00227, 3.3.6
Description:
To set the runtime status of the `net.ipv4.icmp_ignore_bogus_error_responses` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv4.icmp_ignore_bogus_error_responses=1

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv4.icmp_ignore_bogus_error_responses = 1

Rationale:

Ignoring bogus ICMP error responses reduces log size, although some activity would not be logged.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv4.icmp_ignore_bogus_error_responses"
    /tmp/oscap.cswo9H/fix-XXY3WhaS: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.cswo9H/fix-XXY3WhaS: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv4.icmp_ignore_bogus_error_responses from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.icmp_ignore_bogus_error_responses.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv4.icmp_ignore_bogus_error_responses" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value='1'

    #
    # Set runtime for net.ipv4.icmp_ignore_bogus_error_responses
    #
    /sbin/sysctl -q -n -w net.ipv4.icmp_ignore_bogus_error_responses="$sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value"

    #
    # If net.ipv4.icmp_ignore_bogus_error_responses present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv4.icmp_ignore_bogus_error_responses = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.icmp_ignore_bogus_error_responses")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.icmp_ignore_bogus_error_responses\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv4.icmp_ignore_bogus_error_responses\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84015-7"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84015-7
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - PCI-DSS-Req-1.4.3
      - disable_strategy
      - low_complexity
      - medium_disruption
      - reboot_required
      - sysctl_net_ipv4_icmp_ignore_bogus_error_responses
      - unknown_severity

    - name: Comment out any occurrences of net.ipv4.icmp_ignore_bogus_error_responses
        from config files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses
        replace: '#net.ipv4.icmp_ignore_bogus_error_responses'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84015-7
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - PCI-DSS-Req-1.4.3
      - disable_strategy
      - low_complexity
      - medium_disruption
      - reboot_required
      - sysctl_net_ipv4_icmp_ignore_bogus_error_responses
      - unknown_severity
    - name: XCCDF Value sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value # promote to variable
      set_fact:
        sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value: !!str 1
      tags:
        - always

    - name: Ensure sysctl net.ipv4.icmp_ignore_bogus_error_responses is set
      sysctl:
        name: net.ipv4.icmp_ignore_bogus_error_responses
        value: '{{ sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84015-7
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - PCI-DSS-Req-1.4.3
      - disable_strategy
      - low_complexity
      - medium_disruption
      - reboot_required
      - sysctl_net_ipv4_icmp_ignore_bogus_error_responses
      - unknown_severity

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv4.icmp_ignore_bogus_error_responses%3D1%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv4_icmp_ignore_bogus_error_responses.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv4_icmp_ignore_bogus_error_responses:def:1

Class:

compliance

Title:

Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces

Version:

3

Description:

The 'net.ipv4.icmp_ignore_bogus_error_responses' kernel parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv4_icmp_ignore_bogus_error_responses:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_ip_forward
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-83998-5

References:

BP28(R22), 1, 11, 12, 13, 14, 15, 16, 2, 3, 7, 8, 9, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS03.05, DSS05.02, DSS05.05, DSS05.07, DSS06.06, 3.1.20, CCI-000366, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.2, SR 7.1, SR 7.2, SR 7.6, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.9.1.2, CIP-007-3 R4, CIP-007-3 R4.1, CIP-007-3 R4.2, CIP-007-3 R5.1, CM-7(a), CM-7(b), SC-5, CM-6(a), SC-7(a), DE.CM-1, PR.DS-4, PR.IP-1, PR.PT-3, PR.PT-4, Req-1.3.1, Req-1.3.2, SRG-OS-000480-GPOS-00227, 3.2.1
Description:
To set the runtime status of the `net.ipv4.ip_forward` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv4.ip_forward=0

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv4.ip_forward = 0

Rationale:

Routing protocol daemons are typically used on routers to exchange network topology information with other routers. If this capability is used when not required, system network information may be unnecessarily transmitted across the network.

Warnings:

Functionality warning
Certain technologies such as virtual machines, containers, etc. rely on IPv4 forwarding to enable and use networking. Disabling IPv4 forwarding would cause those technologies to stop working. Therefore, this rule should not be used in profiles or benchmarks that target usage of IPv4 forwarding.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv4.ip_forward"
    /tmp/oscap.8C1UGg/fix-XXpd74tE: line 50: /etc/sysctl.conf: Permission denied
    /tmp/oscap.8C1UGg/fix-XXpd74tE: line 51: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv4.ip_forward from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.ip_forward.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv4.ip_forward" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done

    #
    # Set runtime for net.ipv4.ip_forward
    #
    /sbin/sysctl -q -n -w net.ipv4.ip_forward="0"

    #
    # If net.ipv4.ip_forward present in /etc/sysctl.conf, change value to "0"
    #	else, add "net.ipv4.ip_forward = 0" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.ip_forward")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "0"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.ip_forward\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv4.ip_forward\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-83998-5"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv4.ip_forward.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83998-5
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - NIST-800-53-SC-7(a)
      - PCI-DSS-Req-1.3.1
      - PCI-DSS-Req-1.3.2
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_ip_forward

    - name: Comment out any occurrences of net.ipv4.ip_forward from config files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv4.ip_forward
        replace: '#net.ipv4.ip_forward'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83998-5
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - NIST-800-53-SC-7(a)
      - PCI-DSS-Req-1.3.1
      - PCI-DSS-Req-1.3.2
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_ip_forward

    - name: Ensure sysctl net.ipv4.ip_forward is set to 0
      sysctl:
        name: net.ipv4.ip_forward
        value: '0'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-83998-5
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5
      - NIST-800-53-SC-7(a)
      - PCI-DSS-Req-1.3.1
      - PCI-DSS-Req-1.3.2
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_ip_forward

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv4_ip_forward:def:1

Class:

compliance

Title:

Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces

Version:

3

Description:

The 'net.ipv4.ip_forward' kernel parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv4_ip_forward:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by group:
#machine
Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_tcp_syncookies
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:22+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84006-6

References:

BP28(R22), 1, 12, 13, 14, 15, 16, 18, 2, 4, 6, 7, 8, 9, 5.10.1.1, APO01.06, APO13.01, BAI04.04, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.07, DSS06.02, 3.1.20, CCI-000366, CCI-001095, 4.2.3.4, 4.3.3.4, 4.4.3.3, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-7(a), CM-7(b), SC-5(1), SC-5(2), SC-5(3)(a), CM-6(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.PT-4, Req-1.4.1, SRG-OS-000480-GPOS-00227, SRG-OS-000420-GPOS-00186, SRG-OS-000142-GPOS-00071, 3.3.8
Description:
To set the runtime status of the `net.ipv4.tcp_syncookies` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv4.tcp_syncookies=1

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv4.tcp_syncookies = 1

Rationale:

A TCP SYN flood attack can cause a denial of service by filling a system's TCP connection table with connections in the SYN_RCVD state. Syncookies can be used to track a connection when a subsequent ACK is received, verifying the initiator is attempting a valid connection and is not a flood source. This feature is activated when a flood condition is detected, and enables the system to continue servicing valid connection requests.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv4.tcp_syncookies"
    /tmp/oscap.3Jcw2p/fix-XX3DN6lv: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.3Jcw2p/fix-XX3DN6lv: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv4.tcp_syncookies from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv4.tcp_syncookies.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv4.tcp_syncookies" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv4_tcp_syncookies_value='1'

    #
    # Set runtime for net.ipv4.tcp_syncookies
    #
    /sbin/sysctl -q -n -w net.ipv4.tcp_syncookies="$sysctl_net_ipv4_tcp_syncookies_value"

    #
    # If net.ipv4.tcp_syncookies present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv4.tcp_syncookies = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv4.tcp_syncookies")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_tcp_syncookies_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv4.tcp_syncookies\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv4.tcp_syncookies\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84006-6"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv4.tcp_syncookies.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84006-6
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5(1)
      - NIST-800-53-SC-5(2)
      - NIST-800-53-SC-5(3)(a)
      - PCI-DSS-Req-1.4.1
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_tcp_syncookies

    - name: Comment out any occurrences of net.ipv4.tcp_syncookies from config files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv4.tcp_syncookies
        replace: '#net.ipv4.tcp_syncookies'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84006-6
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5(1)
      - NIST-800-53-SC-5(2)
      - NIST-800-53-SC-5(3)(a)
      - PCI-DSS-Req-1.4.1
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_tcp_syncookies
    - name: XCCDF Value sysctl_net_ipv4_tcp_syncookies_value # promote to variable
      set_fact:
        sysctl_net_ipv4_tcp_syncookies_value: !!str 1
      tags:
        - always

    - name: Ensure sysctl net.ipv4.tcp_syncookies is set
      sysctl:
        name: net.ipv4.tcp_syncookies
        value: '{{ sysctl_net_ipv4_tcp_syncookies_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84006-6
      - CJIS-5.10.1.1
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - NIST-800-53-SC-5(1)
      - NIST-800-53-SC-5(2)
      - NIST-800-53-SC-5(3)(a)
      - PCI-DSS-Req-1.4.1
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv4_tcp_syncookies

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv4.tcp_syncookies%3D1%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv4_tcp_syncookies.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv4_tcp_syncookies:def:1

Class:

compliance

Title:

Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces

Version:

3

Description:

The 'net.ipv4.tcp_syncookies' kernel parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv4_tcp_syncookies:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
Configure Accepting Router Advertisements on All IPv6 Interfaces medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv6_conf_all_accept_ra
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:21+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84120-5

References:

11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 3.1.20, CCI-000366, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3, SRG-OS-000480-GPOS-00227, 3.3.9
Description:
To set the runtime status of the `net.ipv6.conf.all.accept_ra` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv6.conf.all.accept_ra=0

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv6.conf.all.accept_ra = 0

Rationale:

An illicit router advertisement message could result in a man-in-the-middle attack.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv6.conf.all.accept_ra"
    /tmp/oscap.G5jKQm/fix-XXThjt83: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.G5jKQm/fix-XXThjt83: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv6.conf.all.accept_ra from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.accept_ra.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv6.conf.all.accept_ra" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv6_conf_all_accept_ra_value='0'

    #
    # Set runtime for net.ipv6.conf.all.accept_ra
    #
    /sbin/sysctl -q -n -w net.ipv6.conf.all.accept_ra="$sysctl_net_ipv6_conf_all_accept_ra_value"

    #
    # If net.ipv6.conf.all.accept_ra present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv6.conf.all.accept_ra = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.accept_ra")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_accept_ra_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.accept_ra\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv6.conf.all.accept_ra\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84120-5"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv6.conf.all.accept_ra.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84120-5
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_all_accept_ra

    - name: Comment out any occurrences of net.ipv6.conf.all.accept_ra from config files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv6.conf.all.accept_ra
        replace: '#net.ipv6.conf.all.accept_ra'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84120-5
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_all_accept_ra
    - name: XCCDF Value sysctl_net_ipv6_conf_all_accept_ra_value # promote to variable
      set_fact:
        sysctl_net_ipv6_conf_all_accept_ra_value: !!str 0
      tags:
        - always

    - name: Ensure sysctl net.ipv6.conf.all.accept_ra is set
      sysctl:
        name: net.ipv6.conf.all.accept_ra
        value: '{{ sysctl_net_ipv6_conf_all_accept_ra_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84120-5
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_all_accept_ra

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv6.conf.all.accept_ra%3D0%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv6_conf_all_accept_ra.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv6_conf_all_accept_ra:def:1

Class:

compliance

Title:

Configure Accepting Router Advertisements on All IPv6 Interfaces

Version:

4

Description:

The kernel 'net.ipv6.conf.all.accept_ra' parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv6_conf_all_accept_ra:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Disable Accepting ICMP Redirects for All IPv6 Interfaces medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv6_conf_all_accept_redirects
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:21+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84125-4

References:

BP28(R22), 11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 3.1.20, CCI-000366, CCI-001551, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), CM-6(b), CM-6.1(iv), PR.IP-1, PR.PT-3, SRG-OS-000480-GPOS-00227, 3.3.2
Description:
To set the runtime status of the `net.ipv6.conf.all.accept_redirects` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv6.conf.all.accept_redirects=0

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv6.conf.all.accept_redirects = 0

Rationale:

An illicit ICMP redirect message could result in a man-in-the-middle attack.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv6.conf.all.accept_redirects"
    /tmp/oscap.P4dIUK/fix-XXkI1s1t: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.P4dIUK/fix-XXkI1s1t: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv6.conf.all.accept_redirects from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.accept_redirects.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv6.conf.all.accept_redirects" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv6_conf_all_accept_redirects_value='0'

    #
    # Set runtime for net.ipv6.conf.all.accept_redirects
    #
    /sbin/sysctl -q -n -w net.ipv6.conf.all.accept_redirects="$sysctl_net_ipv6_conf_all_accept_redirects_value"

    #
    # If net.ipv6.conf.all.accept_redirects present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv6.conf.all.accept_redirects = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.accept_redirects")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_accept_redirects_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.accept_redirects\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv6.conf.all.accept_redirects\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84125-4"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv6.conf.all.accept_redirects.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84125-4
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-6(b)
      - NIST-800-53-CM-6.1(iv)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_all_accept_redirects

    - name: Comment out any occurrences of net.ipv6.conf.all.accept_redirects from config
        files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv6.conf.all.accept_redirects
        replace: '#net.ipv6.conf.all.accept_redirects'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84125-4
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-6(b)
      - NIST-800-53-CM-6.1(iv)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_all_accept_redirects
    - name: XCCDF Value sysctl_net_ipv6_conf_all_accept_redirects_value # promote to variable
      set_fact:
        sysctl_net_ipv6_conf_all_accept_redirects_value: !!str 0
      tags:
        - always

    - name: Ensure sysctl net.ipv6.conf.all.accept_redirects is set
      sysctl:
        name: net.ipv6.conf.all.accept_redirects
        value: '{{ sysctl_net_ipv6_conf_all_accept_redirects_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84125-4
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-6(b)
      - NIST-800-53-CM-6.1(iv)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_all_accept_redirects

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv6.conf.all.accept_redirects%3D0%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv6_conf_all_accept_redirects.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv6_conf_all_accept_redirects:def:1

Class:

compliance

Title:

Disable Accepting ICMP Redirects for All IPv6 Interfaces

Version:

4

Description:

The kernel 'net.ipv6.conf.all.accept_redirects' parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv6_conf_all_accept_redirects:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv6_conf_all_accept_source_route
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:21+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84131-2

References:

BP28(R22), 1, 12, 13, 14, 15, 16, 18, 4, 6, 8, 9, APO01.06, APO13.01, DSS01.05, DSS03.01, DSS05.02, DSS05.04, DSS05.07, DSS06.02, 3.1.20, CCI-000366, 4.2.3.4, 4.3.3.4, 4.4.3.3, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 7.1, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-7(a), CM-7(b), CM-6(a), DE.AE-1, ID.AM-3, PR.AC-5, PR.DS-5, PR.PT-4, SRG-OS-000480-GPOS-00227, 3.3.1
Description:
To set the runtime status of the `net.ipv6.conf.all.accept_source_route` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv6.conf.all.accept_source_route=0

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv6.conf.all.accept_source_route = 0

Rationale:

Source-routed packets allow the source of the packet to suggest routers forward the packet along a different path than configured on the router, which can be used to bypass network security measures. This requirement applies only to the forwarding of source-routerd traffic, such as when IPv6 forwarding is enabled and the system is functioning as a router.
Accepting source-routed packets in the IPv6 protocol has few legitimate uses. It should be disabled unless it is absolutely required.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv6.conf.all.accept_source_route"
    /tmp/oscap.zbSPGU/fix-XXtxixPA: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.zbSPGU/fix-XXtxixPA: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv6.conf.all.accept_source_route from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.accept_source_route.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv6.conf.all.accept_source_route" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv6_conf_all_accept_source_route_value='0'

    #
    # Set runtime for net.ipv6.conf.all.accept_source_route
    #
    /sbin/sysctl -q -n -w net.ipv6.conf.all.accept_source_route="$sysctl_net_ipv6_conf_all_accept_source_route_value"

    #
    # If net.ipv6.conf.all.accept_source_route present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv6.conf.all.accept_source_route = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.accept_source_route")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_accept_source_route_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.accept_source_route\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv6.conf.all.accept_source_route\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84131-2"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv6.conf.all.accept_source_route.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84131-2
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_all_accept_source_route

    - name: Comment out any occurrences of net.ipv6.conf.all.accept_source_route from
        config files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv6.conf.all.accept_source_route
        replace: '#net.ipv6.conf.all.accept_source_route'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84131-2
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_all_accept_source_route
    - name: XCCDF Value sysctl_net_ipv6_conf_all_accept_source_route_value # promote to variable
      set_fact:
        sysctl_net_ipv6_conf_all_accept_source_route_value: !!str 0
      tags:
        - always

    - name: Ensure sysctl net.ipv6.conf.all.accept_source_route is set
      sysctl:
        name: net.ipv6.conf.all.accept_source_route
        value: '{{ sysctl_net_ipv6_conf_all_accept_source_route_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84131-2
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_all_accept_source_route

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv6.conf.all.accept_source_route%3D0%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv6_conf_all_accept_source_route.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv6_conf_all_accept_source_route:def:1

Class:

compliance

Title:

Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces

Version:

4

Description:

The kernel 'net.ipv6.conf.all.accept_source_route' parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv6_conf_all_accept_source_route:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Disable Kernel Parameter for IPv6 Forwarding medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv6_conf_all_forwarding
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:21+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84114-8

References:

1, 11, 12, 13, 14, 15, 16, 2, 3, 7, 8, 9, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS03.05, DSS05.02, DSS05.05, DSS05.07, DSS06.06, CCI-000366, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 6.2, SR 7.1, SR 7.2, SR 7.6, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), CM-6(b), CM-6.1(iv), DE.CM-1, PR.DS-4, PR.IP-1, PR.PT-3, SRG-OS-000480-GPOS-00227, 3.2.1
Description:
To set the runtime status of the `net.ipv6.conf.all.forwarding` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv6.conf.all.forwarding=0

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv6.conf.all.forwarding = 0

Rationale:

IP forwarding permits the kernel to forward packets from one network interface to another. The ability to forward packets between two networks is only appropriate for systems acting as routers.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv6.conf.all.forwarding"
    /tmp/oscap.uu4htn/fix-XXc1A9Vl: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.uu4htn/fix-XXc1A9Vl: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv6.conf.all.forwarding from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.all.forwarding.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv6.conf.all.forwarding" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv6_conf_all_forwarding_value='0'

    #
    # Set runtime for net.ipv6.conf.all.forwarding
    #
    /sbin/sysctl -q -n -w net.ipv6.conf.all.forwarding="$sysctl_net_ipv6_conf_all_forwarding_value"

    #
    # If net.ipv6.conf.all.forwarding present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv6.conf.all.forwarding = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.all.forwarding")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_forwarding_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.all.forwarding\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv6.conf.all.forwarding\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84114-8"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv6.conf.all.forwarding.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84114-8
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-6(b)
      - NIST-800-53-CM-6.1(iv)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_all_forwarding

    - name: Comment out any occurrences of net.ipv6.conf.all.forwarding from config files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv6.conf.all.forwarding
        replace: '#net.ipv6.conf.all.forwarding'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84114-8
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-6(b)
      - NIST-800-53-CM-6.1(iv)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_all_forwarding
    - name: XCCDF Value sysctl_net_ipv6_conf_all_forwarding_value # promote to variable
      set_fact:
        sysctl_net_ipv6_conf_all_forwarding_value: !!str 0
      tags:
        - always

    - name: Ensure sysctl net.ipv6.conf.all.forwarding is set
      sysctl:
        name: net.ipv6.conf.all.forwarding
        value: '{{ sysctl_net_ipv6_conf_all_forwarding_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84114-8
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-6(b)
      - NIST-800-53-CM-6.1(iv)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_all_forwarding

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv6_conf_all_forwarding:def:1

Class:

compliance

Title:

Disable Kernel Parameter for IPv6 Forwarding

Version:

4

Description:

The kernel 'net.ipv6.conf.all.forwarding' parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv6_conf_all_forwarding:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Disable Accepting Router Advertisements on all IPv6 Interfaces by Default medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv6_conf_default_accept_ra
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:21+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84124-7

References:

11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 3.1.20, CCI-000366, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3, SRG-OS-000480-GPOS-00227, 3.3.9
Description:
To set the runtime status of the `net.ipv6.conf.default.accept_ra` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv6.conf.default.accept_ra=0

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv6.conf.default.accept_ra = 0

Rationale:

An illicit router advertisement message could result in a man-in-the-middle attack.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv6.conf.default.accept_ra"
    /tmp/oscap.92A0rT/fix-XXZT9iUy: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.92A0rT/fix-XXZT9iUy: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv6.conf.default.accept_ra from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.accept_ra.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv6.conf.default.accept_ra" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv6_conf_default_accept_ra_value='0'

    #
    # Set runtime for net.ipv6.conf.default.accept_ra
    #
    /sbin/sysctl -q -n -w net.ipv6.conf.default.accept_ra="$sysctl_net_ipv6_conf_default_accept_ra_value"

    #
    # If net.ipv6.conf.default.accept_ra present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv6.conf.default.accept_ra = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.accept_ra")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_accept_ra_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.accept_ra\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv6.conf.default.accept_ra\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84124-7"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv6.conf.default.accept_ra.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84124-7
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_default_accept_ra

    - name: Comment out any occurrences of net.ipv6.conf.default.accept_ra from config
        files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv6.conf.default.accept_ra
        replace: '#net.ipv6.conf.default.accept_ra'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84124-7
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_default_accept_ra
    - name: XCCDF Value sysctl_net_ipv6_conf_default_accept_ra_value # promote to variable
      set_fact:
        sysctl_net_ipv6_conf_default_accept_ra_value: !!str 0
      tags:
        - always

    - name: Ensure sysctl net.ipv6.conf.default.accept_ra is set
      sysctl:
        name: net.ipv6.conf.default.accept_ra
        value: '{{ sysctl_net_ipv6_conf_default_accept_ra_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84124-7
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_default_accept_ra

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv6.conf.default.accept_ra%3D0%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv6_conf_default_accept_ra.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv6_conf_default_accept_ra:def:1

Class:

compliance

Title:

Disable Accepting Router Advertisements on all IPv6 Interfaces by Default

Version:

4

Description:

The kernel 'net.ipv6.conf.default.accept_ra' parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv6_conf_default_accept_ra:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv6_conf_default_accept_redirects
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:21+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84113-0

References:

BP28(R22), 11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 3.1.20, CCI-000366, CCI-001551, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3, SRG-OS-000480-GPOS-00227, 3.3.2
Description:
To set the runtime status of the `net.ipv6.conf.default.accept_redirects` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv6.conf.default.accept_redirects=0

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv6.conf.default.accept_redirects = 0

Rationale:

An illicit ICMP redirect message could result in a man-in-the-middle attack.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv6.conf.default.accept_redirects"
    /tmp/oscap.DIGv9m/fix-XXsJxr78: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.DIGv9m/fix-XXsJxr78: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv6.conf.default.accept_redirects from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.accept_redirects.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv6.conf.default.accept_redirects" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv6_conf_default_accept_redirects_value='0'

    #
    # Set runtime for net.ipv6.conf.default.accept_redirects
    #
    /sbin/sysctl -q -n -w net.ipv6.conf.default.accept_redirects="$sysctl_net_ipv6_conf_default_accept_redirects_value"

    #
    # If net.ipv6.conf.default.accept_redirects present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv6.conf.default.accept_redirects = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.accept_redirects")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_accept_redirects_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.accept_redirects\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv6.conf.default.accept_redirects\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84113-0"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv6.conf.default.accept_redirects.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84113-0
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_default_accept_redirects

    - name: Comment out any occurrences of net.ipv6.conf.default.accept_redirects from
        config files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv6.conf.default.accept_redirects
        replace: '#net.ipv6.conf.default.accept_redirects'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84113-0
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_default_accept_redirects
    - name: XCCDF Value sysctl_net_ipv6_conf_default_accept_redirects_value # promote to variable
      set_fact:
        sysctl_net_ipv6_conf_default_accept_redirects_value: !!str 0
      tags:
        - always

    - name: Ensure sysctl net.ipv6.conf.default.accept_redirects is set
      sysctl:
        name: net.ipv6.conf.default.accept_redirects
        value: '{{ sysctl_net_ipv6_conf_default_accept_redirects_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84113-0
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_default_accept_redirects

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv6.conf.default.accept_redirects%20%3D%200%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv6_conf_default_accept_redirects.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv6_conf_default_accept_redirects:def:1

Class:

compliance

Title:

Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces

Version:

4

Description:

The kernel 'net.ipv6.conf.default.accept_redirects' parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv6_conf_default_accept_redirects:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces by Default medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_sysctl_net_ipv6_conf_default_accept_source_route
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:21+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-84130-4

References:

BP28(R22), 1, 12, 13, 14, 15, 16, 18, 4, 6, 8, 9, APO01.06, APO13.01, DSS01.05, DSS03.01, DSS05.02, DSS05.04, DSS05.07, DSS06.02, 3.1.20, CCI-000366, 4.2.3.4, 4.3.3.4, 4.4.3.3, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 7.1, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-7(a), CM-7(b), CM-6(a), CM-6(b), CM-6.1(iv), DE.AE-1, ID.AM-3, PR.AC-5, PR.DS-5, PR.PT-4, Req-1.4.3, SRG-OS-000480-GPOS-00227, 3.3.1
Description:
To set the runtime status of the `net.ipv6.conf.default.accept_source_route` kernel parameter, run the following command:

    $ sudo sysctl -w net.ipv6.conf.default.accept_source_route=0

To make sure that the setting is persistent, add the following line to a file in the directory `/etc/sysctl.d`:

    net.ipv6.conf.default.accept_source_route = 0

Rationale:

Source-routed packets allow the source of the packet to suggest routers forward the packet along a different path than configured on the router, which can be used to bypass network security measures. This requirement applies only to the forwarding of source-routerd traffic, such as when IPv6 forwarding is enabled and the system is functioning as a router. Accepting source-routed packets in the IPv6 protocol has few legitimate uses. It should be disabled unless it is absolutely required.

Messages:

Message: Message:

    Fix execution completed and returned: 1

Message: Message:

    grep: /run/sysctl.d/*.conf: No such file or directory
    grep: /usr/local/lib/sysctl.d/*.conf: No such file or directory
    sysctl: permission denied on key "net.ipv6.conf.default.accept_source_route"
    /tmp/oscap.Ra4URe/fix-XXvlOwHG: line 52: /etc/sysctl.conf: Permission denied
    /tmp/oscap.Ra4URe/fix-XXvlOwHG: line 53: /etc/sysctl.conf: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

Complexity: | low
Disruption: | medium
Strategy: | disable

    # Remediation is applicable only in certain platforms
    if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

    # Comment out any occurrences of net.ipv6.conf.default.accept_source_route from /etc/sysctl.d/*.conf files

    for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf; do

      matching_list=$(grep -P '^(?!#).*[\s]*net.ipv6.conf.default.accept_source_route.*$' $f | uniq )
      if ! test -z "$matching_list"; then
        while IFS= read -r entry; do
          escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
          # comment out "net.ipv6.conf.default.accept_source_route" matches to preserve user data
          sed -i "s/^${escaped_entry}$/# &/g" $f
        done <<< "$matching_list"
      fi
    done
    sysctl_net_ipv6_conf_default_accept_source_route_value='0'

    #
    # Set runtime for net.ipv6.conf.default.accept_source_route
    #
    /sbin/sysctl -q -n -w net.ipv6.conf.default.accept_source_route="$sysctl_net_ipv6_conf_default_accept_source_route_value"

    #
    # If net.ipv6.conf.default.accept_source_route present in /etc/sysctl.conf, change value to appropriate value
    #	else, add "net.ipv6.conf.default.accept_source_route = value" to /etc/sysctl.conf
    #
    # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
    # Otherwise, regular sed command will do.
    sed_command=('sed' '-i')
    if test -L "/etc/sysctl.conf"; then
        sed_command+=('--follow-symlinks')
    fi

    # Strip any search characters in the key arg so that the key can be replaced without
    # adding any search characters to the config file.
    stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^net.ipv6.conf.default.accept_source_route")

    # shellcheck disable=SC2059
    printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_accept_source_route_value"

    # If the key exists, change it. Otherwise, add it to the config_file.
    # We search for the key string followed by a word boundary (matched by \>),
    # so if we search for 'setting', 'setting2' won't match.
    if LC_ALL=C grep -q -m 1 -i -e "^net.ipv6.conf.default.accept_source_route\\>" "/etc/sysctl.conf"; then
        escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
        "${sed_command[@]}" "s/^net.ipv6.conf.default.accept_source_route\\>.*/$escaped_formatted_output/gi" "/etc/sysctl.conf"
    else
        # \n is precaution for case where file ends without trailing newline
        cce="CCE-84130-4"
        printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "/etc/sysctl.conf" >> "/etc/sysctl.conf"
        printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
    fi

    else
        >&2 echo 'Remediation is not applicable, nothing was done'
    fi

Remediation Ansible snippet

Complexity: | low
Disruption: | medium
Strategy: | disable

    - name: List /etc/sysctl.d/*.conf files
      find:
        paths:
        - /etc/sysctl.d/
        - /run/sysctl.d/
        - /usr/local/lib/sysctl.d/
        contains: ^[\s]*net.ipv6.conf.default.accept_source_route.*$
        patterns: '*.conf'
        file_type: any
      register: find_sysctl_d
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84130-4
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-6(b)
      - NIST-800-53-CM-6.1(iv)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - PCI-DSS-Req-1.4.3
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_default_accept_source_route

    - name: Comment out any occurrences of net.ipv6.conf.default.accept_source_route from
        config files
      replace:
        path: '{{ item.path }}'
        regexp: ^[\s]*net.ipv6.conf.default.accept_source_route
        replace: '#net.ipv6.conf.default.accept_source_route'
      loop: '{{ find_sysctl_d.files }}'
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84130-4
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-6(b)
      - NIST-800-53-CM-6.1(iv)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - PCI-DSS-Req-1.4.3
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_default_accept_source_route
    - name: XCCDF Value sysctl_net_ipv6_conf_default_accept_source_route_value # promote to variable
      set_fact:
        sysctl_net_ipv6_conf_default_accept_source_route_value: !!str 0
      tags:
        - always

    - name: Ensure sysctl net.ipv6.conf.default.accept_source_route is set
      sysctl:
        name: net.ipv6.conf.default.accept_source_route
        value: '{{ sysctl_net_ipv6_conf_default_accept_source_route_value }}'
        state: present
        reload: true
      when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
      tags:
      - CCE-84130-4
      - NIST-800-171-3.1.20
      - NIST-800-53-CM-6(a)
      - NIST-800-53-CM-6(b)
      - NIST-800-53-CM-6.1(iv)
      - NIST-800-53-CM-7(a)
      - NIST-800-53-CM-7(b)
      - PCI-DSS-Req-1.4.3
      - disable_strategy
      - low_complexity
      - medium_disruption
      - medium_severity
      - reboot_required
      - sysctl_net_ipv6_conf_default_accept_source_route

Remediation Kubernetes snippet

    ---
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    spec:
      config:
        ignition:
          version: 3.1.0
        storage:
          files:
          - contents:
              source: data:,net.ipv6.conf.default.accept_source_route%3D0%0A
            mode: 0644
            path: /etc/sysctl.d/75-sysctl_net_ipv6_conf_default_accept_source_route.conf
            overwrite: true

OVAL definition:

Definition ID:

oval:ssg-sysctl_net_ipv6_conf_default_accept_source_route:def:1

Class:

compliance

Title:

Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces by Default

Version:

4

Description:

The kernel 'net.ipv6.conf.default.accept_source_route' parameter should be set to the appropriate value in both system configuration and system runtime.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-sysctl_net_ipv6_conf_default_accept_source_route:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform
CPE platform required by rule:
#machine
Enforce usage of pam_wheel for su authentication medium fix failed

Rule ID: | xccdf_org.ssgproject.content_rule_use_pam_wheel_for_su
Result: | fix failed
Multi-check rule: | no
Time: | 2023-03-16T13:57:16+01:00
Weight: | 1.0
Severity:

medium

Identifiers:

CCE-90085-2

References:

FMT_SMF_EXT.1.1, Req-8.6.1, SRG-OS-000373-GPOS-00156, SRG-OS-000312-GPOS-00123, 5.3.7
Description:
To ensure that only users who are members of the `wheel` group can run commands with altered privileges through the `su` command, make sure that the following line exists in the file `/etc/pam.d/su`:

    auth required pam_wheel.so use_uid

Rationale:

The `su` program allows to run commands with a substitute user and group ID. It is commonly used to run commands as the root user. Limiting access to such command is considered a good security practice.

Warnings:

General warning
Members of "wheel" or GID 0 groups are checked by default if the group option is not set for pam_wheel.so module. Therefore, members of these groups should be manually checked or a different group should be informed according to the site policy.

Messages:

Message: Message:

    Fix execution completed and returned: 4

Message: Message:

    sed: couldn't open temporary file /etc/pam.d/sed9FZveM: Permission denied

Message: Message:

    Failed to verify applied fix: Checking engine returns: fail

Message: Message:

    The OVAL graph of the rule as it was displayed before the fix was performed.

Remediation Shell script

    # uncomment the option if commented
      sed '/^[[:space:]]*#[[:space:]]*auth[[:space:]]\+required[[:space:]]\+pam_wheel\.so[[:space:]]\+use_uid$/s/^[[:space:]]*#//' -i /etc/pam.d/su

Remediation Ansible snippet

Complexity: | low
Disruption: | low
Strategy: | restrict

    - name: restrict usage of su command only to members of wheel group
      replace:
        path: /etc/pam.d/su
        regexp: ^[\s]*#[\s]*auth[\s]+required[\s]+pam_wheel\.so[\s]+use_uid$
        replace: auth             required        pam_wheel.so use_uid
      tags:
      - CCE-90085-2
      - PCI-DSS-Req-8.6.1
      - low_complexity
      - low_disruption
      - medium_severity
      - no_reboot_needed
      - restrict_strategy
      - use_pam_wheel_for_su

OVAL definition:

Definition ID:

oval:ssg-use_pam_wheel_for_su:def:1

Class:

compliance

Title:

Enforce usage of pam_wheel for su authentication

Version:

1

Description:

Only members of the wheel group should be able to authenticate through the su command.

Result explained:

Compliance class describes OVAL Definitions that check to see if a system's state is compliant with a specific policy. An evaluation result of "true", for this class of OVAL Definitions, indicates that a system is compliant with the stated policy.

OVAL graph of OVAL definition: oval:ssg-use_pam_wheel_for_su:def:1
CPE platform required by profile:
cpe:/o:redhat:enterprise_linux:9 Profile platform