Guide to the Secure Configuration of Red Hat Enterprise Linux 6

with profile FISMA Medium for Red Hat Enterprise Linux 6
FISMA Medium for Red Hat Enterprise Linux 6.
This guide presents a catalog of security-relevant configuration settings for Red Hat Enterprise Linux 6. It is a rendering of content structured in the eXtensible Configuration Checklist Description Format (XCCDF) in order to support security automation. The SCAP content is is available in the scap-security-guide package which is developed at https://www.open-scap.org/security-policies/scap-security-guide.

Providing system administrators with such guidance informs them how to securely configure systems under their control in a variety of network roles. Policy makers and baseline creators can use this catalog of settings, with its associated references to higher-level security control catalogs, in order to assist them in security baseline creation. This guide is a catalog, not a checklist, and satisfaction of every item is not likely to be possible or sensible in many operational scenarios. However, the XCCDF format enables granular selection and adjustment of settings, and their association with OVAL and OCIL content provides an automated checking capability. Transformations of this document, and its associated automated checking content, are capable of providing baselines that meet a diverse set of policy objectives. Some example XCCDF Profiles, which are selections of items that form checklists and can be used as baselines, are available with this guide. They can be processed, in an automated fashion, with tools that support the Security Content Automation Protocol (SCAP). The DISA STIG, which provides required settings for US Department of Defense systems, is one example of a baseline created from this guidance.
Do not attempt to implement any of the settings in this guide without first testing them in a non-operational environment. The creators of this guidance assume no responsibility whatsoever for its use by other parties, and makes no guarantees, expressed or implied, about its quality, reliability, or any other characteristic.
Profile TitleFISMA Medium for Red Hat Enterprise Linux 6
Profile IDxccdf_org.ssgproject.content_profile_fisma-medium-rhel6-server

Revision History

Current version: 0.1.41

  • draft (as of 2018-10-09)

Platforms

  • cpe:/o:redhat:enterprise_linux:6
  • cpe:/o:redhat:enterprise_linux:6::client
  • cpe:/o:redhat:enterprise_linux:6::computenode

Table of Contents

  1. Services
    1. Obsolete Services
    2. Cron and At Daemons
    3. Network Time Protocol
    4. Base Services
    5. Avahi Server
    6. SSH Server
  2. System Settings
    1. Installing and Maintaining Software
    2. Configure Syslog
    3. Network Configuration and Firewalls
    4. SELinux
    5. Set Boot Loader Password
    6. Account and Access Control
    7. System Accounting with auditd
    8. File Permissions and Masks

Checklist

contains 211 rules

Services   [ref]group

The best protection against vulnerable software is running less software. This section describes how to review the software which Red Hat Enterprise Linux 6 installs on a system and disable software which is not needed. It then enumerates the software packages installed on a default Red Hat Enterprise Linux 6 system and provides guidance about which ones can be safely disabled.

Red Hat Enterprise Linux 6 provides a convenient minimal install option that essentially installs the bare necessities for a functional system. When building Red Hat Enterprise Linux 6 systems, it is highly recommended to select the minimal packages and then build up the system from there.

contains 46 rules

Obsolete Services   [ref]group

This section discusses a number of network-visible services which have historically caused problems for system security, and for which disabling or severely limiting the service has been the best available guidance for some time. As a result of this, many of these services are not installed as part of Red Hat Enterprise Linux 6 by default.

Organizations which are running these services should switch to more secure equivalents as soon as possible. If it remains absolutely necessary to run one of these services for legacy reasons, care should be taken to restrict the service as much as possible, for instance by configuring host firewall software such as iptables to restrict access to the vulnerable service to only those remote hosts which have a known need to use it.

contains 14 rules

Rlogin, Rsh, and Rexec   [ref]group

The Berkeley r-commands are legacy services which allow cleartext remote access and have an insecure trust model.

contains 5 rules

Uninstall rsh Package   [ref]rule

The rsh package contains the client commands for the rsh services

Rationale:

These legacy clients contain numerous security exposures and have been replaced with the more secure SSH package. Even if the server is removed, it is best to ensure the clients are also removed to prevent users from inadvertently attempting to use these commands and therefore exposing their credentials. Note that removing the rsh package removes the clients for rsh,rcp, and rlogin.

Severity:  unknown

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:disable
# Function to remove packages on RHEL, Fedora, Debian, and possibly other systems.
#
# Example Call(s):
#
#     package_remove telnet-server
#
function package_remove {

# Load function arguments into local variables
local package="$1"

# Check sanity of the input
if [ $# -ne "1" ]
then
  echo "Usage: package_remove 'package_name'"
  echo "Aborting."
  exit 1
fi

if which dnf ; then
  if rpm -q --quiet "$package"; then
    dnf remove -y "$package"
  fi
elif which yum ; then
  if rpm -q --quiet "$package"; then
    yum remove -y "$package"
  fi
elif which apt-get ; then
  apt-get remove -y "$package"
else
  echo "Failed to detect available packaging system, tried dnf, yum and apt-get!"
  echo "Aborting."
  exit 1
fi

}

package_remove rsh
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Ensure rsh is removed
  package:
    name: rsh
    state: absent
  tags:
    - package_rsh_removed
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27359-9
    - NIST-800-171-3.1.13
Remediation Puppet snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
include remove_rsh

class remove_rsh {
  package { 'rsh':
    ensure => 'purged',
  }
}
Remediation Anaconda snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable

package --remove=rsh

Disable rlogin Service   [ref]rule

The rlogin service, which is available with the rsh-server package and runs as a service through xinetd or separately as a systemd socket, should be disabled. If using xinetd, set disable to yes in /etc/xinetd.d/rlogin.

Rationale:

The rlogin service uses unencrypted network communications, which means that data from the login session, including passwords and all other information transmitted during the session, can be stolen by eavesdroppers on the network.

Severity:  high

Disable rexec Service   [ref]rule

The rexec service, which is available with the rsh-server package and runs as a service through xinetd or separately as a systemd socket, should be disabled. If using xinetd, set disable to yes in /etc/xinetd.d/rexec. "

Rationale:

The rexec service uses unencrypted network communications, which means that data from the login session, including passwords and all other information transmitted during the session, can be stolen by eavesdroppers on the network.

Severity:  high

Disable rsh Service   [ref]rule

The rsh service, which is available with the rsh-server package and runs as a service through xinetd or separately as a systemd socket, should be disabled. If using xinetd, set disable to yes in /etc/xinetd.d/rsh.

Rationale:

The rsh service uses unencrypted network communications, which means that data from the login session, including passwords and all other information transmitted during the session, can be stolen by eavesdroppers on the network.

Severity:  high

Remove Rsh Trust Files   [ref]rule

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:

Trust files are convenient, but when used in conjunction with the R-services, they can allow unauthenticated access to a system.

Severity:  high

Remediation Shell script:   (show)

find /home -maxdepth 2 -type f -name .rhosts -exec rm -f '{}' \;

if [ -f /etc/hosts.equiv ]; then
	/bin/rm -f /etc/hosts.equiv
fi
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:restrict
- block:
    - name: "Detect shosts.equiv Files on the System"
      find:
          paths: /
          recurse: yes
          patterns: shosts.equiv
      check_mode: no
      register: shosts_equiv_locations

    - name: "Remove Rsh Trust Files"
      file:
          path: "{{ item.path }}"
          state: absent
      with_items: "{{ shosts_equiv_locations.files }}"
      when: shosts_equiv_locations
  tags:
    - no_rsh_trust_files
    - high_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-27270-8
    - NIST-800-53-AC-17(8)
    - NIST-800-53-CM-7
    - DISA-STIG-RHEL-06-000019

Telnet   [ref]group

The telnet protocol does not provide confidentiality or integrity for information transmitted on the network. This includes authentication information such as passwords. Organizations which use telnet should be actively working to migrate to a more secure protocol.

contains 2 rules

Disable telnet Service   [ref]rule

The telnet service configuration file /etc/xinetd.d/telnet is not created automatically. If it was created manually, check the /etc/xinetd.d/telnet file and ensure that disable = no is changed to read disable = yes as follows below:

# description: The telnet server serves telnet sessions; it uses \\
#       unencrypted username/password pairs for authentication.
service telnet
{
        flags           = REUSE
        socket_type     = stream

        wait            = no
        user            = root
        server          = /usr/sbin/in.telnetd
        log_on_failure  += USERID
        disable         = yes
}
If the /etc/xinetd.d/telnet file does not exist, make sure that the activation of the telnet service on system boot is disabled via the following command:

Rationale:

The telnet protocol uses unencrypted network communication, which means that data from the login session, including passwords and all other information transmitted during the session, can be stolen by eavesdroppers on the network. The telnet protocol is also subject to man-in-the-middle attacks.

Severity:  high

Uninstall telnet-server Package   [ref]rule

The telnet-server package can be removed with the following command:

$ sudo yum 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.

Severity:  high

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:disable
# Function to remove packages on RHEL, Fedora, Debian, and possibly other systems.
#
# Example Call(s):
#
#     package_remove telnet-server
#
function package_remove {

# Load function arguments into local variables
local package="$1"

# Check sanity of the input
if [ $# -ne "1" ]
then
  echo "Usage: package_remove 'package_name'"
  echo "Aborting."
  exit 1
fi

if which dnf ; then
  if rpm -q --quiet "$package"; then
    dnf remove -y "$package"
  fi
elif which yum ; then
  if rpm -q --quiet "$package"; then
    yum remove -y "$package"
  fi
elif which apt-get ; then
  apt-get remove -y "$package"
else
  echo "Failed to detect available packaging system, tried dnf, yum and apt-get!"
  echo "Aborting."
  exit 1
fi

}

package_remove telnet-server
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Ensure telnet-server is removed
  package:
    name: telnet-server
    state: absent
  tags:
    - package_telnet-server_removed
    - high_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27073-6
    - NIST-800-53-CM-7
    - NIST-800-53-AC-17(8)
    - NIST-800-53-CM-7(a)
    - DISA-STIG-RHEL-06-000206
Remediation Puppet snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
include remove_telnet-server

class remove_telnet-server {
  package { 'telnet-server':
    ensure => 'purged',
  }
}
Remediation Anaconda snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable

package --remove=telnet-server

NIS   [ref]group

The Network Information Service (NIS), also known as 'Yellow Pages' (YP), and its successor NIS+ have been made obsolete by Kerberos, LDAP, and other modern centralized authentication services. NIS should not be used because it suffers from security problems inherent in its design, such as inadequate protection of important authentication information.

contains 2 rules

Disable ypbind Service   [ref]rule

The ypbind service, which allows the system to act as a client in a NIS or NIS+ domain, should be disabled. The ypbind service can be disabled with the following command:

$ sudo chkconfig ypbind off

Rationale:

Disabling the ypbind service ensures the system is not acting as a client in a NIS or NIS+ domain. This service should be disabled unless in use.

Severity:  medium

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'ypbind' disable
/sbin/chkconfig --level 0123456 'ypbind' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service ypbind
  service:
    name: ypbind
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_ypbind_disabled
    - medium_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-26894-6
    - NIST-800-53-AC-17(8)
    - NIST-800-53-CM-7
    - DISA-STIG-RHEL-06-000221

Uninstall ypserv Package   [ref]rule

The ypserv package can be removed with the following command:

$ sudo yum erase ypserv

Rationale:

The NIS service provides an unencrypted authentication service which does not provide for the confidentiality and integrity of user passwords or the remote session. Removing the ypserv package decreases the risk of the accidental (or intentional) activation of NIS or NIS+ services.

Severity:  high

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:disable
# Function to remove packages on RHEL, Fedora, Debian, and possibly other systems.
#
# Example Call(s):
#
#     package_remove telnet-server
#
function package_remove {

# Load function arguments into local variables
local package="$1"

# Check sanity of the input
if [ $# -ne "1" ]
then
  echo "Usage: package_remove 'package_name'"
  echo "Aborting."
  exit 1
fi

if which dnf ; then
  if rpm -q --quiet "$package"; then
    dnf remove -y "$package"
  fi
elif which yum ; then
  if rpm -q --quiet "$package"; then
    yum remove -y "$package"
  fi
elif which apt-get ; then
  apt-get remove -y "$package"
else
  echo "Failed to detect available packaging system, tried dnf, yum and apt-get!"
  echo "Aborting."
  exit 1
fi

}

package_remove ypserv
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Ensure ypserv is removed
  package:
    name: ypserv
    state: absent
  tags:
    - package_ypserv_removed
    - high_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27079-3
    - NIST-800-53-CM-7
    - NIST-800-53-AC-17(8)
    - NIST-800-53-CM-7(a)
    - DISA-STIG-RHEL-06-000220
Remediation Puppet snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
include remove_ypserv

class remove_ypserv {
  package { 'ypserv':
    ensure => 'purged',
  }
}
Remediation Anaconda snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable

package --remove=ypserv

TFTP Server   [ref]group

TFTP is a lightweight version of the FTP protocol which has traditionally been used to configure networking equipment. However, TFTP provides little security, and modern versions of networking operating systems frequently support configuration via SSH or other more secure protocols. A TFTP server should be run only if no more secure method of supporting existing equipment can be found.

contains 3 rules

Disable tftp Service   [ref]rule

The tftp service should be disabled. The tftp service can be disabled with the following command:

$ sudo chkconfig tftp off

Rationale:

Disabling the tftp service ensures the system is not acting as a TFTP server, which does not provide encryption or authentication.

Severity:  medium

Identifiers:  CCE-27055-3

References:  SRG-OS-000248, RHEL-06-000223, SV-50410r2_rule, 2.1.6, CCI-001436, AC-17(8), CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'tftp' disable
/sbin/chkconfig --level 0123456 'tftp' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service tftp
  service:
    name: tftp
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_tftp_disabled
    - medium_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27055-3
    - NIST-800-53-AC-17(8)
    - NIST-800-53-CM-7
    - DISA-STIG-RHEL-06-000223

Uninstall tftp-server Package   [ref]rule

The tftp-server package can be removed with the following command:

 $ sudo yum 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.

Severity:  high

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:disable
# Function to remove packages on RHEL, Fedora, Debian, and possibly other systems.
#
# Example Call(s):
#
#     package_remove telnet-server
#
function package_remove {

# Load function arguments into local variables
local package="$1"

# Check sanity of the input
if [ $# -ne "1" ]
then
  echo "Usage: package_remove 'package_name'"
  echo "Aborting."
  exit 1
fi

if which dnf ; then
  if rpm -q --quiet "$package"; then
    dnf remove -y "$package"
  fi
elif which yum ; then
  if rpm -q --quiet "$package"; then
    yum remove -y "$package"
  fi
elif which apt-get ; then
  apt-get remove -y "$package"
else
  echo "Failed to detect available packaging system, tried dnf, yum and apt-get!"
  echo "Aborting."
  exit 1
fi

}

package_remove tftp-server
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Ensure tftp-server is removed
  package:
    name: tftp-server
    state: absent
  tags:
    - package_tftp-server_removed
    - high_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-26946-4
    - NIST-800-53-AC-17(8)
    - NIST-800-53-CM-6(c)
    - NIST-800-53-CM-7
    - DISA-STIG-RHEL-06-000222
Remediation Puppet snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
include remove_tftp-server

class remove_tftp-server {
  package { 'tftp-server':
    ensure => 'purged',
  }
}
Remediation Anaconda snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable

package --remove=tftp-server

Ensure tftp Daemon Uses Secure Mode   [ref]rule

If running the tftp service is necessary, it should be configured to change its root directory at startup. To do so, ensure /etc/xinetd.d/tftp includes -s as a command line argument, as shown in the following example (which is also the default):

server_args = -s /var/lib/tftpboot

Rationale:

Using the -s option causes the TFTP service to only serve files from the given directory. Serving files from an intentionally-specified directory reduces the risk of sharing files which should remain private.

Severity:  high

Xinetd   [ref]group

The xinetd service acts as a dedicated listener for some network services (mostly, obsolete ones) and can be used to provide access controls and perform some logging. It has been largely obsoleted by other features, and it is not installed by default. The older Inetd service is not even available as part of Red Hat Enterprise Linux 6.

contains 2 rules

Disable xinetd Service   [ref]rule

The xinetd service can be disabled with the following command:

$ sudo chkconfig xinetd off

Rationale:

The xinetd service provides a dedicated listener service for some programs, which is no longer necessary for commonly-used network services. Disabling it ensures that these uncommon services are not running, and also prevents attacks against xinetd itself.

Severity:  medium

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'xinetd' disable
/sbin/chkconfig --level 0123456 'xinetd' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service xinetd
  service:
    name: xinetd
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_xinetd_disabled
    - medium_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27046-2
    - NIST-800-53-AC-17(8)
    - NIST-800-53-CM-7
    - NIST-800-171-3.4.7
    - DISA-STIG-RHEL-06-000203

Uninstall xinetd Package   [ref]rule

The xinetd package can be removed with the following command:

$ sudo yum erase xinetd

Rationale:

Removing the xinetd package decreases the risk of the xinetd service's accidental (or intentional) activation.

Severity:  unknown

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:disable
# Function to remove packages on RHEL, Fedora, Debian, and possibly other systems.
#
# Example Call(s):
#
#     package_remove telnet-server
#
function package_remove {

# Load function arguments into local variables
local package="$1"

# Check sanity of the input
if [ $# -ne "1" ]
then
  echo "Usage: package_remove 'package_name'"
  echo "Aborting."
  exit 1
fi

if which dnf ; then
  if rpm -q --quiet "$package"; then
    dnf remove -y "$package"
  fi
elif which yum ; then
  if rpm -q --quiet "$package"; then
    yum remove -y "$package"
  fi
elif which apt-get ; then
  apt-get remove -y "$package"
else
  echo "Failed to detect available packaging system, tried dnf, yum and apt-get!"
  echo "Aborting."
  exit 1
fi

}

package_remove xinetd
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Ensure xinetd is removed
  package:
    name: xinetd
    state: absent
  tags:
    - package_xinetd_removed
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27005-8
    - NIST-800-53-AC-17(8)
    - NIST-800-53-CM-7
    - DISA-STIG-RHEL-06-000204
Remediation Puppet snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
include remove_xinetd

class remove_xinetd {
  package { 'xinetd':
    ensure => 'purged',
  }
}
Remediation Anaconda snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable

package --remove=xinetd

Cron and At Daemons   [ref]group

The cron and at services are used to allow commands to be executed at a later time. The cron service is required by almost all systems to perform necessary maintenance tasks, while at may or may not be required on a given system. Both daemons should be configured defensively.

contains 2 rules

Enable cron Service   [ref]rule

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 chkconfig --level 2345 crond on

Rationale:

Due to its usage for maintenance and security-supporting tasks, enabling the cron daemon is essential.

Severity:  medium

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'crond' disable
/sbin/chkconfig --level 0123456 'crond' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:enable
- name: Enable service crond
  service:
    name: crond
    enabled: "yes"
    state: "started"
  tags:
    - service_crond_enabled
    - medium_severity
    - enable_strategy
    - low_complexity
    - low_disruption
    - CCE-27070-2
    - NIST-800-53-CM-7
    - DISA-STIG-RHEL-06-000224

Disable At Service (atd)   [ref]rule

The at and batch commands can be used to schedule tasks that are meant to be executed only once. This allows delayed execution in a manner similar to cron, except that it is not recurring. The daemon atd keeps track of tasks scheduled via at and batch, and executes them at the specified time. The atd service can be disabled with the following command:

$ sudo chkconfig atd off

Rationale:

The atd service could be used by an unsophisticated insider to carry out activities outside of a normal login session, which could complicate accountability. Furthermore, the need to schedule tasks with at or batch is not common.

Severity:  unknown

Identifiers:  CCE-27249-2

References:  SRG-OS-000096, RHEL-06-000262, SV-50442r3_rule, CCI-000381, CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'atd' disable
/sbin/chkconfig --level 0123456 'atd' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service atd
  service:
    name: atd
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_atd_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27249-2
    - NIST-800-53-CM-7
    - DISA-STIG-RHEL-06-000262

Network Time Protocol   [ref]group

The Network Time Protocol is used to manage the system clock over a network. Computer clocks are not very accurate, so time will drift unpredictably on unmanaged systems. Central time protocols can be used both to ensure that time is consistent among a network of systems, and that their time is consistent with the outside world.

If every system on a network reliably reports the same time, then it is much easier to correlate log messages in case of an attack. In addition, a number of cryptographic protocols (such as Kerberos) use timestamps to prevent certain types of attacks. If your network does not have synchronized time, these protocols may be unreliable or even unusable.

Depending on the specifics of the network, global time accuracy may be just as important as local synchronization, or not very important at all. If your network is connected to the Internet, using a public timeserver (or one provided by your enterprise) provides globally accurate timestamps which may be essential in investigating or responding to an attack which originated outside of your network.

A typical network setup involves a small number of internal systems operating as NTP servers, and the remainder obtaining time information from those internal servers.

There is a choice between the daemons ntpd and chronyd, which are available from the repositories in the ntp and chrony packages respectively.

The default chronyd daemon can work well when external time references are only intermittently accesible, can perform well even when the network is congested for longer periods of time, can usually synchronize the clock faster and with better time accuracy, and quickly adapts to sudden changes in the rate of the clock, for example, due to changes in the temperature of the crystal oscillator. Chronyd should be considered for all systems which are frequently suspended or otherwise intermittently disconnected and reconnected to a network. Mobile and virtual systems for example.

The ntpd NTP daemon fully supports NTP protocol version 4 (RFC 5905), including broadcast, multicast, manycast clients and servers, and the orphan mode. It also supports extra authentication schemes based on public-key cryptography (RFC 5906). The NTP daemon (ntpd) should be considered for systems which are normally kept permanently on. Systems which are required to use broadcast or multicast IP, or to perform authentication of packets with the Autokey protocol, should consider using ntpd.

Refer to https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/ch-Configuring_NTP_Using_the_chrony_Suite.html for more detailed comparison of features of chronyd and ntpd daemon features respectively, and for further guidance how to choose between the two NTP daemons.

The upstream manual pages at http://chrony.tuxfamily.org/manual.html for chronyd and http://www.ntp.org for ntpd provide additional information on the capabilities and configuration of each of the NTP daemons.

contains 3 rules

Specify Additional Remote NTP Servers   [ref]rule

Additional NTP servers can be specified for time synchronization in the file /etc/ntp.conf. To do so, add additional lines of the following form, substituting the IP address or hostname of a remote NTP server for ntpserver:

server ntpserver

Rationale:

Specifying additional NTP servers increases the availability of accurate time data, in the event that one of the specified servers becomes unavailable. This is typical for a system acting as an NTP server for other systems.

Severity:  unknown

Identifiers:  CCE-26958-9

References:  AU-8(1), Req-10.4.3

Enable the NTP Daemon   [ref]rule

The ntpd service can be enabled with the following command:

$ sudo chkconfig --level 2345 ntpd on

Rationale:

Enabling the ntpd service ensures that the ntpd service will be running and that the system will synchronize its time to any servers specified. This is important whether the system is configured to be a client (and synchronize only its own clock) or it is also acting as an NTP server to other systems. Synchronizing time is essential for authentication services such as Kerberos, but it is also important for maintaining accurate logs and auditing possible security breaches.

The NTP daemon offers all of the functionality of ntpdate, which is now deprecated. Additional information on this is available at http://support.ntp.org/bin/view/Dev/DeprecatingNtpdate.

Severity:  medium

Identifiers:  CCE-27093-4

References:  CCI-000160, SRG-OS-000056, RHEL-06-000247, SV-50421r1_rule, AU-8(1), Req-10.4

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'ntpd' disable
/sbin/chkconfig --level 0123456 'ntpd' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:enable
- name: Enable service ntpd
  service:
    name: ntpd
    enabled: "yes"
    state: "started"
  tags:
    - service_ntpd_enabled
    - medium_severity
    - enable_strategy
    - low_complexity
    - low_disruption
    - CCE-27093-4
    - NIST-800-53-AU-8(1)
    - PCI-DSS-Req-10.4
    - DISA-STIG-RHEL-06-000247

Specify a Remote NTP Server   [ref]rule

To specify a remote NTP server for time synchronization, edit the file /etc/ntp.conf. Add or correct the following lines, substituting the IP or hostname of a remote NTP server for ntpserver:

server ntpserver
This instructs the NTP software to contact that remote server to obtain time data.

Rationale:

Synchronizing with an NTP server makes it possible to collate system logs from multiple sources or correlate computer events with real time events.

Severity:  medium

Base Services   [ref]group

This section addresses the base services that are installed on a Red Hat Enterprise Linux 6 default installation which are not covered in other sections. Some of these services listen on the network and should be treated with particular discretion. Other services are local system utilities that may or may not be extraneous. In general, system services should be disabled if not required.

contains 23 rules

Disable Hardware Abstraction Layer Service (haldaemon)   [ref]rule

The Hardware Abstraction Layer Daemon (haldaemon) collects and maintains information about the system's hardware configuration. This service is required on a workstation running a desktop environment, and may be necessary on any system which deals with removable media or devices. The haldaemon service can be disabled with the following command:

$ sudo chkconfig haldaemon off

Rationale:

The haldaemon provides essential functionality on systems that use removable media or devices, but can be disabled for systems that do not require these.

Severity:  unknown

Identifiers:  CCE-27086-8

References:  CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'haldaemon' disable
/sbin/chkconfig --level 0123456 'haldaemon' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service haldaemon
  service:
    name: haldaemon
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_haldaemon_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27086-8
    - NIST-800-53-CM-7

Disable D-Bus IPC Service (messagebus)   [ref]rule

D-Bus provides an IPC mechanism used by a growing list of programs, such as those used for Gnome, Bluetooth, and Avahi. Due to these dependencies, disabling D-Bus may not be practical for many systems. The messagebus service can be disabled with the following command:

$ sudo chkconfig messagebus off

Rationale:

If no services which require D-Bus are needed, then it can be disabled. As a broker for IPC between processes of different privilege levels, it could be a target for attack. However, disabling D-Bus is likely to be impractical for any system which needs to provide a graphical login session.

Severity:  unknown

Identifiers:  CCE-26913-4

References:  CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'messagebus' disable
/sbin/chkconfig --level 0123456 'messagebus' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service messagebus
  service:
    name: messagebus
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_messagebus_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-26913-4
    - NIST-800-53-CM-7

Disable Advanced Configuration and Power Interface (acpid)   [ref]rule

The Advanced Configuration and Power Interface Daemon (acpid) dispatches ACPI events (such as power/reset button depressed) to userspace programs. The acpid service can be disabled with the following command:

$ sudo chkconfig acpid off

Rationale:

ACPI support is highly desirable for systems in some network roles, such as laptops or desktops. For other systems, such as servers, it may permit accidental or trivially achievable denial of service situations and disabling it is appropriate.

Severity:  unknown

Identifiers:  CCE-27061-1

References:  CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'acpid' disable
/sbin/chkconfig --level 0123456 'acpid' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service acpid
  service:
    name: acpid
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_acpid_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27061-1
    - NIST-800-53-CM-7

Disable KDump Kernel Crash Analyzer (kdump)   [ref]rule

The kdump service provides a kernel crash dump analyzer. It uses the kexec system call to boot a secondary kernel ("capture" kernel) following a system crash, which can load information from the crashed kernel for analysis. The kdump service can be disabled with the following command:

$ sudo chkconfig kdump off

Rationale:

Kernel core dumps may contain the full contents of system memory at the time of the crash. Kernel core dumps consume a considerable amount of disk space and may result in denial of service by exhausting the available space on the target file system partition. Unless the system is used for kernel development or testing, there is little need to run the kdump service.

Severity:  medium

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'kdump' disable
/sbin/chkconfig --level 0123456 'kdump' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service kdump
  service:
    name: kdump
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_kdump_disabled
    - medium_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-26850-8
    - NIST-800-53-AC-17(8)
    - NIST-800-53-CM-7
    - NIST-800-53-CM-6(b)
Remediation Anaconda snippet:   (show)


kdump --disable

Disable CPU Speed (cpuspeed)   [ref]rule

The cpuspeed service can adjust the clock speed of supported CPUs based upon the current processing load thereby conserving power and reducing heat. The cpuspeed service can be disabled with the following command:

$ sudo chkconfig cpuspeed off

Rationale:

The cpuspeed service is only necessary if adjusting the CPU clock speed provides benefit. Traditionally this has included laptops (to enhance battery life), but may also apply to server or desktop environments where conserving power is highly desirable or necessary.

Severity:  unknown

Identifiers:  CCE-26973-8

References:  CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'cpuspeed' disable
/sbin/chkconfig --level 0123456 'cpuspeed' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service cpuspeed
  service:
    name: cpuspeed
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_cpuspeed_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-26973-8
    - NIST-800-53-CM-7

Disable Network Console (netconsole)   [ref]rule

The netconsole service is responsible for loading the netconsole kernel module, which logs kernel printk messages over UDP to a syslog server. This allows debugging of problems where disk logging fails and serial consoles are impractical. The netconsole service can be disabled with the following command:

$ sudo chkconfig netconsole off

Rationale:

The netconsole service is not necessary unless there is a need to debug kernel panics, which is not common.

Severity:  unknown

Identifiers:  CCE-27254-2

References:  SRG-OS-000096, RHEL-06-000289, SV-50473r2_rule, CCI-000381, AC-17(8), CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'netconsole' disable
/sbin/chkconfig --level 0123456 'netconsole' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service netconsole
  service:
    name: netconsole
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_netconsole_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27254-2
    - NIST-800-53-AC-17(8)
    - NIST-800-53-CM-7
    - DISA-STIG-RHEL-06-000289

Disable Certmonger Service (certmonger)   [ref]rule

Certmonger is a D-Bus based service that attempts to simplify interaction with certifying authorities on networks which use public-key infrastructure. It is often combined with Red Hat's IPA (Identity Policy Audit) security information management solution to aid in the management of certificates. The certmonger service can be disabled with the following command:

$ sudo chkconfig certmonger off

Rationale:

The services provided by certmonger may be essential for systems fulfilling some roles a PKI infrastructure, but its functionality is not necessary for many other use cases.

Severity:  unknown

Identifiers:  CCE-27267-4

References:  CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'certmonger' disable
/sbin/chkconfig --level 0123456 'certmonger' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service certmonger
  service:
    name: certmonger
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_certmonger_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27267-4
    - NIST-800-53-CM-7

Disable Quota Netlink (quota_nld)   [ref]rule

The quota_nld service provides notifications to users of disk space quota violations. It listens to the kernel via a netlink socket for disk quota violations and notifies the appropriate user of the violation using D-Bus or by sending a message to the terminal that the user has last accessed. The quota_nld service can be disabled with the following command:

$ sudo chkconfig quota_nld off

Rationale:

If disk quotas are enforced on the local system, then the quota_nld service likely provides useful functionality and should remain enabled. However, if disk quotas are not used or user notification of disk quota violation is not desired then there is no need to run this service.

Severity:  unknown

Identifiers:  CCE-27260-9

References:  CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'quota_nld' disable
/sbin/chkconfig --level 0123456 'quota_nld' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service quota_nld
  service:
    name: quota_nld
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_quota_nld_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27260-9
    - NIST-800-53-CM-7

Disable Red Hat Network Service (rhnsd)   [ref]rule

The Red Hat Network service automatically queries Red Hat Network servers to determine whether there are any actions that should be executed, such as package updates. This only occurs if the system was registered to an RHN server or satellite and managed as such. The rhnsd service can be disabled with the following command:

$ sudo chkconfig rhnsd off

Rationale:

Although systems management and patching is extremely important to system security, management by a system outside the enterprise enclave is not desirable for some environments. However, if the system is being managed by RHN or RHN Satellite Server the rhnsd daemon can remain on.

Severity:  unknown

Identifiers:  CCE-26846-6

References:  SRG-OS-000096, RHEL-06-000009, SV-50278r2_rule, 1.2.5, CCI-000382, AC-17(8), CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'rhnsd' disable
/sbin/chkconfig --level 0123456 'rhnsd' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service rhnsd
  service:
    name: rhnsd
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_rhnsd_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-26846-6
    - NIST-800-53-AC-17(8)
    - NIST-800-53-CM-7
    - DISA-STIG-RHEL-06-000009

Disable Software RAID Monitor (mdmonitor)   [ref]rule

The mdmonitor service is used for monitoring a software RAID array; hardware RAID setups do not use this service. The mdmonitor service can be disabled with the following command:

$ sudo chkconfig mdmonitor off

Rationale:

If software RAID monitoring is not required, there is no need to run this service.

Severity:  unknown

Identifiers:  CCE-27193-2

References:  CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'mdmonitor' disable
/sbin/chkconfig --level 0123456 'mdmonitor' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service mdmonitor
  service:
    name: mdmonitor
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_mdmonitor_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27193-2
    - NIST-800-53-CM-7

Enable IRQ Balance (irqbalance)   [ref]rule

The irqbalance service optimizes the balance between power savings and performance through distribution of hardware interrupts across multiple processors. The irqbalance service can be enabled with the following command:

$ sudo chkconfig --level 2345 irqbalance on

Rationale:

In an environment with multiple processors (now common), the irqbalance service provides potential speedups for handling interrupt requests.

Severity:  unknown

Identifiers:  CCE-26990-2

References:  CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'irqbalance' disable
/sbin/chkconfig --level 0123456 'irqbalance' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:enable
- name: Enable service irqbalance
  service:
    name: irqbalance
    enabled: "yes"
    state: "started"
  tags:
    - service_irqbalance_enabled
    - unknown_severity
    - enable_strategy
    - low_complexity
    - low_disruption
    - CCE-26990-2
    - NIST-800-53-CM-7

Disable Odd Job Daemon (oddjobd)   [ref]rule

The oddjobd service exists to provide an interface and access control mechanism through which specified privileged tasks can run tasks for unprivileged client applications. Communication with oddjobd through the system message bus. The oddjobd service can be disabled with the following command:

$ sudo chkconfig oddjobd off

Rationale:

The oddjobd service may provide necessary functionality in some environments, and can be disabled if it is not needed. Execution of tasks by privileged programs, on behalf of unprivileged ones, has traditionally been a source of privilege escalation security issues.

Severity:  unknown

Identifiers:  CCE-27257-5

References:  SRG-OS-000096, RHEL-06-000266, SV-50447r2_rule, CCI-000381, CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'oddjobd' disable
/sbin/chkconfig --level 0123456 'oddjobd' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service oddjobd
  service:
    name: oddjobd
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_oddjobd_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27257-5
    - NIST-800-53-CM-7
    - DISA-STIG-RHEL-06-000266

Disable Control Group Rules Engine (cgred)   [ref]rule

The cgred service moves tasks into control groups according to parameters set in the /etc/cgrules.conf configuration file. The cgred service can be disabled with the following command:

$ sudo chkconfig cgred off

Rationale:

Unless control groups are used to manage system resources, running the cgred service service is not necessary.

Severity:  unknown

Identifiers:  CCE-27252-6

References:  CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'cgred' disable
/sbin/chkconfig --level 0123456 'cgred' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service cgred
  service:
    name: cgred
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_cgred_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27252-6
    - NIST-800-53-CM-7

Disable SMART Disk Monitoring Service (smartd)   [ref]rule

SMART (Self-Monitoring, Analysis, and Reporting Technology) is a feature of hard drives that allows them to detect symptoms of disk failure and relay an appropriate warning. The smartd service can be disabled with the following command:

$ sudo chkconfig smartd off

Rationale:

SMART can help protect against denial of service due to failing hardware. Nevertheless, if it is not needed or the system's drives are not SMART-capable (such as solid state drives), it can be disabled.

Severity:  unknown

Identifiers:  CCE-26853-2

References:  CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'smartd' disable
/sbin/chkconfig --level 0123456 'smartd' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service smartd
  service:
    name: smartd
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_smartd_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-26853-2
    - NIST-800-53-CM-7

Disable Apache Qpid (qpidd)   [ref]rule

The qpidd service provides high speed, secure, guaranteed delivery services. It is an implementation of the Advanced Message Queuing Protocol. By default the qpidd service will bind to port 5672 and listen for connection attempts. The qpidd service can be disabled with the following command:

$ sudo chkconfig qpidd off

Rationale:

The qpidd service is automatically installed when the "base" package selection is selected during installation. The qpidd service listens for network connections, which increases the attack surface of the system. If the system is not intended to receive AMQP traffic, then the qpidd service is not needed and should be disabled or removed.

Severity:  unknown

Identifiers:  CCE-26928-2

References:  SRG-OS-000096, RHEL-06-000267, SV-50449r2_rule, CCI-000382, AC-17(8), CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'qpidd' disable
/sbin/chkconfig --level 0123456 'qpidd' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service qpidd
  service:
    name: qpidd
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_qpidd_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-26928-2
    - NIST-800-53-AC-17(8)
    - NIST-800-53-CM-7
    - DISA-STIG-RHEL-06-000267

Disable Automatic Bug Reporting Tool (abrtd)   [ref]rule

The Automatic Bug Reporting Tool (abrtd) daemon collects and reports crash data when an application crash is detected. Using a variety of plugins, abrtd can email crash reports to system administrators, log crash reports to files, or forward crash reports to a centralized issue tracking system such as RHTSupport. The abrtd service can be disabled with the following command:

$ sudo chkconfig abrtd off

Rationale:

Mishandling crash data could expose sensitive information about vulnerabilities in software executing on the system, as well as sensitive information from within a process's address space or registers.

Severity:  unknown

Identifiers:  CCE-27247-6

References:  SRG-OS-000096, CCI-000381, RHEL-06-000261, SV-50441r2_rule, AC-17(8), CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'abrtd' disable
/sbin/chkconfig --level 0123456 'abrtd' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service abrtd
  service:
    name: abrtd
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_abrtd_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27247-6
    - NIST-800-53-AC-17(8)
    - NIST-800-53-CM-7
    - DISA-STIG-RHEL-06-000261

Disable Cyrus SASL Authentication Daemon (saslauthd)   [ref]rule

The saslauthd service handles plaintext authentication requests on behalf of the SASL library. The service isolates all code requiring superuser privileges for SASL authentication into a single process, and can also be used to provide proxy authentication services to clients that do not understand SASL based authentication. The saslauthd service can be disabled with the following command:

$ sudo chkconfig saslauthd off

Rationale:

The saslauthd service provides essential functionality for performing authentication in some directory environments, such as those which use Kerberos and LDAP. For others, however, in which only local files may be consulted, it is not necessary and should be disabled.

Severity:  unknown

Identifiers:  CCE-27263-3

References:  AC-17(8), CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'saslauthd' disable
/sbin/chkconfig --level 0123456 'saslauthd' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service saslauthd
  service:
    name: saslauthd
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_saslauthd_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27263-3
    - NIST-800-53-AC-17(8)
    - NIST-800-53-CM-7

Disable Control Group Config (cgconfig)   [ref]rule

Control groups allow an administrator to allocate system resources (such as CPU, memory, network bandwidth, etc) among a defined group (or groups) of processes executing on a system. The cgconfig daemon starts at boot and establishes the predefined control groups. The cgconfig service can be disabled with the following command:

$ sudo chkconfig cgconfig off

Rationale:

Unless control groups are used to manage system resources, running the cgconfig service is not necessary.

Severity:  unknown

Identifiers:  CCE-27250-0

References:  CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'cgconfig' disable
/sbin/chkconfig --level 0123456 'cgconfig' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service cgconfig
  service:
    name: cgconfig
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_cgconfig_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27250-0
    - NIST-800-53-CM-7

Disable ntpdate Service (ntpdate)   [ref]rule

The ntpdate service sets the local hardware clock by polling NTP servers when the system boots. It synchronizes to the NTP servers listed in /etc/ntp/step-tickers or /etc/ntp.conf and then sets the local hardware clock to the newly synchronized system time. The ntpdate service can be disabled with the following command:

$ sudo chkconfig ntpdate off

Rationale:

The ntpdate service may only be suitable for systems which are rebooted frequently enough that clock drift does not cause problems between reboots. In any event, the functionality of the ntpdate service is now available in the ntpd program and should be considered deprecated.

Severity:  unknown

Identifiers:  CCE-27256-7

References:  SRG-OS-000096, RHEL-06-000265, SV-50445r2_rule, CCI-000382, AC-17(8), CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'ntpdate' disable
/sbin/chkconfig --level 0123456 'ntpdate' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service ntpdate
  service:
    name: ntpdate
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_ntpdate_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27256-7
    - NIST-800-53-AC-17(8)
    - NIST-800-53-CM-7
    - DISA-STIG-RHEL-06-000265

Disable Network Router Discovery Daemon (rdisc)   [ref]rule

The rdisc service implements the client side of the ICMP Internet Router Discovery Protocol (IRDP), which allows discovery of routers on the local subnet. If a router is discovered then the local routing table is updated with a corresponding default route. By default this daemon is disabled. The rdisc service can be disabled with the following command:

$ sudo chkconfig rdisc off

Rationale:

General-purpose systems typically have their network and routing information configured statically by a system administrator. Workstations or some special-purpose systems often use DHCP (instead of IRDP) to retrieve dynamic network configuration information.

Severity:  unknown

Identifiers:  CCE-27261-7

References:  SRG-OS-000096, RHEL-06-000268, SV-50451r2_rule, CCI-000382, AC-17(8), AC-4, CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'rdisc' disable
/sbin/chkconfig --level 0123456 'rdisc' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service rdisc
  service:
    name: rdisc
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_rdisc_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27261-7
    - NIST-800-53-AC-17(8)
    - NIST-800-53-AC-4
    - NIST-800-53-CM-7
    - DISA-STIG-RHEL-06-000268

Disable Red Hat Subscription Manager Daemon (rhsmcertd)   [ref]rule

The Red Hat Subscription Manager (rhsmcertd) periodically checks for changes in the entitlement certificates for a registered system and updates it accordingly. The rhsmcertd service can be disabled with the following command:

$ sudo chkconfig rhsmcertd off

Rationale:

The rhsmcertd service can provide administrators with some additional control over which of their systems are entitled to particular subscriptions. However, for systems that are managed locally or which are not expected to require remote changes to their subscription status, it is unnecessary and can be disabled.

Severity:  unknown

Identifiers:  CCE-27262-5

References:  CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'rhsmcertd' disable
/sbin/chkconfig --level 0123456 'rhsmcertd' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service rhsmcertd
  service:
    name: rhsmcertd
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_rhsmcertd_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27262-5
    - NIST-800-53-CM-7

Disable Portreserve (portreserve)   [ref]rule

The portreserve service is a TCP port reservation utility that can be used to prevent portmap from binding to well known TCP ports that are required for other services. The portreserve service can be disabled with the following command:

$ sudo chkconfig portreserve off

Rationale:

The portreserve service provides helpful functionality by preventing conflicting usage of ports in the reserved port range, but it can be disabled if not needed.

Severity:  unknown

Identifiers:  CCE-27258-3

References:  AC-17(8), CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'portreserve' disable
/sbin/chkconfig --level 0123456 'portreserve' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service portreserve
  service:
    name: portreserve
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_portreserve_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27258-3
    - NIST-800-53-AC-17(8)
    - NIST-800-53-CM-7

Disable System Statistics Reset Service (sysstat)   [ref]rule

The sysstat service resets various I/O and CPU performance statistics to zero in order to begin counting from a fresh state at boot time. The sysstat service can be disabled with the following command:

$ sudo chkconfig sysstat off

Rationale:

By default the sysstat service merely runs a program at boot to reset the statistics, which can be retrieved using programs such as sar and sadc. These may provide useful insight into system operation, but unless used this service can be disabled.

Severity:  unknown

Identifiers:  CCE-27265-8

References:  CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'sysstat' disable
/sbin/chkconfig --level 0123456 'sysstat' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service sysstat
  service:
    name: sysstat
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_sysstat_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27265-8
    - NIST-800-53-CM-7

Avahi Server   [ref]group

The Avahi daemon implements the DNS Service Discovery and Multicast DNS protocols, which provide service and host discovery on a network. It allows a system to automatically identify resources on the network, such as printers or web servers. This capability is also known as mDNSresponder and is a major part of Zeroconf networking.

contains 1 rule

Disable Avahi Server if Possible   [ref]group

Because the Avahi daemon service keeps an open network port, it is subject to network attacks. Disabling it can reduce the system's vulnerability to such attacks.

contains 1 rule

Disable Avahi Server Software   [ref]rule

The avahi-daemon service can be disabled with the following command:

$ sudo chkconfig avahi-daemon off

Rationale:

Because the Avahi daemon service keeps an open network port, it is subject to network attacks. Its functionality is convenient but is only appropriate if the local network can be trusted.

Severity:  unknown

Identifiers:  CCE-27087-6

References:  SRG-OS-999999, RHEL-06-000246, SV-50419r2_rule, 2.2.3, CCI-000366, CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'avahi-daemon' disable
/sbin/chkconfig --level 0123456 'avahi-daemon' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service avahi-daemon
  service:
    name: avahi-daemon
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_avahi-daemon_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27087-6
    - NIST-800-53-CM-7
    - DISA-STIG-RHEL-06-000246

SSH Server   [ref]group

The SSH protocol is recommended for remote login and remote file transfer. SSH provides confidentiality and integrity for data exchanged between two systems, as well as server authentication, through the use of public key cryptography. The implementation included with the system is called OpenSSH, and more detailed documentation is available from its website, http://www.openssh.org. Its server program is called sshd and provided by the RPM package openssh-server.

contains 3 rules

Configure OpenSSH Server if Necessary   [ref]group

If the system needs to act as an SSH server, then certain changes should be made to the OpenSSH daemon configuration file /etc/ssh/sshd_config. The following recommendations can be applied to this file. See the sshd_config(5) man page for more detailed information.

contains 3 rules

Allow Only SSH Protocol 2   [ref]rule

Only SSH protocol version 2 connections should be permitted. The default setting in /etc/ssh/sshd_config is correct, and can be verified by ensuring that the following line appears:

Protocol 2

Warning:  As of openssh-server version 7.4 and above, the only protocol supported is version 2, and line
Protocol 2
in /etc/ssh/sshd_config is not necessary.
Rationale:

SSH protocol version 1 is an insecure implementation of the SSH protocol and has many well-known vulnerability exploits. Exploits of the SSH daemon could provide immediate root access to the system.

Severity:  high

Remediation Shell script:   (show)

# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append '/etc/ssh/sshd_config' '^Protocol' '2' 'CCE-27072-8' '%s %s'
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:restrict

- name: "Allow Only SSH Protocol 2"
  lineinfile:
    dest: /etc/ssh/sshd_config
    regexp: "^Protocol [0-9]"
    line: "Protocol 2"
    validate: sshd -t -f %s
  #notify: :reload ssh
  tags:
    - sshd_allow_only_protocol2
    - high_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-27072-8
    - NIST-800-53-AC-3(10)
    - NIST-800-53-AC-17(8).1(ii)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-171-3.1.13
    - NIST-800-171-3.5.4
    - CJIS-5.5.6
    - DISA-STIG-RHEL-06-000227

Use Only FIPS 140-2 Validated Ciphers   [ref]rule

Limit the ciphers to those algorithms which are FIPS-approved. Counter (CTR) mode is also preferred over cipher-block chaining (CBC) mode. The following line in /etc/ssh/sshd_config demonstrates use of FIPS-approved ciphers:

Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc
The man page sshd_config(5) contains a list of supported ciphers.

Rationale:

Unapproved mechanisms that are used for authentication to the cryptographic module are not verified and therefore cannot be relied upon to provide confidentiality or integrity, and system data may be compromised.
Operating systems utilizing encryption are required to use FIPS-compliant mechanisms for authenticating to cryptographic modules.
FIPS 140-2 is the current standard for validating that mechanisms used to access cryptographic modules utilize authentication that meets industry and government requirements. For government systems, this allows Security Levels 1, 2, 3, or 4 for use on Red Hat Enterprise Linux.

Severity:  medium

Remediation Shell script:   (show)

grep -q ^Ciphers /etc/ssh/sshd_config && \
  sed -i "s/Ciphers.*/Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc/g" /etc/ssh/sshd_config
if ! [ $? -eq 0 ]; then
    echo "Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc" >> /etc/ssh/sshd_config
fi
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:restrict
- name: Use Only Approved Ciphers
  lineinfile:
    create: yes
    dest: /etc/ssh/sshd_config
    regexp: ^Ciphers
    line: Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc
    validate: sshd -t -f %s
  #notify: restart sshd
  tags:
    - sshd_use_approved_ciphers
    - medium_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-26555-3
    - NIST-800-53-SI-7
    - NIST-800-53-AC-3
    - NIST-800-53-AC-17(2)
    - NIST-800-53-AU-10(5)
    - NIST-800-53-CM-6(b)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-7
    - NIST-800-171-3.1.13
    - NIST-800-171-3.13.11
    - NIST-800-171-3.13.8
    - CJIS-5.5.6
    - DISA-STIG-RHEL-06-000243

System Settings   [ref]group

Contains rules that check correct system settings.

contains 165 rules

Installing and Maintaining Software   [ref]group

The following sections contain information on security-relevant choices during the initial operating system installation process and the setup of software updates.

contains 6 rules

Disk Partitioning   [ref]group

To ensure separation and protection of data, there are top-level system directories which should be placed on their own physical partition or logical volume. The installer's default partitioning scheme creates separate logical volumes for /, /boot, and swap.

  • If starting with any of the default layouts, check the box to \"Review and modify partitioning.\" This allows for the easy creation of additional logical volumes inside the volume group already created, though it may require making /'s logical volume smaller to create space. In general, using logical volumes is preferable to using partitions because they can be more easily adjusted later.
  • If creating a custom layout, create the partitions mentioned in the previous paragraph (which the installer will require anyway), as well as separate ones described in the following sections.
If a system has already been installed, and the default partitioning scheme was used, it is possible but nontrivial to modify it to create separate logical volumes for the directories listed above. The Logical Volume Manager (LVM) makes this possible. See the LVM HOWTO at http://tldp.org/HOWTO/LVM-HOWTO/ for more detailed information on LVM.

contains 2 rules

Ensure /var/log/audit Located On Separate Partition   [ref]rule

Audit logs are stored in the /var/log/audit directory. Ensure that it has its own partition or logical volume at installation time, or migrate it later using LVM. Make absolutely certain that it is large enough to store all audit logs that will be created by the auditing daemon.

Rationale:

Placing /var/log/audit in its own partition enables better separation between audit files and other files, and helps ensure that auditing cannot be halted due to the partition running out of space.

Severity:  low

Ensure /var/log Located On Separate Partition   [ref]rule

System logs are stored in the /var/log directory. Ensure that it has its own partition or logical volume at installation time, or migrate it using LVM.

Rationale:

Placing /var/log in its own partition enables better separation between log files and other files in /var/.

Severity:  unknown

Identifiers:  CCE-26215-4

References:  RHEL-06-000003, SV-50263r1_rule, CCI-001208, SRG-OS-999999, 1.1.11, AU-9, SC-32

System and Software Integrity   [ref]group

System and software integrity can be gained by installing antivirus, increasing system encryption strength with FIPS, verifying installed software, enabling SELinux, installing an Intrusion Prevention System, etc. However, installing or enabling integrity checking tools cannot prevent intrusions, but they can detect that an intrusion may have occurred. Requirements for integrity checking may be highly dependent on the environment in which the system will be used. Snapshot-based approaches such as AIDE may induce considerable overhead in the presence of frequent software updates.

contains 4 rules

Software Integrity Checking   [ref]group

Both the AIDE (Advanced Intrusion Detection Environment) software and the RPM package management system provide mechanisms for verifying the integrity of installed software. AIDE uses snapshots of file metadata (such as hashes) and compares these to current system files in order to detect changes.

The RPM package management system can conduct integrity checks by comparing information in its metadata database with files installed on the system.

contains 4 rules

Verify Integrity with RPM   [ref]group

The RPM package management system includes the ability to verify the integrity of installed packages by comparing the installed files with information about the files taken from the package metadata stored in the RPM database. Although an attacker could corrupt the RPM database (analogous to attacking the AIDE database as described above), this check can still reveal modification of important files. To list which files on the system differ from what is expected by the RPM database:

$ rpm -qVa
See the man page for rpm to see a complete explanation of each column.

contains 1 rule

Verify and Correct File Permissions with RPM   [ref]rule

The RPM package management system can check file access permissions of installed software packages, including many that are important to system security. Verify that the file permissions of system files and commands match vendor values. Check the file permissions with the following command:

$ sudo rpm -Va | grep '^.M'
Output indicates files that do not match vendor defaults. After locating a file with incorrect permissions, run the following command to determine which package owns it:
$ rpm -qf FILENAME

Next, run the following command to reset its permissions to the correct values:
$ sudo rpm --quiet --setperms PACKAGENAME

Warning:  Note: Due to a bug in the gdm package, the RPM verify command may continue to fail even after file permissions have been correctly set on /var/log/gdm. This is being tracked in Red Hat Bugzilla #1277603.
Rationale:

Permissions on system binaries and configuration files that are too generous could allow an unauthorized user to gain privileges that they should not have. The permissions set by the vendor should be maintained. Any deviations from this baseline should be investigated.

Severity:  high

Remediation Shell script:   (show)

Complexity:high
Disruption:medium
Strategy:restrict

# Declare array to hold list of RPM packages we need to correct permissions for
declare -a SETPERMS_RPM_LIST

# Create a list of files on the system having permissions different from what
# is expected by the RPM database
FILES_WITH_INCORRECT_PERMS=($(rpm -Va --nofiledigest | grep '^.M' | awk '{print $NF}'))

# For each file path from that list:
# * Determine the RPM package the file path is shipped by,
# * Include it into SETPERMS_RPM_LIST array

for FILE_PATH in "${FILES_WITH_INCORRECT_PERMS[@]}"
do
	RPM_PACKAGE=$(rpm -qf "$FILE_PATH")
	SETPERMS_RPM_LIST=("${SETPERMS_RPM_LIST[@]}" "$RPM_PACKAGE")
done

# Remove duplicate mention of same RPM in $SETPERMS_RPM_LIST (if any)
SETPERMS_RPM_LIST=( $(echo "${SETPERMS_RPM_LIST[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ') )

# For each of the RPM packages left in the list -- reset its permissions to the
# correct values
for RPM_PACKAGE in "${SETPERMS_RPM_LIST[@]}"
do
	rpm --quiet --setperms "${RPM_PACKAGE}"
done
Remediation Ansible snippet:   (show)

Complexity:high
Disruption:medium
Strategy:restrict
- name: "Read list of files with incorrect permissions"
  shell: "rpm -Va --nofiledigest | awk '/^.M/ {print $NF}'"
  register: files_with_incorrect_permissions
  failed_when: False
  changed_when: False
  check_mode: no
  tags:
    - rpm_verify_permissions
    - high_severity
    - restrict_strategy
    - high_complexity
    - medium_disruption
    - CCE-26731-0
    - NIST-800-53-SI-7
    - NIST-800-53-AC-6
    - NIST-800-53-AU-9(1)
    - NIST-800-53-AU-9(3)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-CM-6(3)
    - NIST-800-171-3.3.8
    - NIST-800-171-3.4.1
    - PCI-DSS-Req-11.5
    - CJIS-5.10.4.1
    - DISA-STIG-RHEL-06-000518

- name: "Correct file permissions with RPM"
  shell: "rpm --quiet --setperms $(rpm -qf '{{item}}')"
  with_items: "{{ files_with_incorrect_permissions.stdout_lines }}"
  when: files_with_incorrect_permissions.stdout_lines | length > 0
  tags:
    - rpm_verify_permissions
    - high_severity
    - restrict_strategy
    - high_complexity
    - medium_disruption
    - CCE-26731-0
    - NIST-800-53-SI-7
    - NIST-800-53-AC-6
    - NIST-800-53-AU-9(1)
    - NIST-800-53-AU-9(3)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-CM-6(3)
    - NIST-800-171-3.3.8
    - NIST-800-171-3.4.1
    - PCI-DSS-Req-11.5
    - CJIS-5.10.4.1
    - DISA-STIG-RHEL-06-000518

Verify Integrity with AIDE   [ref]group

AIDE conducts integrity checks by comparing information about files with previously-gathered information. Ideally, the AIDE database is created immediately after initial system configuration, and then again after any software update. AIDE is highly configurable, with further configuration information located in /usr/share/doc/aide-VERSION.

contains 3 rules

Install AIDE   [ref]rule

The aide package can be installed with the following command:

$ sudo yum install aide

Rationale:

The AIDE package must be installed if it is to be available for integrity checking.

Severity:  medium

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable
# Function to install packages on RHEL, Fedora, Debian, and possibly other systems.
#
# Example Call(s):
#
#     package_install aide
#
function package_install {

# Load function arguments into local variables
local package="$1"

# Check sanity of the input
if [ $# -ne "1" ]
then
  echo "Usage: package_install 'package_name'"
  echo "Aborting."
  exit 1
fi

if which dnf ; then
  if ! rpm -q --quiet "$package"; then
    dnf install -y "$package"
  fi
elif which yum ; then
  if ! rpm -q --quiet "$package"; then
    yum install -y "$package"
  fi
elif which apt-get ; then
  apt-get install -y "$package"
else
  echo "Failed to detect available packaging system, tried dnf, yum and apt-get!"
  echo "Aborting."
  exit 1
fi

}

package_install aide
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure aide is installed
  package:
    name: aide
    state: present
  tags:
    - package_aide_installed
    - medium_severity
    - enable_strategy
    - low_complexity
    - low_disruption
    - CCE-27024-9
    - NIST-800-53-CM-3(d)
    - NIST-800-53-CM-3(e)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-CM-6(3)
    - NIST-800-53-SC-28
    - NIST-800-53-SI-7
    - PCI-DSS-Req-11.5
    - CJIS-5.10.1.3
    - DISA-STIG-RHEL-06-000016
Remediation Puppet snippet:   (show)

Complexity:low
Disruption:low
Strategy:enable
include install_aide

class install_aide {
  package { 'aide':
    ensure => 'installed',
  }
}
Remediation Anaconda snippet:   (show)

Complexity:low
Disruption:low
Strategy:enable

package --add=aide

Configure Periodic Execution of AIDE   [ref]rule

At a minimum, AIDE should be configured to run a weekly scan. At most, AIDE should be run daily. 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.

Severity:  medium

Remediation Shell script:   (show)

# Function to install packages on RHEL, Fedora, Debian, and possibly other systems.
#
# Example Call(s):
#
#     package_install aide
#
function package_install {

# Load function arguments into local variables
local package="$1"

# Check sanity of the input
if [ $# -ne "1" ]
then
  echo "Usage: package_install 'package_name'"
  echo "Aborting."
  exit 1
fi

if which dnf ; then
  if ! rpm -q --quiet "$package"; then
    dnf install -y "$package"
  fi
elif which yum ; then
  if ! rpm -q --quiet "$package"; then
    yum install -y "$package"
  fi
elif which apt-get ; then
  apt-get install -y "$package"
else
  echo "Failed to detect available packaging system, tried dnf, yum and apt-get!"
  echo "Aborting."
  exit 1
fi

}

package_install aide

if ! grep -q "/usr/sbin/aide --check" /etc/crontab ; then
    echo "05 4 * * * root /usr/sbin/aide --check" >> /etc/crontab
fi
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:restrict
- name: "Ensure AIDE is installed"
  package:
    name: "{{item}}"
    state: present
  with_items:
    - aide
  tags:
    - aide_periodic_cron_checking
    - medium_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-27222-9
    - NIST-800-53-CM-3(d)
    - NIST-800-53-CM-3(e)
    - NIST-800-53-CM-3(5)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-CM-6(3)
    - NIST-800-53-SC-28
    - NIST-800-53-SI-7
    - PCI-DSS-Req-11.5
    - CJIS-5.10.1.3
    - DISA-STIG-RHEL-06-000306

- name: "Configure Periodic Execution of AIDE"
  cron:
    name: "run AIDE check"
    minute: 05
    hour: 04
    weekday: 0
    user: root
    job: "/usr/sbin/aide --check"
  tags:
    - aide_periodic_cron_checking
    - medium_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-27222-9
    - NIST-800-53-CM-3(d)
    - NIST-800-53-CM-3(e)
    - NIST-800-53-CM-3(5)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-CM-6(3)
    - NIST-800-53-SC-28
    - NIST-800-53-SI-7
    - PCI-DSS-Req-11.5
    - CJIS-5.10.1.3
    - DISA-STIG-RHEL-06-000306

Build and Test AIDE Database   [ref]rule

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.

Severity:  medium

Remediation Shell script:   (show)

# Function to install packages on RHEL, Fedora, Debian, and possibly other systems.
#
# Example Call(s):
#
#     package_install aide
#
function package_install {

# Load function arguments into local variables
local package="$1"

# Check sanity of the input
if [ $# -ne "1" ]
then
  echo "Usage: package_install 'package_name'"
  echo "Aborting."
  exit 1
fi

if which dnf ; then
  if ! rpm -q --quiet "$package"; then
    dnf install -y "$package"
  fi
elif which yum ; then
  if ! rpm -q --quiet "$package"; then
    yum install -y "$package"
  fi
elif which apt-get ; then
  apt-get install -y "$package"
else
  echo "Failed to detect available packaging system, tried dnf, yum and apt-get!"
  echo "Aborting."
  exit 1
fi

}

package_install aide

/usr/sbin/aide --init
/bin/cp -p /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:restrict
- name: "Ensure AIDE is installed"
  package:
    name: "{{item}}"
    state: present
  with_items:
    - aide
  tags:
    - aide_build_database
    - medium_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-27135-3
    - NIST-800-53-CM-3(d)
    - NIST-800-53-CM-3(e)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-CM-6(3)
    - NIST-800-53-SC-28
    - NIST-800-53-SI-7
    - PCI-DSS-Req-11.5
    - CJIS-5.10.1.3
    - DISA-STIG-RHEL-06-000018

- name: "Build and Test AIDE Database"
  shell: /usr/sbin/aide --init
  tags:
    - aide_build_database
    - medium_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-27135-3
    - NIST-800-53-CM-3(d)
    - NIST-800-53-CM-3(e)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-CM-6(3)
    - NIST-800-53-SC-28
    - NIST-800-53-SI-7
    - PCI-DSS-Req-11.5
    - CJIS-5.10.1.3
    - DISA-STIG-RHEL-06-000018

# mainly to allow ansible's check mode to work
- name: "Check whether the stock AIDE Database exists"
  stat:
    path: /var/lib/aide/aide.db.new.gz
  register: aide_database_stat
  tags:
    - aide_build_database
    - medium_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-27135-3
    - NIST-800-53-CM-3(d)
    - NIST-800-53-CM-3(e)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-CM-6(3)
    - NIST-800-53-SC-28
    - NIST-800-53-SI-7
    - PCI-DSS-Req-11.5
    - CJIS-5.10.1.3
    - DISA-STIG-RHEL-06-000018

- name: "Stage AIDE Database"
  copy:
    src: /var/lib/aide/aide.db.new.gz
    dest: /var/lib/aide/aide.db.gz
    backup: yes
    remote_src: yes
  when: aide_database_stat.stat.exists is defined and aide_database_stat.stat.exists
  tags:
    - aide_build_database
    - medium_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-27135-3
    - NIST-800-53-CM-3(d)
    - NIST-800-53-CM-3(e)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-CM-6(3)
    - NIST-800-53-SC-28
    - NIST-800-53-SI-7
    - PCI-DSS-Req-11.5
    - CJIS-5.10.1.3
    - DISA-STIG-RHEL-06-000018

Configure Syslog   [ref]group

The syslog service has been the default Unix logging mechanism for many years. It has a number of downsides, including inconsistent log format, lack of authentication for received messages, and lack of authentication, encryption, or reliable transport for messages sent over a network. However, due to its long history, syslog is a de facto standard which is supported by almost all Unix applications.

In Red Hat Enterprise Linux 6, rsyslog has replaced ksyslogd as the syslog daemon of choice, and it includes some additional security features such as reliable, connection-oriented (i.e. TCP) transmission of logs, the option to log to database formats, and the encryption of log data en route to a central logging server. This section discusses how to configure rsyslog for best effect, and how to use tools provided with the system to maintain and monitor logs.

contains 5 rules

Ensure Proper Configuration of Log Files   [ref]group

The file /etc/rsyslog.conf controls where log message are written. These are controlled by lines called rules, which consist of a selector and an action. These rules are often customized depending on the role of the system, the requirements of the environment, and whatever may enable the administrator to most effectively make use of log data. The default rules in Red Hat Enterprise Linux 6 are:

*.info;mail.none;authpriv.none;cron.none                /var/log/messages
authpriv.*                                              /var/log/secure
mail.*                                                  -/var/log/maillog
cron.*                                                  /var/log/cron
*.emerg                                                 *
uucp,news.crit                                          /var/log/spooler
local7.*                                                /var/log/boot.log
See the man page rsyslog.conf(5) for more information. Note that the rsyslog daemon can be configured to use a timestamp format that some log processing programs may not understand. If this occurs, edit the file /etc/rsyslog.conf and add or edit the following line:
$ ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat

contains 2 rules

Ensure Log Files Are Owned By Appropriate User   [ref]rule

The owner of all log files written by rsyslog should be (N/A). 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 owner:

$ ls -l LOGFILE
If the owner is not (N/A), run the following command to correct this:
$ sudo chown (N/A) LOGFILE

Rationale:

The log files generated by rsyslog contain valuable information regarding system configuration, user authentication, and other such information. Log files should be protected from unauthorized access.

Severity:  medium

Identifiers:  CCE-26812-8

References:  RHEL-06-000133, SV-50319r2_rule, SRG-OS-000206, CCI-001314, AC-6, SI-11, Req-10.5.1, Req-10.5.2

Ensure Log Files Are Owned By Appropriate Group   [ref]rule

The group-owner of all log files written by rsyslog should be (N/A). 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 group owner:

$ ls -l LOGFILE
If the owner is not (N/A), run the following command to correct this:
$ sudo chgrp (N/A) LOGFILE

Rationale:

The log files generated by rsyslog contain valuable information regarding system configuration, user authentication, and other such information. Log files should be protected from unauthorized access.

Severity:  medium

Identifiers:  CCE-26821-9

References:  RHEL-06-000134, SV-50320r2_rule, SRG-OS-000206, CCI-001314, AC-6, SI-11, Req-10.5.1, Req-10.5.2

Configure rsyslogd to Accept Remote Messages If Acting as a Log Server   [ref]group

By default, rsyslog does not listen over the network for log messages. If needed, modules can be enabled to allow the rsyslog daemon to receive messages from other systems and for the system thus to act as a log server. If the system is not a log server, then lines concerning these modules should remain commented out.

contains 1 rule

Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server   [ref]rule

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.

Severity:  unknown

Ensure All Logs are Rotated by logrotate   [ref]group

Edit the file /etc/logrotate.d/syslog. Find the first line, which should look like this (wrapped for clarity):

/var/log/messages /var/log/secure /var/log/maillog /var/log/spooler \
  /var/log/boot.log /var/log/cron {
Edit this line so that it contains a one-space-separated listing of each log file referenced in /etc/rsyslog.conf.

All logs in use on a system must be rotated regularly, or the log files will consume disk space over time, eventually interfering with system operation. The file /etc/logrotate.d/syslog is the configuration file used by the logrotate program to maintain all log files written by syslog. By default, it rotates logs weekly and stores four archival copies of each log. These settings can be modified by editing /etc/logrotate.conf, but the defaults are sufficient for purposes of this guide.

Note that logrotate is run nightly by the cron job /etc/cron.daily/logrotate. If particularly active logs need to be rotated more often than once a day, some other mechanism must be used.

contains 1 rule

Ensure Logrotate Runs Periodically   [ref]rule

The logrotate utility allows for the automatic rotation of log files. The frequency of rotation is specified in /etc/logrotate.conf, which triggers a cron task. To configure logrotate to run daily, add or correct the following line in /etc/logrotate.conf:

# rotate log files frequency
daily

Rationale:

Log files that are not properly rotated run the risk of growing so large that they fill up the /var/log partition. Valuable logging information could be lost if the /var/log partition becomes full.

Severity:  unknown

Identifiers:  CCE-27014-0

References:  SRG-OS-999999, RHEL-06-000138, SV-50425r1_rule, CCI-000366, AU-9, Req-10.7

Remediation Shell script:   (show)


LOGROTATE_CONF_FILE="/etc/logrotate.conf"
CRON_DAILY_LOGROTATE_FILE="/etc/cron.daily/logrotate"

# daily rotation is configured
grep -q "^daily$" $LOGROTATE_CONF_FILE|| echo "daily" >> $LOGROTATE_CONF_FILE

# remove any line configuring weekly, monthly or yearly rotation
sed -i -r "/^(weekly|monthly|yearly)$/d" $LOGROTATE_CONF_FILE

# configure cron.daily if not already
if ! grep -q "^[[:space:]]*/usr/sbin/logrotate[[:alnum:][:blank:][:punct:]]*$LOGROTATE_CONF_FILE$" $CRON_DAILY_LOGROTATE_FILE; then
	echo "#!/bin/sh" > $CRON_DAILY_LOGROTATE_FILE
	echo "/usr/sbin/logrotate $LOGROTATE_CONF_FILE" >> $CRON_DAILY_LOGROTATE_FILE
fi

Ensure rsyslog is Installed   [ref]rule

Rsyslog is installed by default. The rsyslog package can be installed with the following command:

 $ sudo yum install rsyslog

Rationale:

The rsyslog package provides the rsyslog daemon, which provides system logging services.

Severity:  medium

Identifiers:  CCE-26809-4

References:  NT28(R5), NT28(R46), 4.2.3, CCI-001311, CCI-001312, 164.312(a)(2)(ii), A.12.3.1, AU-9(2)

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable
# Function to install packages on RHEL, Fedora, Debian, and possibly other systems.
#
# Example Call(s):
#
#     package_install aide
#
function package_install {

# Load function arguments into local variables
local package="$1"

# Check sanity of the input
if [ $# -ne "1" ]
then
  echo "Usage: package_install 'package_name'"
  echo "Aborting."
  exit 1
fi

if which dnf ; then
  if ! rpm -q --quiet "$package"; then
    dnf install -y "$package"
  fi
elif which yum ; then
  if ! rpm -q --quiet "$package"; then
    yum install -y "$package"
  fi
elif which apt-get ; then
  apt-get install -y "$package"
else
  echo "Failed to detect available packaging system, tried dnf, yum and apt-get!"
  echo "Aborting."
  exit 1
fi

}

package_install rsyslog
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure rsyslog is installed
  package:
    name: rsyslog
    state: present
  tags:
    - package_rsyslog_installed
    - medium_severity
    - enable_strategy
    - low_complexity
    - low_disruption
    - CCE-26809-4
    - NIST-800-53-AU-9(2)
Remediation Puppet snippet:   (show)

Complexity:low
Disruption:low
Strategy:enable
include install_rsyslog

class install_rsyslog {
  package { 'rsyslog':
    ensure => 'installed',
  }
}
Remediation Anaconda snippet:   (show)

Complexity:low
Disruption:low
Strategy:enable

package --add=rsyslog

Network Configuration and Firewalls   [ref]group

Most systems must be connected to a network of some sort, and this brings with it the substantial risk of network attack. This section discusses the security impact of decisions about networking which must be made when configuring a system.

This section also discusses firewalls, network access controls, and other network security frameworks, which allow system-level rules to be written that can limit an attackers' ability to connect to your system. These rules can specify that network traffic should be allowed or denied from certain IP addresses, hosts, and networks. The rules can also specify which of the system's network services are available to particular hosts or networks.

contains 33 rules

IPv6   [ref]group

The system includes support for Internet Protocol version 6. A major and often-mentioned improvement over IPv4 is its enormous increase in the number of available addresses. Another important feature is its support for automatic configuration of many network settings.

contains 4 rules

Configure IPv6 Settings if Necessary   [ref]group

A major feature of IPv6 is the extent to which systems implementing it can automatically configure their networking devices using information from the network. From a security perspective, manually configuring important configuration information is preferable to accepting it from the network in an unauthenticated fashion.

contains 2 rules

Disable Automatic Configuration   [ref]group

Disable the system's acceptance of router advertisements and redirects by adding or correcting the following line in /etc/sysconfig/network (note that this does not disable sending router solicitations):

IPV6_AUTOCONF=no

contains 2 rules

Configure Accepting IPv6 Router Advertisements by Default   [ref]rule

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
If this is not the system default value, 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.

Severity:  unknown

Identifiers:  CCE-27164-3

References:  4.4.1.1, 3.3.1, 3.1.20, CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable

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
#
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append '/etc/sysctl.conf' '^net.ipv6.conf.default.accept_ra' "$sysctl_net_ipv6_conf_default_accept_ra_value" 'CCE-27164-3'
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- 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: yes
  tags:
    - sysctl_net_ipv6_conf_default_accept_ra
    - unknown_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-27164-3
    - NIST-800-53-CM-7
    - NIST-800-171-3.1.20

Configure Accepting IPv6 Redirects By Default   [ref]rule

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
If this is not the system default value, 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.

Severity:  medium

Identifiers:  CCE-27166-8

References:  4.4.1.2, SRG-OS-999999, RHEL-06-000099, SV-50349r3_rule, 3.3.2, 3.1.20, CCI-001551, CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable

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
#
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append '/etc/sysctl.conf' '^net.ipv6.conf.default.accept_redirects' "$sysctl_net_ipv6_conf_default_accept_redirects_value" 'CCE-27166-8'
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- 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: yes
  tags:
    - sysctl_net_ipv6_conf_default_accept_redirects
    - medium_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-27166-8
    - NIST-800-53-CM-7
    - NIST-800-171-3.1.20
    - DISA-STIG-RHEL-06-000099

Disable Support for IPv6 Unless Needed   [ref]group

Despite configuration that suggests support for IPv6 has been disabled, link-local IPv6 address auto-configuration occurs even when only an IPv4 address is assigned. The only way to effectively prevent execution of the IPv6 networking stack is to instruct the system not to activate the IPv6 kernel module.

contains 2 rules

Disable Support for RPC IPv6   [ref]rule

RPC services for NFSv4 try to load transport modules for udp6 and tcp6 by default, even if IPv6 has been disabled in /etc/modprobe.d. To prevent RPC services such as rpc.mountd from attempting to start IPv6 network listeners, remove or comment out the following two lines in /etc/netconfig:

udp6       tpi_clts      v     inet6    udp     -       -
tcp6       tpi_cots_ord  v     inet6    tcp     -       -

Rationale:

Severity:  unknown

Identifiers:  CCE-27232-8

References:  3.1.20, CM-7

Remediation Shell script:   (show)


# Drop 'tcp6' and 'udp6' entries from /etc/netconfig to prevent RPC
# services for NFSv4 from attempting to start IPv6 network listeners
declare -a IPV6_RPC_ENTRIES=("tcp6" "udp6")

for rpc_entry in ${IPV6_RPC_ENTRIES[@]}
do
	sed -i "/^$rpc_entry[[:space:]]\+tpi\_.*inet6.*/d" /etc/netconfig
done

Disable IPv6 Networking Support Automatic Loading   [ref]rule

To prevent the IPv6 kernel module (ipv6) from binding to the IPv6 networking stack, add the following line to /etc/modprobe.d/disabled.conf (or another file in /etc/modprobe.d):

options ipv6 disable=1
This permits the IPv6 module to be loaded (and thus satisfy other modules that depend on it), while disabling support for the IPv6 protocol.

Rationale:

Any unnecessary network stacks - including IPv6 - should be disabled, to reduce the vulnerability to exploitation.

Severity:  medium

Identifiers:  CCE-27153-6

References:  CCI-001551, SRG-OS-999999, RHEL-06-000098, CM-7

Remediation Shell script:   (show)


# Prevent the IPv6 kernel module (ipv6) from loading the IPv6 networking stack
echo "options ipv6 disable=1" > /etc/modprobe.d/ipv6.conf

# Since according to: https://access.redhat.com/solutions/72733
# "ipv6 disable=1" options doesn't always disable the IPv6 networking stack from
# loading, instruct also sysctl configuration to disable IPv6 according to:
# https://access.redhat.com/solutions/8709#rhel6disable

declare -a IPV6_SETTINGS=("net.ipv6.conf.all.disable_ipv6" "net.ipv6.conf.default.disable_ipv6")

for setting in ${IPV6_SETTINGS[@]}
do
	# Set runtime =1 for setting
	/sbin/sysctl -q -n -w "$setting=1"

	# If setting is present in /etc/sysctl.conf, change value to "1"
	# else, add "$setting = 1" to /etc/sysctl.conf
	if grep -q ^"$setting" /etc/sysctl.conf ; then
		sed -i "s/^$setting.*/$setting = 1/g" /etc/sysctl.conf
	else
		echo "" >> /etc/sysctl.conf
		echo "# Set $setting = 1 per security requirements" >> /etc/sysctl.conf
		echo "$setting = 1" >> /etc/sysctl.conf
	fi
done

iptables and ip6tables   [ref]group

A host-based firewall called netfilter is included as part of the Linux kernel distributed with the system. It is activated by default. This firewall is controlled by the program iptables, and the entire capability is frequently referred to by this name. An analogous program called ip6tables handles filtering for IPv6.

Unlike TCP Wrappers, which depends on the network server program to support and respect the rules written, netfilter filtering occurs at the kernel level, before a program can even process the data from the network packet. As such, any program on the system is affected by the rules written.

This section provides basic information about strengthening the iptables and ip6tables configurations included with the system. For more complete information that may allow the construction of a sophisticated ruleset tailored to your environment, please consult the references at the end of this section.

contains 5 rules

Inspect and Activate Default Rules   [ref]group

View the currently-enforced iptables rules by running the command:

$ sudo iptables -nL --line-numbers
The command is analogous for ip6tables.

If the firewall does not appear to be active (i.e., no rules appear), activate it and ensure that it starts at boot by issuing the following commands (and analogously for ip6tables):
$ sudo service iptables restart
The default iptables rules are:
Chain INPUT (policy ACCEPT)
num  target     prot opt source       destination
1    ACCEPT     all  --  0.0.0.0/0    0.0.0.0/0    state RELATED,ESTABLISHED 
2    ACCEPT     icmp --  0.0.0.0/0    0.0.0.0/0
3    ACCEPT     all  --  0.0.0.0/0    0.0.0.0/0
4    ACCEPT     tcp  --  0.0.0.0/0    0.0.0.0/0    state NEW tcp dpt:22 
5    REJECT     all  --  0.0.0.0/0    0.0.0.0/0    reject-with icmp-host-prohibited 

Chain FORWARD (policy ACCEPT)
num  target     prot opt source       destination
1    REJECT     all  --  0.0.0.0/0    0.0.0.0/0    reject-with icmp-host-prohibited 

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source       destination
The ip6tables default rules are essentially the same.

contains 3 rules

Verify ip6tables Enabled if Using IPv6   [ref]rule

The ip6tables service can be enabled with the following command:

$ sudo chkconfig --level 2345 ip6tables on

Rationale:

The ip6tables service provides the system's host-based firewalling capability for IPv6 and ICMPv6.

Severity:  medium

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'ip6tables' disable
/sbin/chkconfig --level 0123456 'ip6tables' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:enable
- name: Enable service ip6tables
  service:
    name: ip6tables
    enabled: "yes"
    state: "started"
  tags:
    - service_ip6tables_enabled
    - medium_severity
    - enable_strategy
    - low_complexity
    - low_disruption
    - CCE-27006-6
    - NIST-800-53-AC-4
    - NIST-800-53-CA-3(c)
    - NIST-800-53-CM-7
    - DISA-STIG-RHEL-06-000103

Set Default ip6tables Policy for Incoming Packets   [ref]rule

To set the default policy to DROP (instead of ACCEPT) for the built-in INPUT chain which processes incoming packets, add or correct the following line in /etc/sysconfig/ip6tables:

:INPUT DROP [0:0]
If changes were required, reload the ip6tables rules:
$ sudo service ip6tables reload

Rationale:

In ip6tables, the default policy is applied only after all the applicable rules in the table are examined for a match. Setting the default policy to DROP implements proper design for a firewall, i.e. any packets which are not explicitly permitted should not be accepted.

Severity:  medium

Identifiers:  CCE-27317-7

References:  CCI-000066, SRG-OS-000231, RHEL-06-000523, SV-50244r2_rule, CM-7

Remediation Shell script:   (show)

sed -i 's/^:INPUT ACCEPT.*/:INPUT DROP [0:0]/g' /etc/sysconfig/ip6tables

Verify iptables Enabled   [ref]rule

The iptables service can be enabled with the following command:

$ sudo chkconfig --level 2345 iptables on

Rationale:

The iptables service provides the system's host-based firewalling capability for IPv4 and ICMP.

Severity:  medium

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'iptables' disable
/sbin/chkconfig --level 0123456 'iptables' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:enable
- name: Enable service iptables
  service:
    name: iptables
    enabled: "yes"
    state: "started"
  tags:
    - service_iptables_enabled
    - medium_severity
    - enable_strategy
    - low_complexity
    - low_disruption
    - CCE-27018-1
    - NIST-800-53-AC-4
    - NIST-800-53-CA-3(c)
    - NIST-800-53-CM-7
    - DISA-STIG-RHEL-06-000117

Strengthen the Default Ruleset   [ref]group

The default rules can be strengthened. The system scripts that activate the firewall rules expect them to be defined in the configuration files iptables and ip6tables in the directory /etc/sysconfig. Many of the lines in these files are similar to the command line arguments that would be provided to the programs /sbin/iptables or /sbin/ip6tables - but some are quite different.

The following recommendations describe how to strengthen the default ruleset configuration file. An alternative to editing this configuration file is to create a shell script that makes calls to the iptables program to load in rules, and then invokes service iptables save to write those loaded rules to /etc/sysconfig/iptables.

The following alterations can be made directly to /etc/sysconfig/iptables and /etc/sysconfig/ip6tables. Instructions apply to both unless otherwise noted. Language and address conventions for regular iptables are used throughout this section; configuration for ip6tables will be either analogous or explicitly covered.

Warning:  The program system-config-securitylevel allows additional services to penetrate the default firewall rules and automatically adjusts /etc/sysconfig/iptables. This program is only useful if the default ruleset meets your security requirements. Otherwise, this program should not be used to make changes to the firewall configuration because it re-writes the saved configuration file.
contains 2 rules

Set Default iptables Policy for Forwarded Packets   [ref]rule

To set the default policy to DROP (instead of ACCEPT) for the built-in FORWARD chain which processes packets that will be forwarded from one interface to another, add or correct the following line in /etc/sysconfig/iptables:

:FORWARD DROP [0:0]

Rationale:

In iptables, the default policy is applied only after all the applicable rules in the table are examined for a match. Setting the default policy to DROP implements proper design for a firewall, i.e. any packets which are not explicitly permitted should not be accepted.

Severity:  medium

Identifiers:  CCE-27186-6

References:  CCI-001109, SRG-OS-000147, RHEL-06-000320, SV-50487r2_rule, CM-7

Remediation Shell script:   (show)

sed -i 's/^:FORWARD ACCEPT.*/:FORWARD DROP [0:0]/g' /etc/sysconfig/iptables

Set Default iptables Policy for Incoming Packets   [ref]rule

To set the default policy to DROP (instead of ACCEPT) for the built-in INPUT chain which processes incoming packets, add or correct the following line in /etc/sysconfig/iptables:

:INPUT DROP [0:0]

Rationale:

In iptables the default policy is applied only after all the applicable rules in the table are examined for a match. Setting the default policy to DROP implements proper design for a firewall, i.e. any packets which are not explicitly permitted should not be accepted.

Severity:  medium

Remediation Shell script:   (show)

sed -i 's/^:INPUT ACCEPT.*/:INPUT DROP [0:0]/g' /etc/sysconfig/iptables

Kernel Parameters Which Affect Networking   [ref]group

The sysctl utility is used to set parameters which affect the operation of the Linux kernel. Kernel parameters which affect networking and have security implications are described here.

contains 14 rules

Network Related Kernel Runtime Parameters for Hosts and Routers   [ref]group

Certain kernel parameters should be set for systems which are acting as either hosts or routers to improve the system's ability defend against certain types of IPv4 protocol attacks.

contains 11 rules

Configure Kernel Parameter for Accepting Source-Routed Packets By Default   [ref]rule

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
If this is not the system default value, 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.

Severity:  medium

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable

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
#
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append '/etc/sysctl.conf' '^net.ipv4.conf.default.accept_source_route' "$sysctl_net_ipv4_conf_default_accept_source_route_value" 'CCE-26983-7'
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- 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: yes
  tags:
    - sysctl_net_ipv4_conf_default_accept_source_route
    - medium_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-26983-7
    - NIST-800-53-AC-4
    - NIST-800-53-CM-7
    - NIST-800-53-SC-5
    - NIST-800-53-SC-7
    - NIST-800-171-3.1.20
    - CJIS-5.10.1.1
    - DISA-STIG-RHEL-06-000089

Configure Kernel Parameter to Ignore Bogus ICMP Error Responses   [ref]rule

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
If this is not the system default value, 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.

Severity:  unknown

Identifiers:  CCE-26993-6

References:  SRG-OS-999999, RHEL-06-000093, SV-50338r2_rule, 3.2.6, 3.1.20, CM-7, SC-5

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable

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
#
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append '/etc/sysctl.conf' '^net.ipv4.icmp_ignore_bogus_error_responses' "$sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value" 'CCE-26993-6'
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- 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: yes
  tags:
    - sysctl_net_ipv4_icmp_ignore_bogus_error_responses
    - unknown_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-26993-6
    - NIST-800-53-CM-7
    - NIST-800-53-SC-5
    - NIST-800-171-3.1.20
    - DISA-STIG-RHEL-06-000093

Configure Kernel Parameter for Accepting ICMP Redirects By Default   [ref]rule

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
If this is not the system default value, 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.

Severity:  medium

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable

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
#
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append '/etc/sysctl.conf' '^net.ipv4.conf.default.accept_redirects' "$sysctl_net_ipv4_conf_default_accept_redirects_value" 'CCE-27015-7'
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- 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: yes
  tags:
    - sysctl_net_ipv4_conf_default_accept_redirects
    - medium_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-27015-7
    - NIST-800-53-AC-4
    - NIST-800-53-CM-7
    - NIST-800-53-SC-5
    - NIST-800-53-SC-7
    - NIST-800-171-3.1.20
    - CJIS-5.10.1.1
    - DISA-STIG-RHEL-06-000091

Configure Kernel Parameter to Use Reverse Path Filtering by Default   [ref]rule

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
If this is not the system default value, 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.

Severity:  medium

Identifiers:  CCE-26915-9

References:  SRG-OS-999999, RHEL-06-000097, SV-50345r2_rule, 3.2.7, 3.1.20, AC-4, SC-5, SC-7

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable

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
#
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append '/etc/sysctl.conf' '^net.ipv4.conf.default.rp_filter' "$sysctl_net_ipv4_conf_default_rp_filter_value" 'CCE-26915-9'
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- 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: yes
  tags:
    - sysctl_net_ipv4_conf_default_rp_filter
    - medium_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-26915-9
    - NIST-800-53-AC-4
    - NIST-800-53-SC-5
    - NIST-800-53-SC-7
    - NIST-800-171-3.1.20
    - DISA-STIG-RHEL-06-000097

Configure Kernel Parameter for Accepting Secure Redirects for All Interfaces   [ref]rule

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
If this is not the system default value, 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.

Severity:  medium

Identifiers:  CCE-26854-0

References:  RHEL-06-000086, SV-50327r2_rule, SRG-OS-999999, 3.2.3, 3.1.20, CCI-001503, CCI-001551, AC-4, CM-7, SC-5

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable

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
#
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append '/etc/sysctl.conf' '^net.ipv4.conf.all.secure_redirects' "$sysctl_net_ipv4_conf_all_secure_redirects_value" 'CCE-26854-0'
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- 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: yes
  tags:
    - sysctl_net_ipv4_conf_all_secure_redirects
    - medium_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-26854-0
    - NIST-800-53-AC-4
    - NIST-800-53-CM-7
    - NIST-800-53-SC-5
    - NIST-800-171-3.1.20
    - DISA-STIG-RHEL-06-000086

Configure Kernel Parameter for Accepting IPv4 Source-Routed Packets for All Interfaces   [ref]rule

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
If this is not the system default value, 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.

Severity:  medium

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable

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
#
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append '/etc/sysctl.conf' '^net.ipv4.conf.all.accept_source_route' "$sysctl_net_ipv4_conf_all_accept_source_route_value" 'CCE-27037-1'
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- 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: yes
  tags:
    - sysctl_net_ipv4_conf_all_accept_source_route
    - medium_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-27037-1
    - NIST-800-53-AC-4
    - NIST-800-53-CM-7
    - NIST-800-53-SC-5
    - NIST-800-171-3.1.20
    - DISA-STIG-RHEL-06-000083

Configure Kernel Parameter to Use TCP Syncookies   [ref]rule

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
If this is not the system default value, 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.

Severity:  medium

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable

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
#
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append '/etc/sysctl.conf' '^net.ipv4.tcp_syncookies' "$sysctl_net_ipv4_tcp_syncookies_value" 'CCE-27053-8'
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- 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: yes
  tags:
    - sysctl_net_ipv4_tcp_syncookies
    - medium_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-27053-8
    - NIST-800-53-AC-4
    - NIST-800-53-SC-5(1)(2)
    - NIST-800-53-SC-5(2)
    - NIST-800-53-SC-5(3)
    - NIST-800-171-3.1.20
    - CJIS-5.10.1.1
    - DISA-STIG-RHEL-06-000095

Configure Kernel Parameter to Log Martian Packets   [ref]rule

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
If this is not the system default value, 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.

Severity:  unknown

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable

sysctl_net_ipv4_conf_all_log_martians_value="0"

#
# 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
#
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append '/etc/sysctl.conf' '^net.ipv4.conf.all.log_martians' "$sysctl_net_ipv4_conf_all_log_martians_value" 'CCE-27066-0'
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- 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 |-
        0
  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: yes
  tags:
    - sysctl_net_ipv4_conf_all_log_martians
    - unknown_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-27066-0
    - NIST-800-53-AC-3(10)
    - NIST-800-53-AC-17(7)
    - NIST-800-53-CM-7
    - NIST-800-53-SC-5(3)
    - NIST-800-171-3.1.20
    - DISA-STIG-RHEL-06-000088

Configure Kernel Parameter to Use Reverse Path Filtering for All Interfaces   [ref]rule

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
If this is not the system default value, 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.

Severity:  medium

Identifiers:  CCE-26979-5

References:  RHEL-06-000096, SV-50343r2_rule, SRG-OS-999999, 3.2.7, 3.1.20, CCI-001551, AC-4, SC-5, SC-7

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable

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
#
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append '/etc/sysctl.conf' '^net.ipv4.conf.all.rp_filter' "$sysctl_net_ipv4_conf_all_rp_filter_value" 'CCE-26979-5'
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- 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: yes
  tags:
    - sysctl_net_ipv4_conf_all_rp_filter
    - medium_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-26979-5
    - NIST-800-53-AC-4
    - NIST-800-53-SC-5
    - NIST-800-53-SC-7
    - NIST-800-171-3.1.20
    - DISA-STIG-RHEL-06-000096

Configure Kernel Parameter to Ignore ICMP Broadcast Echo Requests   [ref]rule

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
If this is not the system default value, 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.

Severity:  medium

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable

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
#
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append '/etc/sysctl.conf' '^net.ipv4.icmp_echo_ignore_broadcasts' "$sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value" 'CCE-26883-9'
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- 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: yes
  tags:
    - sysctl_net_ipv4_icmp_echo_ignore_broadcasts
    - medium_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-26883-9
    - NIST-800-53-AC-4
    - NIST-800-53-CM-7
    - NIST-800-53-SC-5
    - NIST-800-171-3.1.20
    - CJIS-5.10.1.1
    - DISA-STIG-RHEL-06-000092

Configure Kernel Parameter for Accepting Secure Redirects By Default   [ref]rule

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
If this is not the system default value, 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.

Severity:  medium

Identifiers:  CCE-26831-8

References:  RHEL-06-000090, SV-50333r2_rule, SRG-OS-999999, 3.2.3, 3.1.20, CCI-001551, AC-4, CM-7, SC-5, SC-7

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable

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
#
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append '/etc/sysctl.conf' '^net.ipv4.conf.default.secure_redirects' "$sysctl_net_ipv4_conf_default_secure_redirects_value" 'CCE-26831-8'
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- 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: yes
  tags:
    - sysctl_net_ipv4_conf_default_secure_redirects
    - medium_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-26831-8
    - NIST-800-53-AC-4
    - NIST-800-53-CM-7
    - NIST-800-53-SC-5
    - NIST-800-53-SC-7
    - NIST-800-171-3.1.20
    - DISA-STIG-RHEL-06-000090

Network Parameters for Hosts Only   [ref]group

If the system is not going to be used as a router, then setting certain kernel parameters ensure that the host will not perform routing of network traffic.

contains 3 rules

Disable Kernel Parameter for IP Forwarding   [ref]rule

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
If this is not the system default value, 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.

Severity:  medium

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable


#
# 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
#
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append '/etc/sysctl.conf' '^net.ipv4.ip_forward' "0" 'CCE-26866-4'
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: Ensure sysctl net.ipv4.ip_forward is set to 0
  sysctl:
    name: net.ipv4.ip_forward
    value: 0
    state: present
    reload: yes
  tags:
    - sysctl_net_ipv4_ip_forward
    - medium_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-26866-4
    - NIST-800-53-CM-7
    - NIST-800-53-SC-5
    - NIST-800-53-SC-32
    - NIST-800-171-3.1.20
    - DISA-STIG-RHEL-06-000082

Disable Kernel Parameter for Sending ICMP Redirects for All Interfaces   [ref]rule

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
If this is not the system default value, 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.

Severity:  medium

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable


#
# 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
#
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append '/etc/sysctl.conf' '^net.ipv4.conf.all.send_redirects' "0" 'CCE-27004-1'
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- 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: yes
  tags:
    - sysctl_net_ipv4_conf_all_send_redirects
    - medium_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-27004-1
    - NIST-800-53-AC-4
    - NIST-800-53-CM-7
    - NIST-800-53-SC-5(1)
    - NIST-800-171-3.1.20
    - CJIS-5.10.1.1
    - DISA-STIG-RHEL-06-000081

Disable Kernel Parameter for Sending ICMP Redirects by Default   [ref]rule

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
If this is not the system default value, 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.

Severity:  medium

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable


#
# 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
#
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append '/etc/sysctl.conf' '^net.ipv4.conf.default.send_redirects' "0" 'CCE-27001-7'
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- 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: yes
  tags:
    - sysctl_net_ipv4_conf_default_send_redirects
    - medium_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-27001-7
    - NIST-800-53-AC-4
    - NIST-800-53-CM-7
    - NIST-800-53-SC-5
    - NIST-800-53-SC-7
    - NIST-800-171-3.1.20
    - CJIS-5.10.1.1
    - DISA-STIG-RHEL-06-000080

Uncommon Network Protocols   [ref]group

The system includes support for several network protocols which are not commonly used. Although security vulnerabilities in kernel networking code are not frequently discovered, the consequences can be dramatic. Ensuring uncommon network protocols are disabled reduces the system's risk to attacks targeted at its implementation of those protocols.

Warning:  Although these protocols are not commonly used, avoid disruption in your network environment by ensuring they are not needed prior to disabling them.
contains 4 rules

Disable DCCP Support   [ref]rule

The Datagram Congestion Control Protocol (DCCP) is a relatively new transport layer protocol, designed to support streaming media and telephony. To configure the system to prevent the dccp kernel module from being loaded, add the following line to a file in the directory /etc/modprobe.d:

install dccp /bin/true

Rationale:

Disabling DCCP protects the system against exploitation of any flaws in its implementation.

Severity:  medium

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
if LC_ALL=C grep -q -m 1 "^install dccp" /etc/modprobe.d/dccp.conf ; then
	sed -i 's/^install dccp.*/install dccp /bin/true/g' /etc/modprobe.d/dccp.conf
else
	echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/dccp.conf
	echo "install dccp /bin/true" >> /etc/modprobe.d/dccp.conf
fi
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: Ensure kernel module 'dccp' is disabled
  lineinfile:
    create: yes
    dest: "/etc/modprobe.d/dccp.conf"
    regexp: 'dccp'
    line: "install dccp /bin/true"
  tags:
    - kernel_module_dccp_disabled
    - medium_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-26448-1
    - NIST-800-53-CM-7
    - NIST-800-171-3.4.6
    - CJIS-5.10.1
    - DISA-STIG-RHEL-06-000124
    - DISA-STIG-020101

Disable RDS Support   [ref]rule

The Reliable Datagram Sockets (RDS) protocol is a transport layer protocol designed to provide reliable high- bandwidth, low-latency communications between nodes in a cluster. To configure the system to prevent the rds kernel module from being loaded, add the following line to a file in the directory /etc/modprobe.d:

install rds /bin/true

Rationale:

Disabling RDS protects the system against exploitation of any flaws in its implementation.

Severity:  unknown

Identifiers:  CCE-26239-4

References:  CCI-000382, SRG-OS-000096, RHEL-06-000126, SV-50317r3_rule, CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
if LC_ALL=C grep -q -m 1 "^install rds" /etc/modprobe.d/rds.conf ; then
	sed -i 's/^install rds.*/install rds /bin/true/g' /etc/modprobe.d/rds.conf
else
	echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/rds.conf
	echo "install rds /bin/true" >> /etc/modprobe.d/rds.conf
fi
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: Ensure kernel module 'rds' is disabled
  lineinfile:
    create: yes
    dest: "/etc/modprobe.d/rds.conf"
    regexp: 'rds'
    line: "install rds /bin/true"
  tags:
    - kernel_module_rds_disabled
    - unknown_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-26239-4
    - NIST-800-53-CM-7
    - DISA-STIG-RHEL-06-000126

Disable SCTP Support   [ref]rule

The Stream Control Transmission Protocol (SCTP) is a transport layer protocol, designed to support the idea of message-oriented communication, with several streams of messages within one connection. To configure the system to prevent the sctp kernel module from being loaded, add the following line to a file in the directory /etc/modprobe.d:

install sctp /bin/true

Rationale:

Disabling SCTP protects the system against exploitation of any flaws in its implementation.

Severity:  medium

Identifiers:  CCE-26410-1

References:  RHEL-06-000125, SV-50316r5_rule, CCI-000382, SRG-OS-000096, 3.5.2, 5.10.1, 3.4.6, CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
if LC_ALL=C grep -q -m 1 "^install sctp" /etc/modprobe.d/sctp.conf ; then
	sed -i 's/^install sctp.*/install sctp /bin/true/g' /etc/modprobe.d/sctp.conf
else
	echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/sctp.conf
	echo "install sctp /bin/true" >> /etc/modprobe.d/sctp.conf
fi
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: Ensure kernel module 'sctp' is disabled
  lineinfile:
    create: yes
    dest: "/etc/modprobe.d/sctp.conf"
    regexp: 'sctp'
    line: "install sctp /bin/true"
  tags:
    - kernel_module_sctp_disabled
    - medium_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-26410-1
    - NIST-800-53-CM-7
    - NIST-800-171-3.4.6
    - CJIS-5.10.1
    - DISA-STIG-RHEL-06-000125

Disable TIPC Support   [ref]rule

The Transparent Inter-Process Communication (TIPC) protocol is designed to provide communications between nodes in a cluster. To configure the system to prevent the tipc kernel module from being loaded, add the following line to a file in the directory /etc/modprobe.d:

install tipc /bin/true

Rationale:

Disabling TIPC protects the system against exploitation of any flaws in its implementation.

Severity:  medium

Identifiers:  CCE-26696-5

References:  CCI-000382, SRG-OS-000096, RHEL-06-000127, SV-50318r5_rule, CM-7

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
if LC_ALL=C grep -q -m 1 "^install tipc" /etc/modprobe.d/tipc.conf ; then
	sed -i 's/^install tipc.*/install tipc /bin/true/g' /etc/modprobe.d/tipc.conf
else
	echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/tipc.conf
	echo "install tipc /bin/true" >> /etc/modprobe.d/tipc.conf
fi
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: Ensure kernel module 'tipc' is disabled
  lineinfile:
    create: yes
    dest: "/etc/modprobe.d/tipc.conf"
    regexp: 'tipc'
    line: "install tipc /bin/true"
  tags:
    - kernel_module_tipc_disabled
    - medium_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-26696-5
    - NIST-800-53-CM-7
    - DISA-STIG-RHEL-06-000127

Wireless Networking   [ref]group

Wireless networking, such as 802.11 (WiFi) and Bluetooth, can present a security risk to sensitive or classified systems and networks. Wireless networking hardware is much more likely to be included in laptop or portable systems than in desktops or servers.

Removal of hardware provides the greatest assurance that the wireless capability remains disabled. Acquisition policies often include provisions to prevent the purchase of equipment that will be used in sensitive spaces and includes wireless capabilities. If it is impractical to remove the wireless hardware, and policy permits the device to enter sensitive spaces as long as wireless is disabled, efforts should instead focus on disabling wireless capability via software.

contains 4 rules

Disable Wireless Through Software Configuration   [ref]group

If it is impossible to remove the wireless hardware from the device in question, disable as much of it as possible through software. The following methods can disable software support for wireless networking, but note that these methods do not prevent malicious software or careless users from re-activating the devices.

contains 4 rules

Disable Bluetooth Kernel Modules   [ref]rule

The kernel's module loading system can be configured to prevent loading of the Bluetooth module. Add the following to the appropriate /etc/modprobe.d configuration file to prevent the loading of the Bluetooth module:

install bluetooth /bin/true

Rationale:

If Bluetooth functionality must be disabled, preventing the kernel from loading the kernel module provides an additional safeguard against its activation.

Severity:  medium

Remediation Shell script:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
if LC_ALL=C grep -q -m 1 "^install bluetooth" /etc/modprobe.d/bluetooth.conf ; then
	sed -i 's/^install bluetooth.*/install bluetooth /bin/true/g' /etc/modprobe.d/bluetooth.conf
else
	echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/bluetooth.conf
	echo "install bluetooth /bin/true" >> /etc/modprobe.d/bluetooth.conf
fi
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: Ensure kernel module 'bluetooth' is disabled
  lineinfile:
    create: yes
    dest: "/etc/modprobe.d/bluetooth.conf"
    regexp: 'bluetooth'
    line: "install bluetooth /bin/true"
  tags:
    - kernel_module_bluetooth_disabled
    - medium_severity
    - disable_strategy
    - low_complexity
    - medium_disruption
    - CCE-26763-3
    - NIST-800-53-AC-17(8)
    - NIST-800-53-AC-18(a)
    - NIST-800-53-AC-18(d)
    - NIST-800-53-AC-18(3)
    - NIST-800-53-CM-7
    - NIST-800-171-3.1.16
    - CJIS-5.13.1.3
    - DISA-STIG-RHEL-06-000315

Disable WiFi or Bluetooth in BIOS   [ref]rule

Some machines that include built-in wireless support offer the ability to disable the device through the BIOS. This is hardware-specific; consult your hardware manual or explore the BIOS setup during boot.

Rationale:

Disabling wireless support in the BIOS prevents easy activation of the wireless interface, generally requiring administrators to reboot the system first.

Severity:  unknown

Identifiers:  CCE-26878-9

References:  CCI-000085, AC-17(8), AC-18(a), AC-18(d), AC-18(3), CM-7

Disable Bluetooth Service   [ref]rule

The bluetooth service can be disabled with the following command:

$ sudo chkconfig bluetooth off
$ sudo service bluetooth stop

Rationale:

Disabling the bluetooth service prevents the system from attempting connections to Bluetooth devices, which entails some security risk. Nevertheless, variation in this risk decision may be expected due to the utility of Bluetooth connectivity and its limited range.

Severity:  medium

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'bluetooth' disable
/sbin/chkconfig --level 0123456 'bluetooth' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service bluetooth
  service:
    name: bluetooth
    enabled: "no"
    state: "stopped"
  register: service_result
  failed_when: "service_result is failed and ('Could not find the requested service' not in service_result.msg)"
  tags:
    - service_bluetooth_disabled
    - medium_severity
    - disable_strategy
    - low_complexity
    - low_disruption
    - CCE-27081-9
    - NIST-800-53-AC-17(8)
    - NIST-800-53-AC-18(a)
    - NIST-800-53-AC-18(d)
    - NIST-800-53-AC-18(3)
    - NIST-800-53-CM-7
    - NIST-800-171-3.1.16
    - DISA-STIG-RHEL-06-000331

Deactivate Wireless Network Interfaces   [ref]rule

Deactivating wireless network interfaces should prevent normal usage of the wireless capability.

Configure the system to disable all wireless network interfaces with the following command:

$ sudo nmcli radio wifi off

Rationale:

The use of wireless networking can introduce many different attack vectors into the organization's network. Common attack vectors such as malicious association and ad hoc networks will allow an attacker to spoof a wireless access point (AP), allowing validated systems to connect to the malicious AP and enabling the attacker to monitor and record network traffic. These malicious APs can also serve to create a man-in-the-middle attack or be used to create a denial of service to valid network resources.

Severity:  medium

Ensure System is Not Acting as a Network Sniffer   [ref]rule

The system should not be acting as a network sniffer, which can capture all traffic on the network to which it is connected. Run the following to determine if any interface is running in promiscuous mode:

$ ip link | grep PROMISC

Rationale:

Network interfaces in promiscuous mode allow for the capture of all network traffic visible to the system. If unauthorized individuals can access these applications, it may allow them to collect information such as logon IDs, passwords, and key exchanges between systems.

If the system is being used to perform a network troubleshooting function, the use of these tools must be documented with the Information Systems Security Manager (ISSM) and restricted to only authorized personnel.

Severity:  medium

Identifiers:  CCE-27152-8

References:  CCI-000366, CM-7, CM-7(2).1(i), MA-3, SRG-OS-000480-GPOS-00227

Disable Zeroconf Networking   [ref]rule

Zeroconf networking allows the system to assign itself an IP address and engage in IP communication without a statically-assigned address or even a DHCP server. Automatic address assignment via Zeroconf (or DHCP) is not recommended. To disable Zeroconf automatic route assignment in the 169.254.0.0 subnet, add or correct the following line in /etc/sysconfig/network:

NOZEROCONF=yes

Rationale:

Zeroconf addresses are in the network 169.254.0.0. The networking scripts add entries to the system's routing table for these addresses. Zeroconf address assignment commonly occurs when the system is configured to use DHCP but fails to receive an address assignment from the DHCP server.

Severity:  unknown

Identifiers:  CCE-27151-0

References:  CM-7

Remediation Shell script:   (show)

echo "NOZEROCONF=yes" >> /etc/sysconfig/network

SELinux   [ref]group

SELinux is a feature of the Linux kernel which can be used to guard against misconfigured or compromised programs. SELinux enforces the idea that programs should be limited in what files they can access and what actions they can take.

The default SELinux policy, as configured on Red Hat Enterprise Linux 6, has been sufficiently developed and debugged that it should be usable on almost any Red Hat system with minimal configuration and a small amount of system administrator training. This policy prevents system services - including most of the common network-visible services such as mail servers, FTP servers, and DNS servers - from accessing files which those services have no valid reason to access. This action alone prevents a huge amount of possible damage from network attacks against services, from trojaned software, and so forth.

This guide recommends that SELinux be enabled using the default (targeted) policy on every Red Hat system, unless that system has unusual requirements which make a stronger policy appropriate.

contains 6 rules

Ensure SELinux Not Disabled in /etc/grub.conf   [ref]rule

SELinux can be disabled at boot time by an argument in /etc/grub.conf. 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.

Severity:  medium

Identifiers:  CCE-26956-3

References:  CCI-000022, CCI-000032, RHEL-06-000017, SV-65547r2_rule, AC-3, AC-3(3), AC-6, AU-9

Remediation Shell script:   (show)

sed -i --follow-symlinks "s/selinux=0//gI" /etc/grub.conf
sed -i --follow-symlinks "s/enforcing=0//gI" /etc/grub.conf

Configure SELinux Policy   [ref]rule

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.

Severity:  high

Remediation Shell script:   (show)


var_selinux_policy_name="targeted"
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append '/etc/sysconfig/selinux' '^SELINUXTYPE=' $var_selinux_policy_name 'CCE-26875-5' '%s=%s'
Remediation Ansible snippet:   (show)

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"
  lineinfile:
    path: /etc/sysconfig/selinux
    regexp: '^SELINUXTYPE='
    line: "SELINUXTYPE={{ var_selinux_policy_name }}"
    create: yes
  tags:
    - selinux_policytype
    - high_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-26875-5
    - NIST-800-53-AC-3
    - NIST-800-53-AC-3(3)
    - NIST-800-53-AC-3(4)
    - NIST-800-53-AC-4
    - NIST-800-53-AC-6
    - NIST-800-53-AU-9
    - NIST-800-53-SI-6(a)
    - NIST-800-171-3.1.2
    - NIST-800-171-3.7.2
    - DISA-STIG-RHEL-06-000023

Ensure No Daemons are Unconfined by SELinux   [ref]rule

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 initrc_t context.

To check for unconfined daemons, run the following command:

$ sudo ps -eZ | egrep "initrc" | egrep -vw "tr|ps|egrep|bash|awk" | tr ':' ' ' | awk '{ print $NF }'
It should produce no output in a well-configured system.

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.
Rationale:

Daemons which run with the initrc_t context may cause AVC denials, or allow privileges that the daemon does not require.

Severity:  medium

Ensure No Device Files are Unlabeled by SELinux   [ref]rule

Device files, which are used for communication with important system resources, should be labeled with proper SELinux types. If any device files do not carry the SELinux type device_t, report the bug so that policy can be corrected. Supply information about what the device is and what programs use it.

To check for unlabeled device files, run the following command:

$ sudo find /dev -context *:device_t:* \( -type c -o -type b \) -printf "%p %Z\n"
It should produce no output in a well-configured system.

Warning:  Automatic remediation of this control is not available. The remediation can be achieved by amending SELinux policy.
Rationale:

If a device file carries the SELinux type device_t, then SELinux cannot properly restrict access to the device file.

Severity:  medium

Ensure SELinux State is Enforcing   [ref]rule

The SELinux state should be set to enforcing at system boot time. In the file /etc/selinux/config, add or correct the following line to configure the system to boot into enforcing mode:

SELINUX=enforcing

Rationale:

Setting the SELinux state to enforcing ensures SELinux is able to confine potentially compromised processes to the security policy, which is designed to prevent them from causing damage to the system or further elevating their privileges.

Severity:  high

Remediation Shell script:   (show)


var_selinux_state="enforcing"
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state 'CCE-26969-6' '%s=%s'

fixfiles onboot
fixfiles -f relabel
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:restrict
- name: XCCDF Value var_selinux_state # promote to variable
  set_fact:
    var_selinux_state: !!str |-
        enforcing
  tags:
    - always

- name: "Ensure SELinux State is Enforcing"
  lineinfile:
    path: /etc/sysconfig/selinux
    regexp: '^SELINUX='
    line: "SELINUX={{ var_selinux_state }}"
    create: yes
  tags:
    - selinux_state
    - high_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-26969-6
    - NIST-800-53-AC-3
    - NIST-800-53-AC-3(3)
    - NIST-800-53-AC-3(4)
    - NIST-800-53-AC-4
    - NIST-800-53-AC-6
    - NIST-800-53-AU-9
    - NIST-800-53-SI-6(a)
    - NIST-800-171-3.1.2
    - NIST-800-171-3.7.2
    - DISA-STIG-RHEL-06-000020

Enable the SELinux Context Restoration Service (restorecond)   [ref]rule

The restorecond service utilizes inotify to look for the creation of new files listed in the /etc/selinux/restorecond.conf configuration file. When a file is created, restorecond ensures the file receives the proper SELinux security context. The restorecond service can be enabled with the following command:

$ sudo chkconfig --level 2345 restorecond on

Rationale:

The restorecond service helps ensure that the default SELinux file context is applied to files. This allows automatic correction of file contexts created by some programs.

Severity:  unknown

Identifiers:  CCE-26991-0

References:  AC-3, AC-3(3), AC-4, AC-6, AU-9

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable

/sbin/service 'restorecond' disable
/sbin/chkconfig --level 0123456 'restorecond' off
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:enable
- name: Enable service restorecond
  service:
    name: restorecond
    enabled: "yes"
    state: "started"
  tags:
    - service_restorecond_enabled
    - unknown_severity
    - enable_strategy
    - low_complexity
    - low_disruption
    - CCE-26991-0
    - NIST-800-53-AC-3
    - NIST-800-53-AC-3(3)
    - NIST-800-53-AC-4
    - NIST-800-53-AC-6
    - NIST-800-53-AU-9

Set Boot Loader Password   [ref]group

During the boot process, the boot loader is responsible for starting the execution of the kernel and passing options to it. The boot loader allows for the selection of different kernels - possibly on different partitions or media. The default Red Hat Enterprise Linux boot loader for x86 systems is called GRUB. Options it can pass to the kernel include single-user mode, which provides root access without any authentication, and the ability to disable SELinux. To prevent local users from modifying the boot parameters and endangering security, protect the boot loader configuration with a password and ensure its configuration file's permissions are set properly.

contains 1 rule

Set Boot Loader Password in grub.conf   [ref]rule

The grub boot loader should have password protection enabled to protect boot-time settings. To do so, select a password and then generate a hash from it by running the following command:

$ grub-crypt --sha-512
When prompted to enter a password, insert the following line into /etc/grub.conf immediately after the header comments. (Use the output from grub-crypt as the value of password-hash):
password --encrypted password-hash
NOTE: To meet FISMA Moderate, the bootloader password MUST differ from the root password.

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.

Severity:  medium

Identifiers:  CCE-26911-8

References:  CCI-000213, SRG-OS-000080, RHEL-06-000068, SV-50386r4_rule, IA-2(1), IA-5(e) AC-3

Account and Access Control   [ref]group

In traditional Unix security, if an attacker gains shell access to a certain login account, they can perform any action or access any file to which that account has access. Therefore, making it more difficult for unauthorized people to gain shell access to accounts, particularly to privileged accounts, is a necessary part of securing a system. This section introduces mechanisms for restricting access to accounts under Red Hat Enterprise Linux 6.

contains 29 rules

Protect Accounts by Configuring PAM   [ref]group

PAM, or Pluggable Authentication Modules, is a system which implements modular authentication for Linux programs. PAM provides a flexible and configurable architecture for authentication, and it should be configured to minimize exposure to unnecessary risk. This section contains guidance on how to accomplish that.

PAM is implemented as a set of shared objects which are loaded and invoked whenever an application wishes to authenticate a user. Typically, the application must be running as root in order to take advantage of PAM, because PAM's modules often need to be able to access sensitive stores of account information, such as /etc/shadow. Traditional privileged network listeners (e.g. sshd) or SUID programs (e.g. sudo) already meet this requirement. An SUID root application, userhelper, is provided so that programs which are not SUID or privileged themselves can still take advantage of PAM.

PAM looks in the directory /etc/pam.d for application-specific configuration information. For instance, if the program login attempts to authenticate a user, then PAM's libraries follow the instructions in the file /etc/pam.d/login to determine what actions should be taken.

One very important file in /etc/pam.d is /etc/pam.d/system-auth. This file, which is included by many other PAM configuration files, defines 'default' system authentication measures. Modifying this file is a good way to make far-reaching authentication changes, for instance when implementing a centralized authentication service.

Warning:  Be careful when making changes to PAM's configuration files. The syntax for these files is complex, and modifications can have unexpected consequences. The default configurations shipped with applications should be sufficient for most users.
Warning:  Running authconfig or system-config-authentication will re-write the PAM configuration files, destroying any manually made changes and replacing them with a series of system defaults. One reference to the configuration file syntax can be found at http://www.linux-pam.org/Linux-PAM-html/sag-configuration-file.html.
contains 13 rules

Set Password Hashing Algorithm   [ref]group

The system's default algorithm for storing password hashes in /etc/shadow is SHA-512. This can be configured in several locations.

contains 3 rules

Set Password Hashing Algorithm in /etc/login.defs   [ref]rule

In /etc/login.defs, add or correct the following line to ensure the system will use SHA-512 as the hashing algorithm:

ENCRYPT_METHOD SHA512

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 kept in plain text.

Using a stronger hashing algorithm makes password cracking attacks more difficult.

Severity:  medium

Remediation Shell script:   (show)

if grep --silent ^ENCRYPT_METHOD /etc/login.defs ; then
	sed -i 's/^ENCRYPT_METHOD.*/ENCRYPT_METHOD SHA512/g' /etc/login.defs
else
	echo "" >> /etc/login.defs
	echo "ENCRYPT_METHOD SHA512" >> /etc/login.defs
fi
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:restrict
- name: Set Password Hashing Algorithm in /etc/login.defs
  lineinfile:
      dest: /etc/login.defs
      regexp: ^#?ENCRYPT_METHOD
      line: ENCRYPT_METHOD SHA512
      state: present
  tags:
    - set_password_hashing_algorithm_logindefs
    - medium_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-27228-6
    - NIST-800-53-IA-5(b)
    - NIST-800-53-IA-5(c)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-7
    - NIST-800-171-3.13.11
    - PCI-DSS-Req-8.2.1
    - CJIS-5.6.2.2
    - DISA-STIG-RHEL-06-000063

Set Password Hashing Algorithm in /etc/libuser.conf   [ref]rule

In /etc/libuser.conf, add or correct the following line in its [defaults] section to ensure the system will use the SHA-512 algorithm for password hashing:

crypt_style = sha512

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.

Severity:  medium

Remediation Shell script:   (show)


LIBUSER_CONF="/etc/libuser.conf"
CRYPT_STYLE_REGEX='[[:space:]]*\[defaults](.*(\n)+)+?[[:space:]]*crypt_style[[:space:]]*'

# Try find crypt_style in [defaults] section. If it is here, then change algorithm to sha512.
# If it isn't here, then add it to [defaults] section.
if grep -qzosP $CRYPT_STYLE_REGEX $LIBUSER_CONF ; then
        sed -i "s/\(crypt_style[[:space:]]*=[[:space:]]*\).*/\1sha512/g" $LIBUSER_CONF
elif grep -qs "\[defaults]" $LIBUSER_CONF ; then
        sed -i "/[[:space:]]*\[defaults]/a crypt_style = sha512" $LIBUSER_CONF
else
        echo -e "[defaults]\ncrypt_style = sha512" >> $LIBUSER_CONF
fi
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:restrict
- name: Set Password Hashing Algorithm in /etc/libuser.conf
  lineinfile:
    dest: /etc/libuser.conf
    insertafter: '^\s*\[defaults]'
    regexp: ^#?crypt_style
    line: crypt_style = sha512
    state: present
  tags:
    - set_password_hashing_algorithm_libuserconf
    - medium_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-27229-4
    - NIST-800-53-IA-5(b)
    - NIST-800-53-IA-5(c)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-7
    - NIST-800-171-3.13.11
    - PCI-DSS-Req-8.2.1
    - CJIS-5.6.2.2
    - DISA-STIG-RHEL-06-000064

Set PAM's Password Hashing Algorithm   [ref]rule

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.

Severity:  medium

Remediation Shell script:   (show)


AUTH_FILES[0]="/etc/pam.d/system-auth"
AUTH_FILES[1]="/etc/pam.d/password-auth"

for pamFile in "${AUTH_FILES[@]}"
do
	if ! grep -q "^password.*sufficient.*pam_unix.so.*sha512" $pamFile; then
		sed -i --follow-symlinks "/^password.*sufficient.*pam_unix.so/ s/$/ sha512/" $pamFile
	fi
done

Set Lockouts for Failed Password Attempts   [ref]group

The pam_faillock PAM module provides the capability to lock out user accounts after a number of failed login attempts. Its documentation is available in /usr/share/doc/pam-VERSION/txts/README.pam_faillock.

Warning:  Locking out user accounts presents the risk of a denial-of-service attack. The lockout policy must weigh whether the risk of such a denial-of-service attack outweighs the benefits of thwarting password guessing attacks.
contains 4 rules

Set Lockout Time For Failed Password Attempts   [ref]rule

To configure the system to lock out accounts after a number of incorrect login attempts and require an administrator to unlock the account using pam_faillock.so, modify the content of both /etc/pam.d/system-auth and /etc/pam.d/password-auth as follows:

  • add the following line immediately before the pam_unix.so statement in the AUTH section:
    auth required pam_faillock.so preauth silent deny=3 unlock_time=604800 fail_interval=900
  • add the following line immediately after the pam_unix.so statement in the AUTH section:
    auth [default=die] pam_faillock.so authfail deny=3 unlock_time=604800 fail_interval=900
  • add the following line immediately before the pam_unix.so statement in the ACCOUNT section:
    account required pam_faillock.so

Rationale:

Locking out user accounts after a number of incorrect attempts prevents direct password guessing attacks. Ensuring that an administrator is involved in unlocking locked accounts draws appropriate attention to such situations.

Severity:  medium

Remediation Shell script:   (show)


var_accounts_passwords_pam_faillock_unlock_time="604800"
function include_set_faillock_option {
	:
}

function insert_preauth {
	local pam_file="$1"
	local option="$2"
	local value="$3"
	# is auth required pam_faillock.so preauth present?
	if grep -qE "^\s*auth\s+required\s+pam_faillock\.so\s+preauth.*$" "$pam_file" ; then
		# is the option set?
		if grep -qE "^\s*auth\s+required\s+pam_faillock\.so\s+preauth.*$option=([0-9]*).*$" "$pam_file" ; then
			# just change the value of option to a correct value
			sed -i --follow-symlinks "s/\(^auth.*required.*pam_faillock.so.*preauth.*silent.*\)\($option *= *\).*/\1\2$value/" "$pam_file"
		# the option is not set.
		else
			# append the option
			sed -i --follow-symlinks "/^auth.*required.*pam_faillock.so.*preauth.*silent.*/ s/$/ $option=$value/" "$pam_file"
		fi
	# auth required pam_faillock.so preauth is not present, insert the whole line
	else
		sed -i --follow-symlinks "/^auth.*sufficient.*pam_unix.so.*/i auth        required      pam_faillock.so preauth silent $option=$value" "$pam_file"
	fi
}

function insert_authfail {
	local pam_file="$1"
	local option="$2"
	local value="$3"
	# is auth default pam_faillock.so authfail present?
	if grep -qE "^\s*auth\s+(\[default=die\])\s+pam_faillock\.so\s+authfail.*$" "$pam_file" ; then
		# is the option set?
		if grep -qE "^\s*auth\s+(\[default=die\])\s+pam_faillock\.so\s+authfail.*$option=([0-9]*).*$" "$pam_file" ; then
			# just change the value of option to a correct value
			sed -i --follow-symlinks "s/\(^auth.*[default=die].*pam_faillock.so.*authfail.*\)\($option *= *\).*/\1\2$value/" "$pam_file"
		# the option is not set.
		else
			# append the option
			sed -i --follow-symlinks "/^auth.*[default=die].*pam_faillock.so.*authfail.*/ s/$/ $option=$value/" "$pam_file"
		fi
	# auth default pam_faillock.so authfail is not present, insert the whole line
	else
		sed -i --follow-symlinks "/^auth.*sufficient.*pam_unix.so.*/a auth        [default=die] pam_faillock.so authfail $option=$value" "$pam_file"
	fi
}

function insert_account {
	local pam_file="$1"
	if ! grep -qE "^\s*account\s+required\s+pam_faillock\.so.*$" "$pam_file" ; then
		sed -E -i --follow-symlinks "/^\s*account\s*required\s*pam_unix.so/i account     required      pam_faillock.so" "$pam_file"
	fi
}

function set_faillock_option {
	local pam_file="$1"
	local option="$2"
	local value="$3"
	insert_preauth "$pam_file" "$option" "$value"
	insert_authfail "$pam_file" "$option" "$value"
	insert_account "$pam_file"
}

include_set_faillock_option

AUTH_FILES[0]="/etc/pam.d/system-auth"
AUTH_FILES[1]="/etc/pam.d/password-auth"

for pam_file in "${AUTH_FILES[@]}"
do
	set_faillock_option "$pam_file" "unlock_time" "$var_accounts_passwords_pam_faillock_unlock_time"
done

Limit Password Reuse   [ref]rule

Do not allow users to reuse recent passwords. This can be accomplished by using the remember option for the pam_unix or pam_pwhistory PAM modules.

In the file /etc/pam.d/system-auth, append remember=24 to the line which refers to the pam_unix.so or pam_pwhistory.somodule, as shown below:

  • for the pam_unix.so case:
    password sufficient pam_unix.so ...existing_options... remember=24
  • for the pam_pwhistory.so case:
    password requisite pam_pwhistory.so ...existing_options... remember=24
The DoD STIG requirement is 5 passwords.

Rationale:

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

Severity:  medium

Remediation Shell script:   (show)


var_password_pam_unix_remember="24"

AUTH_FILES[0]="/etc/pam.d/system-auth"
AUTH_FILES[1]="/etc/pam.d/password-auth"

for pamFile in "${AUTH_FILES[@]}"
do
	if grep -q "remember=" $pamFile; then
		sed -i --follow-symlinks "s/\(^password.*sufficient.*pam_unix.so.*\)\(\(remember *= *\)[^ $]*\)/\1remember=$var_password_pam_unix_remember/" $pamFile
	else
		sed -i --follow-symlinks "/^password[[:space:]]\+sufficient[[:space:]]\+pam_unix.so/ s/$/ remember=$var_password_pam_unix_remember/" $pamFile
	fi
done
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Strategy:configure
- name: XCCDF Value var_password_pam_unix_remember # promote to variable
  set_fact:
    var_password_pam_unix_remember: !!str |-
        24
  tags:
    - always

- name: "Do not allow users to reuse recent passwords - system-auth (change)"
  replace:
    dest: /etc/pam.d/system-auth
    follow: yes
    regexp: '^(password\s+sufficient\s+pam_unix\.so\s.*remember\s*=\s*)(\S+)(.*)$'
    replace: '\g<1>{{ var_password_pam_unix_remember }}\g<3>'
  tags:
    - accounts_password_pam_unix_remember
    - medium_severity
    - configure_strategy
    - low_complexity
    - medium_disruption
    - CCE-26741-9
    - NIST-800-53-IA-5(f)
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-171-3.5.8
    - PCI-DSS-Req-8.2.5
    - CJIS-5.6.2.1.1
    - DISA-STIG-RHEL-06-000274

- name: "Do not allow users to reuse recent passwords - system-auth (add)"
  replace:
    dest: /etc/pam.d/system-auth
    follow: yes
    regexp: '^password\s+sufficient\s+pam_unix\.so\s(?!.*remember\s*=\s*).*$'
    replace: '\g<0> remember={{ var_password_pam_unix_remember }}'
  tags:
    - accounts_password_pam_unix_remember
    - medium_severity
    - configure_strategy
    - low_complexity
    - medium_disruption
    - CCE-26741-9
    - NIST-800-53-IA-5(f)
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-171-3.5.8
    - PCI-DSS-Req-8.2.5
    - CJIS-5.6.2.1.1
    - DISA-STIG-RHEL-06-000274

Set Interval For Counting Failed Password Attempts   [ref]rule

Utilizing pam_faillock.so, the fail_interval directive configures the system to lock out an account after a number of incorrect login attempts within a specified time period. Modify the content of both /etc/pam.d/system-auth and /etc/pam.d/password-auth as follows:

  • Add the following line immediately before the pam_unix.so statement in the AUTH section:
    auth required pam_faillock.so preauth silent deny=3 unlock_time=604800 fail_interval=900
  • Add the following line immediately after the pam_unix.so statement in the AUTH section:
    auth [default=die] pam_faillock.so authfail deny=3 unlock_time=604800 fail_interval=900
    
  • Add the following line immediately before the pam_unix.so statement in the ACCOUNT section:
    account required pam_faillock.so

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.

Severity:  medium

Remediation Shell script:   (show)

function include_set_faillock_option {
	:
}

function insert_preauth {
	local pam_file="$1"
	local option="$2"
	local value="$3"
	# is auth required pam_faillock.so preauth present?
	if grep -qE "^\s*auth\s+required\s+pam_faillock\.so\s+preauth.*$" "$pam_file" ; then
		# is the option set?
		if grep -qE "^\s*auth\s+required\s+pam_faillock\.so\s+preauth.*$option=([0-9]*).*$" "$pam_file" ; then
			# just change the value of option to a correct value
			sed -i --follow-symlinks "s/\(^auth.*required.*pam_faillock.so.*preauth.*silent.*\)\($option *= *\).*/\1\2$value/" "$pam_file"
		# the option is not set.
		else
			# append the option
			sed -i --follow-symlinks "/^auth.*required.*pam_faillock.so.*preauth.*silent.*/ s/$/ $option=$value/" "$pam_file"
		fi
	# auth required pam_faillock.so preauth is not present, insert the whole line
	else
		sed -i --follow-symlinks "/^auth.*sufficient.*pam_unix.so.*/i auth        required      pam_faillock.so preauth silent $option=$value" "$pam_file"
	fi
}

function insert_authfail {
	local pam_file="$1"
	local option="$2"
	local value="$3"
	# is auth default pam_faillock.so authfail present?
	if grep -qE "^\s*auth\s+(\[default=die\])\s+pam_faillock\.so\s+authfail.*$" "$pam_file" ; then
		# is the option set?
		if grep -qE "^\s*auth\s+(\[default=die\])\s+pam_faillock\.so\s+authfail.*$option=([0-9]*).*$" "$pam_file" ; then
			# just change the value of option to a correct value
			sed -i --follow-symlinks "s/\(^auth.*[default=die].*pam_faillock.so.*authfail.*\)\($option *= *\).*/\1\2$value/" "$pam_file"
		# the option is not set.
		else
			# append the option
			sed -i --follow-symlinks "/^auth.*[default=die].*pam_faillock.so.*authfail.*/ s/$/ $option=$value/" "$pam_file"
		fi
	# auth default pam_faillock.so authfail is not present, insert the whole line
	else
		sed -i --follow-symlinks "/^auth.*sufficient.*pam_unix.so.*/a auth        [default=die] pam_faillock.so authfail $option=$value" "$pam_file"
	fi
}

function insert_account {
	local pam_file="$1"
	if ! grep -qE "^\s*account\s+required\s+pam_faillock\.so.*$" "$pam_file" ; then
		sed -E -i --follow-symlinks "/^\s*account\s*required\s*pam_unix.so/i account     required      pam_faillock.so" "$pam_file"
	fi
}

function set_faillock_option {
	local pam_file="$1"
	local option="$2"
	local value="$3"
	insert_preauth "$pam_file" "$option" "$value"
	insert_authfail "$pam_file" "$option" "$value"
	insert_account "$pam_file"
}

include_set_faillock_option

var_accounts_passwords_pam_faillock_fail_interval="900"

AUTH_FILES[0]="/etc/pam.d/system-auth"
AUTH_FILES[1]="/etc/pam.d/password-auth"

for pam_file in "${AUTH_FILES[@]}"
do
	set_faillock_option "$pam_file" "fail_interval" "$var_accounts_passwords_pam_faillock_fail_interval"
done

Set Deny For Failed Password Attempts   [ref]rule

To configure the system to lock out accounts after a number of incorrect login attempts using pam_faillock.so, modify the content of both /etc/pam.d/system-auth and /etc/pam.d/password-auth as follows:

  • add the following line immediately before the pam_unix.so statement in the AUTH section:
    auth required pam_faillock.so preauth silent deny=3 unlock_time=604800 fail_interval=900
  • add the following line immediately after the pam_unix.so statement in the AUTH section:
    auth [default=die] pam_faillock.so authfail deny=3 unlock_time=604800 fail_interval=900
  • add the following line immediately before the pam_unix.so statement in the ACCOUNT section:
    account required pam_faillock.so

Rationale:

Locking out user accounts after a number of incorrect attempts prevents direct password guessing attacks.

Severity:  medium

Remediation Shell script:   (show)


var_accounts_passwords_pam_faillock_deny="3"
function include_set_faillock_option {
	:
}

function insert_preauth {
	local pam_file="$1"
	local option="$2"
	local value="$3"
	# is auth required pam_faillock.so preauth present?
	if grep -qE "^\s*auth\s+required\s+pam_faillock\.so\s+preauth.*$" "$pam_file" ; then
		# is the option set?
		if grep -qE "^\s*auth\s+required\s+pam_faillock\.so\s+preauth.*$option=([0-9]*).*$" "$pam_file" ; then
			# just change the value of option to a correct value
			sed -i --follow-symlinks "s/\(^auth.*required.*pam_faillock.so.*preauth.*silent.*\)\($option *= *\).*/\1\2$value/" "$pam_file"
		# the option is not set.
		else
			# append the option
			sed -i --follow-symlinks "/^auth.*required.*pam_faillock.so.*preauth.*silent.*/ s/$/ $option=$value/" "$pam_file"
		fi
	# auth required pam_faillock.so preauth is not present, insert the whole line
	else
		sed -i --follow-symlinks "/^auth.*sufficient.*pam_unix.so.*/i auth        required      pam_faillock.so preauth silent $option=$value" "$pam_file"
	fi
}

function insert_authfail {
	local pam_file="$1"
	local option="$2"
	local value="$3"
	# is auth default pam_faillock.so authfail present?
	if grep -qE "^\s*auth\s+(\[default=die\])\s+pam_faillock\.so\s+authfail.*$" "$pam_file" ; then
		# is the option set?
		if grep -qE "^\s*auth\s+(\[default=die\])\s+pam_faillock\.so\s+authfail.*$option=([0-9]*).*$" "$pam_file" ; then
			# just change the value of option to a correct value
			sed -i --follow-symlinks "s/\(^auth.*[default=die].*pam_faillock.so.*authfail.*\)\($option *= *\).*/\1\2$value/" "$pam_file"
		# the option is not set.
		else
			# append the option
			sed -i --follow-symlinks "/^auth.*[default=die].*pam_faillock.so.*authfail.*/ s/$/ $option=$value/" "$pam_file"
		fi
	# auth default pam_faillock.so authfail is not present, insert the whole line
	else
		sed -i --follow-symlinks "/^auth.*sufficient.*pam_unix.so.*/a auth        [default=die] pam_faillock.so authfail $option=$value" "$pam_file"
	fi
}

function insert_account {
	local pam_file="$1"
	if ! grep -qE "^\s*account\s+required\s+pam_faillock\.so.*$" "$pam_file" ; then
		sed -E -i --follow-symlinks "/^\s*account\s*required\s*pam_unix.so/i account     required      pam_faillock.so" "$pam_file"
	fi
}

function set_faillock_option {
	local pam_file="$1"
	local option="$2"
	local value="$3"
	insert_preauth "$pam_file" "$option" "$value"
	insert_authfail "$pam_file" "$option" "$value"
	insert_account "$pam_file"
}

include_set_faillock_option

AUTH_FILES[0]="/etc/pam.d/system-auth"
AUTH_FILES[1]="/etc/pam.d/password-auth"

for pam_file in "${AUTH_FILES[@]}"
do
	set_faillock_option "$pam_file" "deny" "$var_accounts_passwords_pam_faillock_deny"
done
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:restrict
- 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: XCCDF Value var_accounts_passwords_pam_faillock_unlock_time # promote to variable
  set_fact:
    var_accounts_passwords_pam_faillock_unlock_time: !!str |-
        604800
  tags:
    - always
- name: XCCDF Value var_accounts_passwords_pam_faillock_fail_interval # promote to variable
  set_fact:
    var_accounts_passwords_pam_faillock_fail_interval: !!str |-
        900
  tags:
    - always

- name: set auth pam_faillock before pam_unix.so
  pamd:
    name: system-auth
    type: auth
    control: sufficient
    module_path: pam_unix.so
    new_type: auth
    new_control: required
    new_module_path: pam_faillock.so
    module_arguments: 'preauth
        silent
        deny: {{ var_accounts_passwords_pam_faillock_deny }}
        unlock_time={{ var_accounts_passwords_pam_faillock_unlock_time }}
        fail_interval={{ var_accounts_passwords_pam_faillock_fail_interval }}'
    state: before
  tags:
    - accounts_passwords_pam_faillock_deny
    - medium_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-26844-1
    - NIST-800-53-AC-7(a)
    - NIST-800-53-AC-7(b)
    - NIST-800-171-3.1.8
    - PCI-DSS-Req-8.1.6
    - CJIS-5.5.3
    - DISA-STIG-RHEL-06-000061

- name: set auth pam_faillock after pam_unix.so
  pamd:
    name: system-auth
    type: auth
    control: sufficient
    module_path: pam_unix.so
    new_type: auth
    new_control: '[default=die]'
    new_module_path: pam_faillock.so
    module_arguments: 'preauth
        silent
        deny: {{ var_accounts_passwords_pam_faillock_deny }}
        unlock_time={{ var_accounts_passwords_pam_faillock_unlock_time }}
        fail_interval={{ var_accounts_passwords_pam_faillock_fail_interval }}'
    state: after
  tags:
    - accounts_passwords_pam_faillock_deny
    - medium_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-26844-1
    - NIST-800-53-AC-7(a)
    - NIST-800-53-AC-7(b)
    - NIST-800-171-3.1.8
    - PCI-DSS-Req-8.1.6
    - CJIS-5.5.3
    - DISA-STIG-RHEL-06-000061

- name: set account pam_faillock before pam_unix.so
  pamd:
    name: system-auth
    type: account
    control: required
    module_path: pam_unix.so
    new_type: account
    new_control: required
    new_module_path: pam_faillock.so
    state: before
  tags:
    - accounts_passwords_pam_faillock_deny
    - medium_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-26844-1
    - NIST-800-53-AC-7(a)
    - NIST-800-53-AC-7(b)
    - NIST-800-171-3.1.8
    - PCI-DSS-Req-8.1.6
    - CJIS-5.5.3
    - DISA-STIG-RHEL-06-000061

Set Password Quality Requirements   [ref]group

The default pam_cracklib PAM module provides strength checking for passwords. It performs a number of checks, such as making sure passwords are not similar to dictionary words, are of at least a certain length, are not the previous password reversed, and are not simply a change of case from the previous password. It can also require passwords to be in certain character classes.

The man page pam_cracklib(8) provides information on the capabilities and configuration of each.

contains 6 rules

Set Password Quality Requirements, if using pam_cracklib   [ref]group

The pam_cracklib PAM module can be configured to meet requirements for a variety of policies.

For example, to configure pam_cracklib to require at least one uppercase character, lowercase character, digit, and other (special) character, locate the following line in /etc/pam.d/system-auth:

password requisite pam_cracklib.so try_first_pass retry=3
and then alter it to read:
password required pam_cracklib.so try_first_pass retry=3 maxrepeat=3 minlen=14 dcredit=-1 ucredit=-1 ocredit=-1 lcredit=-1 difok=4
If no such line exists, add one as the first line of the password section in /etc/pam.d/system-auth. The arguments can be modified to ensure compliance with your organization's security policy. Discussion of each parameter follows.

Warning:  Note that the password quality requirements are not enforced for the root account for some reason.
contains 6 rules

Set Password Retry Prompts Permitted Per-Session   [ref]rule

To configure the number of retry prompts that are permitted per-session:

Edit the pam_cracklib.so statement in /etc/pam.d/system-auth to show 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.

Severity:  unknown

Identifiers:  CCE-27123-9

References:  CCI-001092, IA-5(c)

Set Password Strength Minimum Special Characters   [ref]rule

The pam_cracklib module's ocredit= parameter controls requirements for usage of special (or ``other'') characters in a password. When set to a negative number, any password will be required to contain that many special characters. When set to a positive number, pam_cracklib will grant +1 additional length credit for each special character. Add ocredit=-1 after pam_cracklib.so to require use of a special character in passwords.

Rationale:

Requiring a minimum number of special characters makes password guessing attacks more difficult by ensuring a larger search space.

Severity:  unknown

Identifiers:  CCE-26409-3

References:  CCI-001619, SRG-OS-000266, RHEL-06-000058, SV-50371r1_rule, IA-5(b), IA-5(c), IA-5(1)(a)

Set Password to Maximum of Three Consecutive Repeating Characters   [ref]rule

The pam_cracklib module's maxrepeat parameter controls requirements for consecutive repeating characters. When set to a positive number, it will reject passwords which contain more than that number of consecutive characters. Add maxrepeat=3 after pam_cracklib.so to prevent a run of (3 + 1) or more identical characters:

password required pam_cracklib.so maxrepeat=3

Rationale:

Passwords with excessive repeating characters may be more vulnerable to password-guessing attacks.

Severity:  unknown

Identifiers:  CCE-27227-8

References:  CCI-000366, SRG-OS-999999, RHEL-06-000299, SV-50494r2_rule, IA-5(c)

Set Password Strength Minimum Uppercase Characters   [ref]rule

The pam_cracklib module's ucredit= parameter controls requirements for usage of uppercase letters in a password. When set to a negative number, any password will be required to contain that many uppercase characters. When set to a positive number, pam_cracklib will grant +1 additional length credit for each uppercase character. Add ucredit=-1 after pam_cracklib.so to require use of an upper case character in passwords.

Rationale:

Requiring a minimum number of uppercase characters makes password guessing attacks more difficult by ensuring a larger search space.

Severity:  unknown

Set Password Strength Minimum Lowercase Characters   [ref]rule

The pam_cracklib module's lcredit= parameter controls requirements for usage of lowercase letters in a password. When set to a negative number, any password will be required to contain that many lowercase characters. When set to a positive number, pam_cracklib will grant +1 additional length credit for each lowercase character. Add lcredit=-1 after pam_cracklib.so to require use of a lowercase character in passwords.

Rationale:

Requiring a minimum number of lowercase characters makes password guessing attacks more difficult by ensuring a larger search space.

Severity:  unknown

Set Password Strength Minimum Different Characters   [ref]rule

The pam_cracklib module's difok parameter controls requirements for usage of different characters during a password change. Add difok= after pam_cracklib.so to require differing characters when changing passwords. The DoD requirement is 4.

Rationale:

Requiring a minimum number of different characters during password changes ensures that newly changed passwords should not resemble previously compromised ones. Note that passwords which are changed on compromised systems will still be compromised, however.

Severity:  unknown

Identifiers:  CCE-26615-5

References:  CCI-000195, SRG-OS-000072, RHEL-06-000060, SV-50373r2_rule, IA-5(b), IA-5(c), IA-5(1)(b)

Protect Physical Console Access   [ref]group

It is impossible to fully protect a system from an attacker with physical access, so securing the space in which the system is located should be considered a necessary step. However, there are some steps which, if taken, make it more difficult for an attacker to quickly or undetectably modify a system from its console.

contains 2 rules

Configure Screen Locking   [ref]group

When a user must temporarily leave an account logged-in, screen locking should be employed to prevent passersby from abusing the account. User education and training is particularly important for screen locking to be effective, and policies can be implemented to reinforce this.

Automatic screen locking is only meant as a safeguard for those cases where a user forgot to lock the screen.

contains 1 rule

Configure Console Screen Locking   [ref]group

A console screen locking mechanism is provided in the screen package, which is not installed by default.

contains 1 rule

Install the screen Package   [ref]rule

To enable console screen locking, install the screen package. The screen package can be installed with the following command:

$ sudo yum install screen
Instruct users to begin new terminal sessions with the following command:
$ screen
The console can now be locked with the following key combination:
ctrl+a x

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 des not logout because of the temporary nature of the absence. Rather than relying on the user to manually lock their operation system session prior to vacating the vicinity, operating systems need to be able to identify when a user's session has idled and take action to initiate the session lock.

The screen package allows for a session lock to be implemented and configured.

Severity:  medium

Remediation Shell script:   (show)

Complexity:low
Disruption:low
Strategy:enable
# Function to install packages on RHEL, Fedora, Debian, and possibly other systems.
#
# Example Call(s):
#
#     package_install aide
#
function package_install {

# Load function arguments into local variables
local package="$1"

# Check sanity of the input
if [ $# -ne "1" ]
then
  echo "Usage: package_install 'package_name'"
  echo "Aborting."
  exit 1
fi

if which dnf ; then
  if ! rpm -q --quiet "$package"; then
    dnf install -y "$package"
  fi
elif which yum ; then
  if ! rpm -q --quiet "$package"; then
    yum install -y "$package"
  fi
elif which apt-get ; then
  apt-get install -y "$package"
else
  echo "Failed to detect available packaging system, tried dnf, yum and apt-get!"
  echo "Aborting."
  exit 1
fi

}

package_install screen
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure screen is installed
  package:
    name: screen
    state: present
  tags:
    - package_screen_installed
    - medium_severity
    - enable_strategy
    - low_complexity
    - low_disruption
    - CCE-26940-7
    - NIST-800-53-AC-11(a)
    - NIST-800-171-3.1.10
    - DISA-STIG-RHEL-06-000071
Remediation Puppet snippet:   (show)

Complexity:low
Disruption:low
Strategy:enable
include install_screen

class install_screen {
  package { 'screen':
    ensure => 'installed',
  }
}
Remediation Anaconda snippet:   (show)

Complexity:low
Disruption:low
Strategy:enable

package --add=screen

Require Authentication for Single User Mode   [ref]rule

Single-user mode is intended as a system recovery method, providing a single user root access to the system by providing a boot option at startup. By default, no authentication is performed if single-user mode is selected.

To require entry of the root password even if the system is started in single-user mode, add or correct the following line in the file /etc/sysconfig/init:

SINGLE=/sbin/sulogin

Rationale:

This prevents attackers with physical access from trivially bypassing security on the machine and gaining root access. Such accesses are further prevented by configuring the bootloader password.

Severity:  medium

Remediation Shell script:   (show)


grep -q ^SINGLE /etc/sysconfig/init && \
  sed -i "s/SINGLE.*/SINGLE=\/sbin\/sulogin/g" /etc/sysconfig/init
if ! [ $? -eq 0 ]; then
    echo "SINGLE=/sbin/sulogin" >> /etc/sysconfig/init
fi

Secure Session Configuration Files for Login Accounts   [ref]group

When a user logs into a Unix account, the system configures the user's session by reading a number of files. Many of these files are located in the user's home directory, and may have weak permissions as a result of user error or misconfiguration. If an attacker can modify or even read certain types of account configuration information, they can often gain full access to the affected user's account. Therefore, it is important to test and correct configuration file permissions for interactive accounts, particularly those of privileged users such as root or system administrators.

contains 1 rule

Warning Banners for System Accesses   [ref]group

Each system should expose as little information about itself as possible.

System banners, which are typically displayed just before a login prompt, give out information about the service or the host's operating system. This might include the distribution name and the system kernel version, and the particular version of a network service. This information can assist intruders in gaining access to the system as it can reveal whether the system is running vulnerable software. Most network services can be configured to limit what information is displayed.

Many organizations implement security policies that require a system banner provide notice of the system's ownership, provide warning to unauthorized users, and remind authorized users of their consent to monitoring.

contains 1 rule

Modify the System Login Banner   [ref]rule

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.

Severity:  medium

Remediation Shell script:   (show)


login_banner_text="--[\s\n]+WARNING[\s\n]+--[\s\n]*This[\s\n]+system[\s\n]+is[\s\n]+for[\s\n]+the[\s\n]+use[\s\n]+of[\s\n]+authorized[\s\n]+users[\s\n]+only.[\s\n]+Individuals[\s\n]*using[\s\n]+this[\s\n]+computer[\s\n]+system[\s\n]+without[\s\n]+authority[\s\n]+or[\s\n]+in[\s\n]+excess[\s\n]+of[\s\n]+their[\s\n]*authority[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+having[\s\n]+all[\s\n]+their[\s\n]+activities[\s\n]+on[\s\n]+this[\s\n]+system[\s\n]*monitored[\s\n]+and[\s\n]+recorded[\s\n]+by[\s\n]+system[\s\n]+personnel.[\s\n]+Anyone[\s\n]+using[\s\n]+this[\s\n]*system[\s\n]+expressly[\s\n]+consents[\s\n]+to[\s\n]+such[\s\n]+monitoring[\s\n]+and[\s\n]+is[\s\n]+advised[\s\n]+that[\s\n]*if[\s\n]+such[\s\n]+monitoring[\s\n]+reveals[\s\n]+possible[\s\n]+evidence[\s\n]+of[\s\n]+criminal[\s\n]+activity[\s\n]*system[\s\n]+personal[\s\n]+may[\s\n]+provide[\s\n]+the[\s\n]+evidence[\s\n]+of[\s\n]+such[\s\n]+monitoring[\s\n]+to[\s\n]+law[\s\n]*enforcement[\s\n]+officials."

# There was a regular-expression matching various banners, needs to be expanded
expanded=$(echo "$login_banner_text" | sed 's/(\\\\\x27)\*/\\\x27/g;s/(\\\x27)\*//g;s/\^(\(.*\)|.*$/\1/g;s/\[\\s\\n\][+*]/ /g;s/\\//g;s/[^-]- /\n\n-/g;s/(n)\**//g')
formatted=$(echo "$expanded" | fold -sw 80)

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

printf "\n" >> /etc/issue

Protect Accounts by Restricting Password-Based Login   [ref]group

Conventionally, Unix shell accounts are accessed by providing a username and password to a login program, which tests these values for correctness using the /etc/passwd and /etc/shadow files. Password-based login is vulnerable to guessing of weak passwords, and to sniffing and man-in-the-middle attacks against passwords entered over a network or at an insecure console. Therefore, mechanisms for accessing accounts by entering usernames and passwords should be restricted to those which are operationally necessary.

contains 12 rules

Set Password Expiration Parameters   [ref]group

The file /etc/login.defs controls several password-related settings. Programs such as passwd, su, and login consult /etc/login.defs to determine behavior with regard to password aging, expiration warnings, and length. See the man page login.defs(5) for more information.

Users should be forced to change their passwords, in order to decrease the utility of compromised passwords. However, the need to change passwords often should be balanced against the risk that users will reuse or write down passwords if forced to change them too often. Forcing password changes every 90-360 days, depending on the environment, is recommended. Set the appropriate value as PASS_MAX_DAYS and apply it to existing accounts with the -M flag.

The PASS_MIN_DAYS (-m) setting prevents password changes for 7 days after the first change, to discourage password cycling. If you use this setting, train users to contact an administrator for an emergency password change in case a new password becomes compromised. The PASS_WARN_AGE (-W) setting gives users 7 days of warnings at login time that their passwords are about to expire.

For example, for each existing human user USER, expiration parameters could be adjusted to a 180 day maximum password age, 7 day minimum password age, and 7 day warning period with the following command:

$ sudo chage -M 180 -m 7 -W 7 USER

contains 4 rules

Restrict Root Logins   [ref]group

Direct root logins should be allowed only for emergency use. In normal situations, the administrator should access the system via a unique unprivileged account, and then use su or sudo to execute privileged commands. Discouraging administrators from accessing the root account directly ensures an audit trail in organizations with multiple administrators. Locking down the channels through which root can connect directly also reduces opportunities for password-guessing against the root account. The login program uses the file /etc/securetty to determine which interfaces should allow root logins. The virtual devices /dev/console and /dev/tty* represent the system consoles (accessible via the Ctrl-Alt-F1 through Ctrl-Alt-F6 keyboard sequences on a default installation). The default securetty file also contains /dev/vc/*. These are likely to be deprecated in most environments, but may be retained for compatibility. Root should also be prohibited from connecting via network protocols. Other sections of this document include guidance describing how to prevent root from logging in via SSH.

contains 3 rules

Verify Only Root Has UID 0   [ref]rule

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.

Severity:  high

Remediation Shell script:   (show)

awk -F: '$3 == 0 && $1 != "root" { print $1 }' /etc/passwd | xargs passwd -l

Restrict Serial Port Root Logins   [ref]rule

To restrict root logins on serial ports, ensure lines of this form do not appear in /etc/securetty:

ttyS0
ttyS1

Rationale:

Preventing direct root login to serial port interfaces helps ensure accountability for actions taken on the systems using the root account.

Severity:  unknown

Remediation Shell script:   (show)

sed -i '/ttyS/d' /etc/securetty
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:restrict
- name: "Restrict Serial Port Root Logins"
  lineinfile:
    dest: /etc/securetty
    regexp: 'ttyS[0-9]'
    state: absent
  tags:
    - restrict_serial_port_logins
    - unknown_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-27047-0
    - NIST-800-53-AC-6(2)
    - NIST-800-171-3.1.1
    - NIST-800-171-3.1.5
    - DISA-STIG-RHEL-06-000028
contains 2 rules

Verify Proper Storage and Existence of Password Hashes   [ref]group

By default, password hashes for local accounts are stored in the second field (colon-separated) in /etc/shadow. This file should be readable only by processes running with root credentials, preventing users from casually accessing others' password hashes and attempting to crack them. However, it remains possible to misconfigure the system and store password hashes in world-readable files such as /etc/passwd, or to even store passwords themselves in plaintext on the system. Using system-provided tools for password change/creation should allow administrators to avoid such misconfiguration.

contains 3 rules

Verify No netrc Files Exist   [ref]rule

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. DoD policy requires passwords be encrypted in storage and not used in access scripts.

Severity:  medium

Identifiers:  CCE-27225-2

References:  SRG-OS-000073, RHEL-06-000347, SV-50420r2_rule, CCI-000196, IA-5(h), AC-3

Prevent Log In to Accounts With Empty Password   [ref]rule

If an account is configured for password authentication but does not have an assigned password, it may be possible to log into the account without authentication. Remove any instances of the nullok option in /etc/pam.d/system-auth to prevent logins with empty passwords.

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.

Severity:  high

Remediation Shell script:   (show)

sed --follow-symlinks -i 's/\<nullok\>//g' /etc/pam.d/system-auth
sed --follow-symlinks -i 's/\<nullok\>//g' /etc/pam.d/password-auth
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:medium
Strategy:configure
- name: "Prevent Log In to Accounts With Empty Password - system-auth"
  replace:
    dest: /etc/pam.d/system-auth
    follow: yes
    regexp: 'nullok'
  tags:
    - no_empty_passwords
    - high_severity
    - configure_strategy
    - low_complexity
    - medium_disruption
    - CCE-27038-9
    - NIST-800-53-AC-6
    - NIST-800-53-IA-5(b)
    - NIST-800-53-IA-5(c)
    - NIST-800-53-IA-5(1)(a)
    - NIST-800-171-3.1.1
    - NIST-800-171-3.1.5
    - PCI-DSS-Req-8.2.3
    - CJIS-5.5.2
    - DISA-STIG-RHEL-06-000030

- name: "Prevent Log In to Accounts With Empty Password - password-auth"
  replace:
    dest: /etc/pam.d/password-auth
    follow: yes
    regexp: 'nullok'
  tags:
    - no_empty_passwords
    - high_severity
    - configure_strategy
    - low_complexity
    - medium_disruption
    - CCE-27038-9
    - NIST-800-53-AC-6
    - NIST-800-53-IA-5(b)
    - NIST-800-53-IA-5(c)
    - NIST-800-53-IA-5(1)(a)
    - NIST-800-171-3.1.1
    - NIST-800-171-3.1.5
    - PCI-DSS-Req-8.2.3
    - CJIS-5.5.2
    - DISA-STIG-RHEL-06-000030

Verify All Account Password Hashes are Shadowed   [ref]rule

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.

Severity:  medium

Identifiers:  CCE-26476-2

References:  RHEL-06-000031, SV-50300r1_rule, CCI-000201, SRG-OS-999999, 5.5.2, 3.5.10, IA-5(h), Req-8.2.1

System Accounting with auditd   [ref]group

The audit service provides substantial capabilities for recording system activities. By default, the service audits about SELinux AVC denials and certain types of security-relevant events such as system logins, account modifications, and authentication events performed by programs such as sudo. Under its default configuration, auditd has modest disk space requirements, and should not noticeably impact system performance.

NOTE: The Linux Audit daemon auditd can be configured to use the augenrules program to read audit rules files (*.rules) located in /etc/audit/rules.d location and compile them to create the resulting form of the /etc/audit/audit.rules configuration file during the daemon startup (default configuration). Alternatively, the auditd daemon can use the auditctl utility to read audit rules from the /etc/audit/audit.rules configuration file during daemon startup, and load them into the kernel. The expected behavior is configured via the appropriate ExecStartPost directive setting in the /usr/lib/systemd/system/auditd.service configuration file. To instruct the auditd daemon to use the augenrules program to read audit rules (default configuration), use the following setting:

ExecStartPost=-/sbin/augenrules --load
in the /usr/lib/systemd/system/auditd.service configuration file. In order to instruct the auditd daemon to use the auditctl utility to read audit rules, use the following setting:
ExecStartPost=-/sbin/auditctl -R /etc/audit/audit.rules
in the /usr/lib/systemd/system/auditd.service configuration file. Refer to [Service] section of the /usr/lib/systemd/system/auditd.service configuration file for further details.

Government networks often have substantial auditing requirements and auditd can be configured to meet these requirements. Examining some example audit records demonstrates how the Linux audit system satisfies common requirements. The following example from Fedora Documentation available at https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/SELinux_Users_and_Administrators_Guide/sect-Security-Enhanced_Linux-Troubleshooting-Fixing_Problems.html#sect-Security-Enhanced_Linux-Fixing_Problems-Raw_Audit_Messages shows the substantial amount of information captured in a two typical "raw" audit messages, followed by a breakdown of the most important fields. In this example the message is SELinux-related and reports an AVC denial (and the associated system call) that occurred when the Apache HTTP Server attempted to access the /var/www/html/file1 file (labeled with the samba_share_t type):
type=AVC msg=audit(1226874073.147:96): avc:  denied  { getattr } for pid=2465 comm="httpd"
path="/var/www/html/file1" dev=dm-0 ino=284133 scontext=unconfined_u:system_r:httpd_t:s0
tcontext=unconfined_u:object_r:samba_share_t:s0 tclass=file

type=SYSCALL msg=audit(1226874073.147:96): arch=40000003 syscall=196 success=no exit=-13
a0=b98df198 a1=bfec85dc a2=54dff4 a3=2008171 items=0 ppid=2463 pid=2465 auid=502 uid=48
gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=6 comm="httpd"
exe="/usr/sbin/httpd" subj=unconfined_u:system_r:httpd_t:s0 key=(null)
  • msg=audit(1226874073.147:96)
    • The number in parentheses is the unformatted time stamp (Epoch time) for the event, which can be converted to standard time by using the date command.
  • { getattr }
    • The item in braces indicates the permission that was denied. getattr indicates the source process was trying to read the target file's status information. This occurs before reading files. This action is denied due to the file being accessed having the wrong label. Commonly seen permissions include getattr, read, and write.
  • comm="httpd"
    • The executable that launched the process. The full path of the executable is found in the exe= section of the system call (SYSCALL) message, which in this case, is exe="/usr/sbin/httpd".
  • path="/var/www/html/file1"
    • The path to the object (target) the process attempted to access.
  • scontext="unconfined_u:system_r:httpd_t:s0"
    • The SELinux context of the process that attempted the denied action. In this case, it is the SELinux context of the Apache HTTP Server, which is running in the httpd_t domain.
  • tcontext="unconfined_u:object_r:samba_share_t:s0"
    • The SELinux context of the object (target) the process attempted to access. In this case, it is the SELinux context of file1. Note: the samba_share_t type is not accessible to processes running in the httpd_t domain.
  • From the system call (SYSCALL) message, two items are of interest:
    • success=no: indicates whether the denial (AVC) was enforced or not. success=no indicates the system call was not successful (SELinux denied access). success=yes indicates the system call was successful - this can be seen for permissive domains or unconfined domains, such as initrc_t and kernel_t.
    • exe="/usr/sbin/httpd": the full path to the executable that launched the process, which in this case, is exe="/usr/sbin/httpd".

contains 41 rules

Configure auditd Data Retention   [ref]group

The audit system writes data to /var/log/audit/audit.log. By default, auditd rotates 5 logs by size (6MB), retaining a maximum of 30MB of data in total, and refuses to write entries when the disk is too full. This minimizes the risk of audit data filling its partition and impacting other services. This also minimizes the risk of the audit daemon temporarily disabling the system if it cannot write audit log (which it can be configured to do). For a busy system or a system which is thoroughly auditing system activity, the default settings for data retention may be insufficient. The log file size needed will depend heavily on what types of events are being audited. First configure auditing to log all the events of interest. Then monitor the log size manually for awhile to determine what file size will allow you to keep the required data for the correct time period.

Using a dedicated partition for /var/log/audit prevents the auditd logs from disrupting system functionality if they fill, and, more importantly, prevents other activity in /var from filling the partition and stopping the audit trail. (The audit logs are size-limited and therefore unlikely to grow without bound unless configured to do so.) Some machines may have requirements that no actions occur which cannot be audited. If this is the case, then auditd can be configured to halt the machine if it runs out of space. Note: Since older logs are rotated, configuring auditd this way does not prevent older logs from being rotated away before they can be viewed. If your system is configured to halt when logging cannot be performed, make sure this can never happen under normal circumstances! Ensure that /var/log/audit is on its own partition, and that this partition is larger than the maximum amount of data auditd will retain normally.

contains 7 rules

Configure auditd Max Log File Size   [ref]rule

Determine the amount of audit data (in megabytes) which should be retained in each log file. Edit the file /etc/audit/auditd.conf. Add or modify the following line, substituting the correct value of 6 for STOREMB:

max_log_file = STOREMB
Set the value to 6 (MB) or higher for general-purpose systems. Larger values, of course, support retention of even more audit data.

Rationale:

The total storage for audit log files must be large enough to retain log information over the period required. This is a function of the maximum log file size and the number of logs retained.

Severity:  medium

Identifiers:  CCE-27550-3

References:  RHEL-06-000160, SV-50434r1_rule, SRG-OS-999999, 5.2.1.1, 5.4.1.1, AU-1(b), AU-11, IR-5, Req-10.7

Remediation Shell script:   (show)


var_auditd_max_log_file="6"

AUDITCONFIG=/etc/audit/auditd.conf
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append $AUDITCONFIG '^max_log_file' "$var_auditd_max_log_file" "CCE-27550-3"
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:restrict
- name: XCCDF Value var_auditd_max_log_file # promote to variable
  set_fact:
    var_auditd_max_log_file: !!str |-
        6
  tags:
    - always

- name: Configure auditd Max Log File Size
  lineinfile:
    dest: /etc/audit/auditd.conf
    regexp: '^\s*max_log_file\s*=\s*.*$'
    line: "max_log_file = {{ var_auditd_max_log_file }}"
    state: present
  #notify: reload auditd
  tags:
    - auditd_data_retention_max_log_file
    - medium_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-27550-3
    - NIST-800-53-AU-1(b)
    - NIST-800-53-AU-11
    - NIST-800-53-IR-5
    - PCI-DSS-Req-10.7
    - CJIS-5.4.1.1
    - DISA-STIG-RHEL-06-000160

Configure auditd mail_acct Action on Low Disk Space   [ref]rule

The auditd service can be configured to send email to a designated account in certain situations. Add or correct the following line in /etc/audit/auditd.conf to ensure that administrators are notified via email for those situations:

action_mail_acct = root

Rationale:

Email sent to the root account is typically aliased to the administrators of the system, who can take appropriate action.

Severity:  medium

Remediation Shell script:   (show)


var_auditd_action_mail_acct="root"

AUDITCONFIG=/etc/audit/auditd.conf
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append $AUDITCONFIG '^action_mail_acct' "$var_auditd_action_mail_acct" "CCE-27241-9"
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:restrict
- name: XCCDF Value var_auditd_action_mail_acct # promote to variable
  set_fact:
    var_auditd_action_mail_acct: !!str |-
        root
  tags:
    - always

- name: Configure auditd mail_acct Action on Low Disk Space
  lineinfile:
    dest: /etc/audit/auditd.conf
    line: "action_mail_acct = {{ var_auditd_action_mail_acct }}"
    state: present
  #notify: reload auditd
  tags:
    - auditd_data_retention_action_mail_acct
    - medium_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-27241-9
    - NIST-800-53-AU-1(b)
    - NIST-800-53-AU-4
    - NIST-800-53-AU-5(1)
    - NIST-800-53-AU-5(a)
    - NIST-800-53-IR-5
    - NIST-800-171-3.3.1
    - PCI-DSS-Req-10.7.a
    - CJIS-5.4.1.1
    - DISA-STIG-RHEL-06-000313

Configure auditd to use audispd's syslog plugin   [ref]rule

To configure the auditd service to use the syslog plug-in of the audispd audit event multiplexor, set the active line in /etc/audisp/plugins.d/syslog.conf to yes. Restart the auditd service:

$ sudo service auditd restart

Rationale:

The auditd service does not include the ability to send audit records to a centralized server for management directly. It does, however, include a plug-in for audit event multiplexor (audispd) to pass audit records to the local syslog server

Severity:  medium

Remediation Shell script:   (show)


var_syslog_active="yes"

AUDISP_SYSLOGCONFIG=/etc/audisp/plugins.d/syslog.conf
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append $AUDISP_SYSLOGCONFIG '^active' "$var_syslog_active" "CCE-26933-2"

Configure auditd admin_space_left Action on Low Disk Space   [ref]rule

The auditd service can be configured to take an action when disk space is running low but prior to running out of space completely. Edit the file /etc/audit/auditd.conf. Add or modify the following line, substituting ACTION appropriately:

admin_space_left_action = ACTION
Set this value to single to cause the system to switch to single user mode for corrective action. Acceptable values also include suspend and halt. For certain systems, the need for availability outweighs the need to log all actions, and a different setting should be determined. Details regarding all possible values for ACTION are described in the auditd.conf man page.

Rationale:

Administrators should be made aware of an inability to record audit records. If a separate partition or logical volume of adequate size is used, running low on space for audit records should never occur.

Severity:  medium

Remediation Shell script:   (show)


var_auditd_admin_space_left_action="halt"

AUDITCONFIG=/etc/audit/auditd.conf
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append $AUDITCONFIG '^admin_space_left_action' "$var_auditd_admin_space_left_action" "CCE-27239-3"
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:restrict
- name: XCCDF Value var_auditd_admin_space_left_action # promote to variable
  set_fact:
    var_auditd_admin_space_left_action: !!str |-
        halt
  tags:
    - always

- name: Configure auditd admin_space_left Action on Low Disk Space
  lineinfile:
    dest: /etc/audit/auditd.conf
    line: "admin_space_left_action = {{ var_auditd_admin_space_left_action }}"
    regexp: '^\s*admin_space_left_action\s*=\s*.*$'
    state: present
  #notify: reload auditd
  tags:
    - auditd_data_retention_admin_space_left_action
    - medium_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-27239-3
    - NIST-800-53-AU-1(b)
    - NIST-800-53-AU-4
    - NIST-800-53-AU-5(b)
    - NIST-800-53-IR-5
    - NIST-800-171-3.3.1
    - PCI-DSS-Req-10.7
    - CJIS-5.4.1.1
    - DISA-STIG-RHEL-06-000163

Configure auditd max_log_file_action Upon Reaching Maximum Log Size   [ref]rule

The default action to take when the logs reach their maximum size is to rotate the log files, discarding the oldest one. To configure the action taken by auditd, add or correct the line in /etc/audit/auditd.conf:

max_log_file_action = ACTION
Possible values for ACTION are described in the auditd.conf man page. These include:
  • syslog
  • suspend
  • rotate
  • keep_logs
Set the ACTION to rotate to ensure log rotation occurs. This is the default. The setting is case-insensitive.

Rationale:

Automatically rotating logs (by setting this to rotate) minimizes the chances of the system unexpectedly running out of disk space by being overwhelmed with log data. However, for systems that must never discard log data, or which use external processes to transfer it and reclaim space, keep_logs can be employed.

Severity:  medium

Remediation Shell script:   (show)


var_auditd_max_log_file_action="rotate"

AUDITCONFIG=/etc/audit/auditd.conf
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append $AUDITCONFIG '^max_log_file_action' "$var_auditd_max_log_file_action" "CCE-27237-7"
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:restrict
- name: XCCDF Value var_auditd_max_log_file_action # promote to variable
  set_fact:
    var_auditd_max_log_file_action: !!str |-
        rotate
  tags:
    - always

- name: Configure auditd max_log_file_action Upon Reaching Maximum Log Size
  lineinfile:
    dest: /etc/audit/auditd.conf
    line: "max_log_file_action = {{ var_auditd_max_log_file_action }}"
    regexp: '^\s*max_log_file_action\s*=\s*.*$'
    state: present
  #notify: reload auditd
  tags:
    - auditd_data_retention_max_log_file_action
    - medium_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-27237-7
    - NIST-800-53-AU-1(b)
    - NIST-800-53-AU-4
    - NIST-800-53-AU-11
    - NIST-800-53-IR-5
    - PCI-DSS-Req-10.7
    - CJIS-5.4.1.1
    - DISA-STIG-RHEL-06-000161

Configure auditd space_left Action on Low Disk Space   [ref]rule

The auditd service can be configured to take an action when disk space starts to run low. Edit the file /etc/audit/auditd.conf. Modify the following line, substituting ACTION appropriately:

space_left_action = ACTION
Possible values for ACTION are described in the auditd.conf man page. These include:
  • syslog
  • email
  • exec
  • suspend
  • single
  • halt
Set this to email (instead of the default, which is suspend) as it is more likely to get prompt attention. Acceptable values also include suspend, single, and halt.

Rationale:

Notifying administrators of an impending disk space problem may allow them to take corrective action prior to any disruption.

Severity:  medium

Remediation Shell script:   (show)


var_auditd_space_left_action="email"

#
# If space_left_action present in /etc/audit/auditd.conf, change value
# to var_auditd_space_left_action, else
# add "space_left_action = $var_auditd_space_left_action" to /etc/audit/auditd.conf
#

AUDITCONFIG=/etc/audit/auditd.conf
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append $AUDITCONFIG '^space_left_action' "$var_auditd_space_left_action" "CCE-27238-5"
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:restrict
- name: XCCDF Value var_auditd_space_left_action # promote to variable
  set_fact:
    var_auditd_space_left_action: !!str |-
        email
  tags:
    - always

- name: Configure auditd space_left Action on Low Disk Space
  lineinfile:
    dest: /etc/audit/auditd.conf
    line: "space_left_action = {{ var_auditd_space_left_action }}"
    regexp: '^\s*space_left_action\s*=\s*.*$'
    state: present
  #notify: reload auditd
  tags:
    - auditd_data_retention_space_left_action
    - medium_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-27238-5
    - NIST-800-53-AU-1(b)
    - NIST-800-53-AU-4
    - NIST-800-53-AU-5(1)
    - NIST-800-53-AU-5(b)
    - NIST-800-53-IR-5
    - NIST-800-171-3.3.1
    - PCI-DSS-Req-10.7
    - CJIS-5.4.1.1
    - DISA-STIG-RHEL-06-000005

Configure auditd Number of Logs Retained   [ref]rule

Determine how many log files auditd should retain when it rotates logs. Edit the file /etc/audit/auditd.conf. Add or modify the following line, substituting NUMLOGS with the correct value of 5:

num_logs = NUMLOGS
Set the value to 5 for general-purpose systems. Note that values less than 2 result in no log rotation.

Rationale:

The total storage for audit log files must be large enough to retain log information over the period required. This is a function of the maximum log file size and the number of logs retained.

Severity:  medium

Identifiers:  CCE-27522-2

References:  RHEL-06-000159, SV-50437r1_rule, SRG-OS-999999, 5.4.1.1, 3.3.1, AU-1(b), AU-11, IR-5, Req-10.7

Remediation Shell script:   (show)


var_auditd_num_logs="5"

AUDITCONFIG=/etc/audit/auditd.conf
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # 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 "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="CCE-${cce}"
  else
    cce="CCE"
  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' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$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 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}

replace_or_append $AUDITCONFIG '^num_logs' "$var_auditd_num_logs" "CCE-27522-2"
Remediation Ansible snippet:   (show)

Complexity:low
Disruption:low
Strategy:restrict
- name: XCCDF Value var_auditd_num_logs # promote to variable
  set_fact:
    var_auditd_num_logs: !!str |-
        5
  tags:
    - always

- name: Configure auditd Number of Logs Retained
  lineinfile:
    dest: /etc/audit/auditd.conf
    line: "num_logs = {{ var_auditd_num_logs }}"
    regexp: '^\s*num_logs\s*=\s*.*$'
    state: present
  #notify: reload auditd
  tags:
    - auditd_data_retention_num_logs
    - medium_severity
    - restrict_strategy
    - low_complexity
    - low_disruption
    - CCE-27522-2
    - NIST-800-53-AU-1(b)
    - NIST-800-53-AU-11
    - NIST-800-53-IR-5
    - NIST-800-171-3.3.1
    - PCI-DSS-Req-10.7
    - CJIS-5.4.1.1
    - DISA-STIG-RHEL-06-000159

Configure auditd Rules for Comprehensive Auditing   [ref]group

The auditd program can perform comprehensive monitoring of system activity. This section describes recommended configuration settings for comprehensive auditing, but a full description of the auditing system's capabilities is beyond the scope of this guide. The mailing list linux-audit@redhat.com exists to facilitate community discussion of the auditing system.

The audit subsystem supports extensive collection of events, including:

  • Tracing of arbitrary system calls (identified by name or number) on entry or exit.
  • Filtering by PID, UID, call success, system call argument (with some limitations), etc.
  • Monitoring of specific files for modifications to the file's contents or metadata.

Auditing rules at startup are controlled by the file /etc/audit/audit.rules. Add rules to it to meet the auditing requirements for your organization. Each line in /etc/audit/audit.rules represents a series of arguments that can be passed to auditctl and can be individually tested during runtime. See documentation in /usr/share/doc/audit-VERSION and in the related man pages for more details.

If copying any example audit rulesets from /usr/share/doc/audit-VERSION, be sure to comment out the lines containing arch= which are not appropriate for your system's architecture. Then review and understand the following rules, ensuring rules are activated as needed for the appropriate architecture.

After reviewing all the rules, reading the following sections, and editing as needed, the new rules can be activated as follows:
$ sudo service auditd restart

contains 32 rules

Record Information on Kernel Modules Loading and Unloading   [ref]group

To capture kernel module loading and unloading events, use following lines, setting ARCH to either b32 for 32-bit system, or having two lines for both b32 and b64 in case your system is 64-bit:

-w /usr/sbin/insmod -p x -k modules
-w /usr/sbin/rmmod -p x -k modules
-w /usr/sbin/modprobe -p x -k modules
-a always,exit -F arch=ARCH -S init_module,delete_module -F key=modules
Place to add the lines depends on a way auditd daemon is configured. If it is configured to use the augenrules program (the default), add the lines to a file with suffix .rules in the directory /etc/audit/rules.d. If the auditd daemon is configured to use the auditctl utility, add the lines to file /etc/audit/audit.rules.

contains 1 rule

Ensure auditd Collects Information on Kernel Module Loading and Unloading   [ref]rule

To capture kernel module loading and unloading events, use following lines, setting ARCH to either b32 for 32-bit system, or having two lines for both b32 and b64 in case your system is 64-bit:

-w /usr/sbin/insmod -p x -k modules
-w /usr/sbin/rmmod -p x -k modules
-w /usr/sbin/modprobe -p x -k modules

-a always,exit -F arch=ARCH -S init_module,delete_module -F key=modules

The place to add the lines depends on a way auditd daemon is configured. If it is configured to use the augenrules program (the default), add the lines to a file with suffix .rules in the directory /etc/audit/rules.d. If the auditd daemon is configured to use the auditctl utility, add the lines to file /etc/audit/audit.rules.

Warning:  This rule checks for multiple syscalls related to kernel module loading and unloading; it was written with DISA STIG in mind. Other policies should use a separate rule for each syscall that needs to be checked. For example:
  • audit_rules_kernel_module_loading_insmod
  • audit_rules_kernel_module_loading_rmmod
  • audit_rules_kernel_module_loading_modprobe
Rationale:

The addition/removal of kernel modules can be used to alter the behavior of the kernel and potentially introduce malicious code into kernel space. It is important to have an audit trail of modules that have been introduced into the kernel.

Severity:  medium

contains 1 rule