contains 71 rules |
System Settings
[ref]groupContains rules that check correct system settings. |
contains 50 rules |
Installing and Maintaining Software
[ref]groupThe following sections contain information on
security-relevant choices during the initial operating system
installation process and the setup of software
updates. |
contains 7 rules |
Disk Partitioning
[ref]groupTo 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. |
contains 6 rules |
Ensure /home Located On Separate Partition
[ref]ruleIf user home directories will be stored locally, create a separate partition
for /home at installation time (or migrate it later using LVM). If
/home will be mounted from another system such as an NFS server, then
creating a separate partition is not necessary at installation time, and the
mountpoint can instead be configured later. Rationale:Ensuring that /home is mounted on its own partition enables the
setting of more restrictive mount options, and also helps ensure that
users cannot trivially fill partitions used for log or audit data storage. References:
R28, 1.1.12, 12, 15, 8, APO13.01, DSS05.02, CCI-000366, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 7.1, SR 7.6, A.13.1.1, A.13.2.1, A.14.1.3, CM-6(a), SC-5(2), PR.PT-4, SRG-OS-000480-GPOS-00227 |
Ensure /tmp Located On Separate Partition
[ref]ruleThe /tmp directory is a world-writable directory used
for temporary file storage. Ensure it has its own partition or
logical volume at installation time, or migrate it using LVM. Rationale:The /tmp partition is used as temporary storage by many programs.
Placing /tmp in its own partition enables the setting of more
restrictive mount options, which can help protect programs which use it. References:
1.1.2, 12, 15, 8, APO13.01, DSS05.02, CCI-000366, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 7.1, SR 7.6, A.13.1.1, A.13.2.1, A.14.1.3, CM-6(a), SC-5(2), PR.PT-4, SRG-OS-000480-GPOS-00227 |
Ensure /var Located On Separate Partition
[ref]ruleThe /var directory is used by daemons and other system
services to store frequently-changing data. Ensure that /var has its own partition
or logical volume at installation time, or migrate it using LVM. Rationale:Ensuring that /var is mounted on its own partition enables the
setting of more restrictive mount options. This helps protect
system services such as daemons or other programs which use it.
It is not uncommon for the /var directory to contain
world-writable directories installed by other software packages. References:
R28, 1.1.5, 12, 15, 8, APO13.01, DSS05.02, CCI-000366, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 7.1, SR 7.6, A.13.1.1, A.13.2.1, A.14.1.3, CM-6(a), SC-5(2), PR.PT-4, SRG-OS-000480-GPOS-00227 |
Ensure /var/log Located On Separate Partition
[ref]ruleSystem logs are stored in the /var/log directory.
Ensure that /var/log 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/ . References:
R28, 1.1.10, 1, 12, 14, 15, 16, 3, 5, 6, 8, APO11.04, APO13.01, BAI03.05, DSS05.02, DSS05.04, DSS05.07, MEA02.01, CCI-000366, 4.3.3.3.9, 4.3.3.5.8, 4.3.4.4.7, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 2.10, SR 2.11, SR 2.12, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 7.1, SR 7.6, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.13.1.1, A.13.2.1, A.14.1.3, CIP-007-3 R6.5, CM-6(a), AU-4, SC-5(2), PR.PT-1, PR.PT-4, SRG-OS-000480-GPOS-00227 |
Ensure /var/log/audit Located On Separate Partition
[ref]ruleAudit logs are stored in the /var/log/audit directory.
Ensure that /var/log/audit has its own partition or logical
volume at installation time, or migrate it 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. References:
R71, 1.1.11, 1, 12, 13, 14, 15, 16, 2, 3, 5, 6, 8, APO11.04, APO13.01, BAI03.05, BAI04.04, DSS05.02, DSS05.04, DSS05.07, MEA02.01, CCI-000366, CCI-001849, 164.312(a)(2)(ii), 4.3.3.3.9, 4.3.3.5.8, 4.3.4.4.7, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 2.10, SR 2.11, SR 2.12, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 7.1, SR 7.2, SR 7.6, A.12.1.3, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.13.1.1, A.13.2.1, A.14.1.3, A.17.2.1, CIP-007-3 R6.5, CM-6(a), AU-4, SC-5(2), PR.DS-4, PR.PT-1, PR.PT-4, FMT_SMF_EXT.1, SRG-OS-000341-GPOS-00132, SRG-OS-000480-GPOS-00227, SRG-APP-000357-CTR-000800 |
Ensure /var/tmp Located On Separate Partition
[ref]ruleThe /var/tmp directory is a world-writable directory used
for temporary file storage. Ensure it has its own partition or
logical volume at installation time, or migrate it using LVM. Rationale:The /var/tmp partition is used as temporary storage by many programs.
Placing /var/tmp in its own partition enables the setting of more
restrictive mount options, which can help protect programs which use it. |
Updating Software
[ref]groupThe apt_get command line tool is used to install and
update software packages. The system also provides a graphical
software update tool in the System menu, in the Administration submenu,
called Software Update.
Ubuntu 18.04 systems contain an installed software catalog called
the RPM database, which records metadata of installed packages. Consistently using
apt_get or the graphical Software Update for all software installation
allows for insight into the current inventory of installed software on the system.
|
contains 1 rule |
Ensure Software Patches Installed
[ref]rule
If the system has an apt repository available, run the following command to install updates:
$ apt update && apt full-upgrade
NOTE: U.S. Defense systems are required to be patched within 30 days or sooner as local policy
dictates.Warning:
Ubuntu 18.04 does not have a corresponding OVAL CVE Feed. Therefore, this will result in a "not checked" result during a scan. Rationale:Installing software updates is a fundamental mitigation against
the exploitation of publicly-known vulnerabilities. If the most
recent security patches and updates are not installed, unauthorized
users may take advantage of weaknesses in the unpatched software. The
lack of prompt attention to patching could result in a system compromise. References:
R61, 18, 20, 4, 5.10.4.1, APO12.01, APO12.02, APO12.03, APO12.04, BAI03.10, DSS05.01, DSS05.02, CCI-000366, 4.2.3, 4.2.3.12, 4.2.3.7, 4.2.3.9, A.12.6.1, A.14.2.3, A.16.1.3, A.18.2.2, A.18.2.3, SI-2(5), SI-2(c), CM-6(a), ID.RA-1, PR.IP-12, FMT_MOF_EXT.1, Req-6.2, 6.3.3, 6.3, SRG-OS-000480-GPOS-00227 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | high |
---|
Reboot: | true |
---|
Strategy: | patch |
---|
- name: Security patches are up to date
package:
name: '*'
state: latest
tags:
- CJIS-5.10.4.1
- NIST-800-53-CM-6(a)
- NIST-800-53-SI-2(5)
- NIST-800-53-SI-2(c)
- PCI-DSS-Req-6.2
- PCI-DSSv4-6.3
- PCI-DSSv4-6.3.3
- high_disruption
- low_complexity
- medium_severity
- patch_strategy
- reboot_required
- security_patches_up_to_date
- skip_ansible_lint
|
Network Configuration and Firewalls
[ref]groupMost 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 2 rules |
Uncommon Network Protocols
[ref]groupThe 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 2 rules |
Disable RDS Support
[ref]ruleThe 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 the file /etc/modprobe.d/rds.conf :
install rds /bin/false Rationale:Disabling RDS protects
the system against exploitation of any flaws in its implementation. References:
11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | medium |
---|
Reboot: | true |
---|
Strategy: | disable |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_rds_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
- name: Ensure kernel module 'rds' is disabled
lineinfile:
create: true
dest: /etc/modprobe.d/rds.conf
regexp: install\s+rds
line: install rds /bin/false
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_rds_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
- name: Ensure kernel module 'rds' is blacklisted
lineinfile:
create: true
dest: /etc/modprobe.d/rds.conf
regexp: ^blacklist rds$
line: blacklist rds
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_rds_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | medium |
---|
Reboot: | true |
---|
Strategy: | disable |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed; then
if LC_ALL=C grep -q -m 1 "^install rds" /etc/modprobe.d/rds.conf ; then
sed -i 's#^install rds.*#install rds /bin/false#g' /etc/modprobe.d/rds.conf
else
echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/rds.conf
echo "install rds /bin/false" >> /etc/modprobe.d/rds.conf
fi
if ! LC_ALL=C grep -q -m 1 "^blacklist rds$" /etc/modprobe.d/rds.conf ; then
echo "blacklist rds" >> /etc/modprobe.d/rds.conf
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Disable TIPC Support
[ref]ruleThe 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 the file /etc/modprobe.d/tipc.conf :
install tipc /bin/false Warning:
This configuration baseline was created to deploy the base operating system for general purpose
workloads. When the operating system is configured for certain purposes, such as
a node in High Performance Computing cluster, it is expected that
the tipc kernel module will be loaded. Rationale:Disabling TIPC protects
the system against exploitation of any flaws in its implementation. References:
11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, CCI-000381, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3, FMT_SMF_EXT.1, SRG-OS-000095-GPOS-00049 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | medium |
---|
Reboot: | true |
---|
Strategy: | disable |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_tipc_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
- name: Ensure kernel module 'tipc' is disabled
lineinfile:
create: true
dest: /etc/modprobe.d/tipc.conf
regexp: install\s+tipc
line: install tipc /bin/false
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_tipc_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
- name: Ensure kernel module 'tipc' is blacklisted
lineinfile:
create: true
dest: /etc/modprobe.d/tipc.conf
regexp: ^blacklist tipc$
line: blacklist tipc
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_tipc_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | medium |
---|
Reboot: | true |
---|
Strategy: | disable |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed; then
if LC_ALL=C grep -q -m 1 "^install tipc" /etc/modprobe.d/tipc.conf ; then
sed -i 's#^install tipc.*#install tipc /bin/false#g' /etc/modprobe.d/tipc.conf
else
echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/tipc.conf
echo "install tipc /bin/false" >> /etc/modprobe.d/tipc.conf
fi
if ! LC_ALL=C grep -q -m 1 "^blacklist tipc$" /etc/modprobe.d/tipc.conf ; then
echo "blacklist tipc" >> /etc/modprobe.d/tipc.conf
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
File Permissions and Masks
[ref]groupTraditional Unix security relies heavily on file and
directory permissions to prevent unauthorized users from reading or
modifying files to which they should not have access.
Several of the commands in this section search filesystems
for files or directories with certain characteristics, and are
intended to be run on every local partition on a given system.
When the variable PART appears in one of the commands below,
it means that the command is intended to be run repeatedly, with the
name of each local partition substituted for PART in turn.
The following command prints a list of all xfs partitions on the local
system, which is the default filesystem for Ubuntu 18.04
installations:
$ mount -t xfs | awk '{print $3}'
For any systems that use a different
local filesystem type, modify this command as appropriate. |
contains 41 rules |
Verify Permissions on Important Files and
Directories
[ref]groupPermissions for many files on a system must be set
restrictively to ensure sensitive information is properly protected.
This section discusses important
permission restrictions which can be verified
to ensure that no harmful discrepancies have
arisen. |
contains 26 rules |
Verify Permissions on Files with Local Account Information and Credentials
[ref]groupThe default restrictive permissions for files which act as
important security databases such as passwd , shadow ,
group , and gshadow files must be maintained. Many utilities
need read access to the passwd file in order to function properly, but
read access to the shadow file allows malicious attacks against system
passwords, and should never be enabled. |
contains 24 rules |
Verify Group Who Owns Backup group File
[ref]rule To properly set the group owner of /etc/group- , run the command: $ sudo chgrp root /etc/group- Rationale:The /etc/group- file is a backup file of /etc/group , and as such,
it contains information regarding groups that are configured on the system.
Protection of this file is important for system security. Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/group-
stat:
path: /etc/group-
register: file_exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_groupowner_backup_etc_group
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure group owner 0 on /etc/group-
file:
path: /etc/group-
group: '0'
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_groupowner_backup_etc_group
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chgrp 0 /etc/group-
|
Verify Group Who Owns Backup gshadow File
[ref]rule To properly set the group owner of /etc/gshadow- , run the command: $ sudo chgrp shadow /etc/gshadow- Rationale:The /etc/gshadow- file is a backup of /etc/gshadow , and as such,
it contains group password hashes. Protection of this file is critical for system security. Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/gshadow-
stat:
path: /etc/gshadow-
register: file_exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7
- configure_strategy
- file_groupowner_backup_etc_gshadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure group owner 42 on /etc/gshadow-
file:
path: /etc/gshadow-
group: '42'
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7
- configure_strategy
- file_groupowner_backup_etc_gshadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chgrp 42 /etc/gshadow-
|
Verify Group Who Owns Backup passwd File
[ref]rule To properly set the group owner of /etc/passwd- , run the command: $ sudo chgrp root /etc/passwd- Rationale:The /etc/passwd- file is a backup file of /etc/passwd , and as such,
it contains information about the users that are configured on the system.
Protection of this file is critical for system security. Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/passwd-
stat:
path: /etc/passwd-
register: file_exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_groupowner_backup_etc_passwd
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure group owner 0 on /etc/passwd-
file:
path: /etc/passwd-
group: '0'
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_groupowner_backup_etc_passwd
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chgrp 0 /etc/passwd-
|
Verify User Who Owns Backup shadow File
[ref]rule To properly set the group owner of /etc/shadow- , run the command: $ sudo chgrp shadow /etc/shadow- Rationale:The /etc/shadow- file is a backup file of /etc/shadow , and as such,
it contains the list of local system accounts and password hashes.
Protection of this file is critical for system security. Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/shadow-
stat:
path: /etc/shadow-
register: file_exists
tags:
- PCI-DSS-Req-8.7
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_groupowner_backup_etc_shadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure group owner 42 on /etc/shadow-
file:
path: /etc/shadow-
group: '42'
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- PCI-DSS-Req-8.7
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_groupowner_backup_etc_shadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chgrp 42 /etc/shadow-
|
Verify Group Who Owns group File
[ref]rule To properly set the group owner of /etc/group , run the command: $ sudo chgrp root /etc/group Rationale:The /etc/group file contains information regarding groups that are configured
on the system. Protection of this file is important for system security. References:
R50, 12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-000366, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-8.7.c, 2.2.6, 2.2, SRG-OS-000480-GPOS-00227 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/group
stat:
path: /etc/group
register: file_exists
tags:
- CJIS-5.5.2.2
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_groupowner_etc_group
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure group owner 0 on /etc/group
file:
path: /etc/group
group: '0'
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- CJIS-5.5.2.2
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_groupowner_etc_group
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chgrp 0 /etc/group
|
Verify Group Who Owns gshadow File
[ref]rule To properly set the group owner of /etc/gshadow , run the command: $ sudo chgrp shadow /etc/gshadow Rationale:The /etc/gshadow file contains group password hashes. Protection of this file
is critical for system security. References:
R50, 12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-000366, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/gshadow
stat:
path: /etc/gshadow
register: file_exists
tags:
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- configure_strategy
- file_groupowner_etc_gshadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure group owner 42 on /etc/gshadow
file:
path: /etc/gshadow
group: '42'
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- configure_strategy
- file_groupowner_etc_gshadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chgrp 42 /etc/gshadow
|
Verify Group Who Owns passwd File
[ref]rule To properly set the group owner of /etc/passwd , run the command: $ sudo chgrp root /etc/passwd Rationale:The /etc/passwd file contains information about the users that are configured on
the system. Protection of this file is critical for system security. References:
R50, 12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-000366, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-8.7.c, 2.2.6, 2.2, SRG-OS-000480-GPOS-00227 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/passwd
stat:
path: /etc/passwd
register: file_exists
tags:
- CJIS-5.5.2.2
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_groupowner_etc_passwd
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure group owner 0 on /etc/passwd
file:
path: /etc/passwd
group: '0'
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- CJIS-5.5.2.2
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_groupowner_etc_passwd
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chgrp 0 /etc/passwd
|
Verify Group Who Owns shadow File
[ref]rule To properly set the group owner of /etc/shadow , run the command: $ sudo chgrp shadow /etc/shadow Rationale:The /etc/shadow file stores password hashes. Protection of this file is
critical for system security. References:
R50, 12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-000366, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-8.7.c, 2.2.6, 2.2, SRG-OS-000480-GPOS-00227 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/shadow
stat:
path: /etc/shadow
register: file_exists
tags:
- CJIS-5.5.2.2
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_groupowner_etc_shadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure group owner 42 on /etc/shadow
file:
path: /etc/shadow
group: '42'
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- CJIS-5.5.2.2
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_groupowner_etc_shadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chgrp 42 /etc/shadow
|
Verify User Who Owns Backup group File
[ref]rule To properly set the owner of /etc/group- , run the command: $ sudo chown root /etc/group- Rationale:The /etc/group- file is a backup file of /etc/group , and as such,
it contains information regarding groups that are configured on the system.
Protection of this file is important for system security. Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/group-
stat:
path: /etc/group-
register: file_exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_owner_backup_etc_group
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure owner 0 on /etc/group-
file:
path: /etc/group-
owner: '0'
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_owner_backup_etc_group
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chown 0 /etc/group-
|
Verify User Who Owns Backup gshadow File
[ref]rule To properly set the owner of /etc/gshadow- , run the command: $ sudo chown root /etc/gshadow- Rationale:The /etc/gshadow- file is a backup of /etc/gshadow , and as such,
it contains group password hashes. Protection of this file is critical for system security. Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/gshadow-
stat:
path: /etc/gshadow-
register: file_exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7
- configure_strategy
- file_owner_backup_etc_gshadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure owner 0 on /etc/gshadow-
file:
path: /etc/gshadow-
owner: '0'
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7
- configure_strategy
- file_owner_backup_etc_gshadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chown 0 /etc/gshadow-
|
Verify User Who Owns Backup passwd File
[ref]rule To properly set the owner of /etc/passwd- , run the command: $ sudo chown root /etc/passwd- Rationale:The /etc/passwd- file is a backup file of /etc/passwd , and as such,
it contains information about the users that are configured on the system.
Protection of this file is critical for system security. Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/passwd-
stat:
path: /etc/passwd-
register: file_exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_owner_backup_etc_passwd
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure owner 0 on /etc/passwd-
file:
path: /etc/passwd-
owner: '0'
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_owner_backup_etc_passwd
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chown 0 /etc/passwd-
|
Verify Group Who Owns Backup shadow File
[ref]rule To properly set the owner of /etc/shadow- , run the command: $ sudo chown root /etc/shadow- Rationale:The /etc/shadow- file is a backup file of /etc/shadow , and as such,
it contains the list of local system accounts and password hashes.
Protection of this file is critical for system security. Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/shadow-
stat:
path: /etc/shadow-
register: file_exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_owner_backup_etc_shadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure owner 0 on /etc/shadow-
file:
path: /etc/shadow-
owner: '0'
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_owner_backup_etc_shadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chown 0 /etc/shadow-
|
Verify User Who Owns group File
[ref]rule To properly set the owner of /etc/group , run the command: $ sudo chown root /etc/group Rationale:The /etc/group file contains information regarding groups that are configured
on the system. Protection of this file is important for system security. References:
R50, 12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-000366, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-8.7.c, 2.2.6, 2.2, SRG-OS-000480-GPOS-00227 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/group
stat:
path: /etc/group
register: file_exists
tags:
- CJIS-5.5.2.2
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_owner_etc_group
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure owner 0 on /etc/group
file:
path: /etc/group
owner: '0'
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- CJIS-5.5.2.2
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_owner_etc_group
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chown 0 /etc/group
|
Verify User Who Owns gshadow File
[ref]rule To properly set the owner of /etc/gshadow , run the command: $ sudo chown root /etc/gshadow Rationale:The /etc/gshadow file contains group password hashes. Protection of this file
is critical for system security. References:
R50, 12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-000366, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/gshadow
stat:
path: /etc/gshadow
register: file_exists
tags:
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- configure_strategy
- file_owner_etc_gshadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure owner 0 on /etc/gshadow
file:
path: /etc/gshadow
owner: '0'
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- configure_strategy
- file_owner_etc_gshadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chown 0 /etc/gshadow
|
Verify User Who Owns passwd File
[ref]rule To properly set the owner of /etc/passwd , run the command: $ sudo chown root /etc/passwd Rationale:The /etc/passwd file contains information about the users that are configured on
the system. Protection of this file is critical for system security. References:
R50, 12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-000366, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-8.7.c, 2.2.6, 2.2, SRG-OS-000480-GPOS-00227 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/passwd
stat:
path: /etc/passwd
register: file_exists
tags:
- CJIS-5.5.2.2
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_owner_etc_passwd
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure owner 0 on /etc/passwd
file:
path: /etc/passwd
owner: '0'
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- CJIS-5.5.2.2
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_owner_etc_passwd
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chown 0 /etc/passwd
|
Verify User Who Owns shadow File
[ref]rule To properly set the owner of /etc/shadow , run the command: $ sudo chown root /etc/shadow Rationale:The /etc/shadow file contains the list of local
system accounts and stores password hashes. Protection of this file is
critical for system security. Failure to give ownership of this file
to root provides the designated owner with access to sensitive information
which could weaken the system security posture. References:
R50, 12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-000366, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-8.7.c, 2.2.6, 2.2, SRG-OS-000480-GPOS-00227 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/shadow
stat:
path: /etc/shadow
register: file_exists
tags:
- CJIS-5.5.2.2
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_owner_etc_shadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure owner 0 on /etc/shadow
file:
path: /etc/shadow
owner: '0'
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- CJIS-5.5.2.2
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_owner_etc_shadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chown 0 /etc/shadow
|
Verify Permissions on Backup group File
[ref]rule
To properly set the permissions of /etc/group- , run the command:
$ sudo chmod 0644 /etc/group- Rationale:The /etc/group- file is a backup file of /etc/group , and as such,
it contains information regarding groups that are configured on the system.
Protection of this file is important for system security. Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/group-
stat:
path: /etc/group-
register: file_exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_permissions_backup_etc_group
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure permission u-xs,g-xws,o-xwt on /etc/group-
file:
path: /etc/group-
mode: u-xs,g-xws,o-xwt
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_permissions_backup_etc_group
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chmod u-xs,g-xws,o-xwt /etc/group-
|
Verify Permissions on Backup gshadow File
[ref]rule
To properly set the permissions of /etc/gshadow- , run the command:
$ sudo chmod 0640 /etc/gshadow- Rationale:The /etc/gshadow- file is a backup of /etc/gshadow , and as such,
it contains group password hashes. Protection of this file is critical for system security. Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/gshadow-
stat:
path: /etc/gshadow-
register: file_exists
tags:
- NIST-800-53-AC-6 (1)
- configure_strategy
- file_permissions_backup_etc_gshadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure permission u-xs,g-xws,o-xwrt on /etc/gshadow-
file:
path: /etc/gshadow-
mode: u-xs,g-xws,o-xwrt
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- NIST-800-53-AC-6 (1)
- configure_strategy
- file_permissions_backup_etc_gshadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chmod u-xs,g-xws,o-xwrt /etc/gshadow-
|
Verify Permissions on Backup passwd File
[ref]rule
To properly set the permissions of /etc/passwd- , run the command:
$ sudo chmod 0644 /etc/passwd- Rationale:The /etc/passwd- file is a backup file of /etc/passwd , and as such,
it contains information about the users that are configured on the system.
Protection of this file is critical for system security. Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/passwd-
stat:
path: /etc/passwd-
register: file_exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_permissions_backup_etc_passwd
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure permission u-xs,g-xws,o-xwt on /etc/passwd-
file:
path: /etc/passwd-
mode: u-xs,g-xws,o-xwt
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_permissions_backup_etc_passwd
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chmod u-xs,g-xws,o-xwt /etc/passwd-
|
Verify Permissions on Backup shadow File
[ref]rule
To properly set the permissions of /etc/shadow- , run the command:
$ sudo chmod 0640 /etc/shadow- Rationale:The /etc/shadow- file is a backup file of /etc/shadow , and as such,
it contains the list of local system accounts and password hashes.
Protection of this file is critical for system security. Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/shadow-
stat:
path: /etc/shadow-
register: file_exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_permissions_backup_etc_shadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure permission u-xs,g-xws,o-xwrt on /etc/shadow-
file:
path: /etc/shadow-
mode: u-xs,g-xws,o-xwrt
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- NIST-800-53-AC-6 (1)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_permissions_backup_etc_shadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chmod u-xs,g-xws,o-xwrt /etc/shadow-
|
Verify Permissions on group File
[ref]rule
To properly set the permissions of /etc/group , run the command:
$ sudo chmod 0644 /etc/group Rationale:The /etc/group file contains information regarding groups that are configured
on the system. Protection of this file is important for system security. References:
R50, 12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-000366, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-8.7.c, 2.2.6, 2.2, SRG-OS-000480-GPOS-00227 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/group
stat:
path: /etc/group
register: file_exists
tags:
- CJIS-5.5.2.2
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_permissions_etc_group
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure permission u-xs,g-xws,o-xwt on /etc/group
file:
path: /etc/group
mode: u-xs,g-xws,o-xwt
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- CJIS-5.5.2.2
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_permissions_etc_group
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chmod u-xs,g-xws,o-xwt /etc/group
|
Verify Permissions on gshadow File
[ref]rule
To properly set the permissions of /etc/gshadow , run the command:
$ sudo chmod 0640 /etc/gshadow Rationale:The /etc/gshadow file contains group password hashes. Protection of this file
is critical for system security. References:
R50, 12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-000366, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/gshadow
stat:
path: /etc/gshadow
register: file_exists
tags:
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- configure_strategy
- file_permissions_etc_gshadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure permission u-xs,g-xws,o-xwrt on /etc/gshadow
file:
path: /etc/gshadow
mode: u-xs,g-xws,o-xwrt
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- configure_strategy
- file_permissions_etc_gshadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chmod u-xs,g-xws,o-xwrt /etc/gshadow
|
Verify Permissions on passwd File
[ref]rule
To properly set the permissions of /etc/passwd , run the command:
$ sudo chmod 0644 /etc/passwd Rationale:If the /etc/passwd file is writable by a group-owner or the
world the risk of its compromise is increased. The file contains the list of
accounts on the system and associated information, and protection of this file
is critical for system security. References:
R50, 12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-000366, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-8.7.c, 2.2.6, 2.2, SRG-OS-000480-GPOS-00227 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/passwd
stat:
path: /etc/passwd
register: file_exists
tags:
- CJIS-5.5.2.2
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_permissions_etc_passwd
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure permission u-xs,g-xws,o-xwt on /etc/passwd
file:
path: /etc/passwd
mode: u-xs,g-xws,o-xwt
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- CJIS-5.5.2.2
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_permissions_etc_passwd
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chmod u-xs,g-xws,o-xwt /etc/passwd
|
Verify Permissions on shadow File
[ref]rule
To properly set the permissions of /etc/shadow , run the command:
$ sudo chmod 0640 /etc/shadow Rationale:The /etc/shadow file contains the list of local
system accounts and stores password hashes. Protection of this file is
critical for system security. Failure to give ownership of this file
to root provides the designated owner with access to sensitive information
which could weaken the system security posture. References:
R50, 12, 13, 14, 15, 16, 18, 3, 5, 5.5.2.2, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-000366, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, Req-8.7.c, 2.2.6, 2.2, SRG-OS-000480-GPOS-00227 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Test for existence /etc/shadow
stat:
path: /etc/shadow
register: file_exists
tags:
- CJIS-5.5.2.2
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_permissions_etc_shadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Ensure permission u-xs,g-xws,o-xwrt on /etc/shadow
file:
path: /etc/shadow
mode: u-xs,g-xws,o-xwrt
when: file_exists.stat is defined and file_exists.stat.exists
tags:
- CJIS-5.5.2.2
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.7.c
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- configure_strategy
- file_permissions_etc_shadow
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
chmod u-xs,g-xws,o-xwrt /etc/shadow
|
Verify that All World-Writable Directories Have Sticky Bits Set
[ref]ruleWhen the so-called 'sticky bit' is set on a directory, only the owner of a given file may
remove that file from the directory. Without the sticky bit, any user with write access to a
directory may remove any file in the directory. Setting the sticky bit prevents users from
removing each other's files. In cases where there is no reason for a directory to be
world-writable, a better solution is to remove that permission rather than to set the sticky
bit. However, if a directory is used by a particular application, consult that application's
documentation instead of blindly changing modes.
To set the sticky bit on a world-writable directory DIR, run the following command:
$ sudo chmod +t DIR Warning:
This rule can take a long time to perform the check and might consume a considerable
amount of resources depending on the number of directories present on the system. It is
not a problem in most cases, but especially systems with a large number of directories can
be affected. See https://access.redhat.com/articles/6999111 . Rationale:Failing to set the sticky bit on public directories allows unauthorized users to delete files
in the directory structure.
The only authorized public directories are those temporary directories supplied with the
system, or those designed to be temporary file repositories. The setting is normally reserved
for directories used by the system, by users for temporary file storage (such as /tmp ),
and for directories requiring global read/write access. References:
R54, 1.1.20, 12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, CCI-001090, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, 2.2.6, 2.2, SRG-OS-000138-GPOS-00069 Remediation Shell script: (show)
df --local -P | awk '{if (NR!=1) print $6}' \
| xargs -I '$6' find '$6' -xdev -type d \
\( -perm -0002 -a ! -perm -1000 \) 2>/dev/null \
-exec chmod a+t {} +
|
Ensure No World-Writable Files Exist
[ref]ruleIt is generally a good idea to remove global (other) write access to a file when it is
discovered. However, check with documentation for specific applications before making changes.
Also, monitor for recurring world-writable files, as these may be symptoms of a misconfigured
application or user account. Finally, this applies to real files and not virtual files that
are a part of pseudo file systems such as sysfs or procfs . Warning:
This rule can take a long time to perform the check and might consume a considerable
amount of resources depending on the number of files present on the system. It is not a
problem in most cases, but especially systems with a large number of files can be affected.
See https://access.redhat.com/articles/6999111 . Rationale:Data in world-writable files can be modified by any user on the system. In almost all
circumstances, files can be configured using a combination of user and group permissions to
support whatever legitimate access is needed without the risk caused by world-writable files. References:
R54, 12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, 2.2.6, 2.2 Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
FILTER_NODEV=$(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,)
PARTITIONS=$(findmnt -n -l -k -it $FILTER_NODEV | awk '{ print $1 }')
for PARTITION in $PARTITIONS; do
find "${PARTITION}" -xdev -type f -perm -002 -exec chmod o-w {} \; 2>/dev/null
done
# Ensure /tmp is also fixed whem tmpfs is used.
if grep "^tmpfs /tmp" /proc/mounts; then
find /tmp -xdev -type f -perm -002 -exec chmod o-w {} \; 2>/dev/null
fi
|
Restrict Dynamic Mounting and Unmounting of
Filesystems
[ref]groupLinux includes a number of facilities for the automated addition
and removal of filesystems on a running system. These facilities may be
necessary in many environments, but this capability also carries some risk -- whether direct
risk from allowing users to introduce arbitrary filesystems,
or risk that software flaws in the automated mount facility itself could
allow an attacker to compromise the system.
This command can be used to list the types of filesystems that are
available to the currently executing kernel:
$ find /lib/modules/`uname -r`/kernel/fs -type f -name '*.ko'
If these filesystems are not required then they can be explicitly disabled
in a configuratio file in /etc/modprobe.d . |
contains 6 rules |
Disable Mounting of cramfs
[ref]rule
To configure the system to prevent the cramfs
kernel module from being loaded, add the following line to the file /etc/modprobe.d/cramfs.conf :
install cramfs /bin/false
This effectively prevents usage of this uncommon filesystem.
The cramfs filesystem type is a compressed read-only
Linux filesystem embedded in small footprint systems. A
cramfs image can be used without having to first
decompress the image.Rationale:Removing support for unneeded filesystem types reduces the local attack surface
of the server. References:
1.1.1.1, 11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 3.4.6, CCI-000381, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3, SRG-OS-000095-GPOS-00049 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | medium |
---|
Reboot: | true |
---|
Strategy: | disable |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- NIST-800-171-3.4.6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_cramfs_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
- name: Ensure kernel module 'cramfs' is disabled
lineinfile:
create: true
dest: /etc/modprobe.d/cramfs.conf
regexp: install\s+cramfs
line: install cramfs /bin/false
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-171-3.4.6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_cramfs_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
- name: Ensure kernel module 'cramfs' is blacklisted
lineinfile:
create: true
dest: /etc/modprobe.d/cramfs.conf
regexp: ^blacklist cramfs$
line: blacklist cramfs
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-171-3.4.6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_cramfs_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | medium |
---|
Reboot: | true |
---|
Strategy: | disable |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed; then
if LC_ALL=C grep -q -m 1 "^install cramfs" /etc/modprobe.d/cramfs.conf ; then
sed -i 's#^install cramfs.*#install cramfs /bin/false#g' /etc/modprobe.d/cramfs.conf
else
echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/cramfs.conf
echo "install cramfs /bin/false" >> /etc/modprobe.d/cramfs.conf
fi
if ! LC_ALL=C grep -q -m 1 "^blacklist cramfs$" /etc/modprobe.d/cramfs.conf ; then
echo "blacklist cramfs" >> /etc/modprobe.d/cramfs.conf
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Disable Mounting of freevxfs
[ref]rule
To configure the system to prevent the freevxfs
kernel module from being loaded, add the following line to the file /etc/modprobe.d/freevxfs.conf :
install freevxfs /bin/false
This effectively prevents usage of this uncommon filesystem.Rationale:Linux kernel modules which implement filesystems that are not needed by the
local system should be disabled. References:
11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 3.4.6, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | medium |
---|
Reboot: | true |
---|
Strategy: | disable |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- NIST-800-171-3.4.6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_freevxfs_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
- name: Ensure kernel module 'freevxfs' is disabled
lineinfile:
create: true
dest: /etc/modprobe.d/freevxfs.conf
regexp: install\s+freevxfs
line: install freevxfs /bin/false
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-171-3.4.6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_freevxfs_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
- name: Ensure kernel module 'freevxfs' is blacklisted
lineinfile:
create: true
dest: /etc/modprobe.d/freevxfs.conf
regexp: ^blacklist freevxfs$
line: blacklist freevxfs
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-171-3.4.6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_freevxfs_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | medium |
---|
Reboot: | true |
---|
Strategy: | disable |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed; then
if LC_ALL=C grep -q -m 1 "^install freevxfs" /etc/modprobe.d/freevxfs.conf ; then
sed -i 's#^install freevxfs.*#install freevxfs /bin/false#g' /etc/modprobe.d/freevxfs.conf
else
echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/freevxfs.conf
echo "install freevxfs /bin/false" >> /etc/modprobe.d/freevxfs.conf
fi
if ! LC_ALL=C grep -q -m 1 "^blacklist freevxfs$" /etc/modprobe.d/freevxfs.conf ; then
echo "blacklist freevxfs" >> /etc/modprobe.d/freevxfs.conf
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Disable Mounting of hfs
[ref]rule
To configure the system to prevent the hfs
kernel module from being loaded, add the following line to the file /etc/modprobe.d/hfs.conf :
install hfs /bin/false
This effectively prevents usage of this uncommon filesystem.Rationale:Linux kernel modules which implement filesystems that are not needed by the
local system should be disabled. References:
11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 3.4.6, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | medium |
---|
Reboot: | true |
---|
Strategy: | disable |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- NIST-800-171-3.4.6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_hfs_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
- name: Ensure kernel module 'hfs' is disabled
lineinfile:
create: true
dest: /etc/modprobe.d/hfs.conf
regexp: install\s+hfs
line: install hfs /bin/false
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-171-3.4.6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_hfs_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
- name: Ensure kernel module 'hfs' is blacklisted
lineinfile:
create: true
dest: /etc/modprobe.d/hfs.conf
regexp: ^blacklist hfs$
line: blacklist hfs
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-171-3.4.6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_hfs_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | medium |
---|
Reboot: | true |
---|
Strategy: | disable |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed; then
if LC_ALL=C grep -q -m 1 "^install hfs" /etc/modprobe.d/hfs.conf ; then
sed -i 's#^install hfs.*#install hfs /bin/false#g' /etc/modprobe.d/hfs.conf
else
echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/hfs.conf
echo "install hfs /bin/false" >> /etc/modprobe.d/hfs.conf
fi
if ! LC_ALL=C grep -q -m 1 "^blacklist hfs$" /etc/modprobe.d/hfs.conf ; then
echo "blacklist hfs" >> /etc/modprobe.d/hfs.conf
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Disable Mounting of hfsplus
[ref]rule
To configure the system to prevent the hfsplus
kernel module from being loaded, add the following line to the file /etc/modprobe.d/hfsplus.conf :
install hfsplus /bin/false
This effectively prevents usage of this uncommon filesystem.Rationale:Linux kernel modules which implement filesystems that are not needed by the
local system should be disabled. References:
11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 3.4.6, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | medium |
---|
Reboot: | true |
---|
Strategy: | disable |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- NIST-800-171-3.4.6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_hfsplus_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
- name: Ensure kernel module 'hfsplus' is disabled
lineinfile:
create: true
dest: /etc/modprobe.d/hfsplus.conf
regexp: install\s+hfsplus
line: install hfsplus /bin/false
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-171-3.4.6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_hfsplus_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
- name: Ensure kernel module 'hfsplus' is blacklisted
lineinfile:
create: true
dest: /etc/modprobe.d/hfsplus.conf
regexp: ^blacklist hfsplus$
line: blacklist hfsplus
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-171-3.4.6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_hfsplus_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | medium |
---|
Reboot: | true |
---|
Strategy: | disable |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed; then
if LC_ALL=C grep -q -m 1 "^install hfsplus" /etc/modprobe.d/hfsplus.conf ; then
sed -i 's#^install hfsplus.*#install hfsplus /bin/false#g' /etc/modprobe.d/hfsplus.conf
else
echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/hfsplus.conf
echo "install hfsplus /bin/false" >> /etc/modprobe.d/hfsplus.conf
fi
if ! LC_ALL=C grep -q -m 1 "^blacklist hfsplus$" /etc/modprobe.d/hfsplus.conf ; then
echo "blacklist hfsplus" >> /etc/modprobe.d/hfsplus.conf
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Disable Mounting of jffs2
[ref]rule
To configure the system to prevent the jffs2
kernel module from being loaded, add the following line to the file /etc/modprobe.d/jffs2.conf :
install jffs2 /bin/false
This effectively prevents usage of this uncommon filesystem.Rationale:Linux kernel modules which implement filesystems that are not needed by the
local system should be disabled. References:
11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 3.4.6, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | medium |
---|
Reboot: | true |
---|
Strategy: | disable |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- NIST-800-171-3.4.6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_jffs2_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
- name: Ensure kernel module 'jffs2' is disabled
lineinfile:
create: true
dest: /etc/modprobe.d/jffs2.conf
regexp: install\s+jffs2
line: install jffs2 /bin/false
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-171-3.4.6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_jffs2_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
- name: Ensure kernel module 'jffs2' is blacklisted
lineinfile:
create: true
dest: /etc/modprobe.d/jffs2.conf
regexp: ^blacklist jffs2$
line: blacklist jffs2
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-171-3.4.6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_jffs2_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | medium |
---|
Reboot: | true |
---|
Strategy: | disable |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed; then
if LC_ALL=C grep -q -m 1 "^install jffs2" /etc/modprobe.d/jffs2.conf ; then
sed -i 's#^install jffs2.*#install jffs2 /bin/false#g' /etc/modprobe.d/jffs2.conf
else
echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/jffs2.conf
echo "install jffs2 /bin/false" >> /etc/modprobe.d/jffs2.conf
fi
if ! LC_ALL=C grep -q -m 1 "^blacklist jffs2$" /etc/modprobe.d/jffs2.conf ; then
echo "blacklist jffs2" >> /etc/modprobe.d/jffs2.conf
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Disable Mounting of udf
[ref]rule
To configure the system to prevent the udf
kernel module from being loaded, add the following line to the file /etc/modprobe.d/udf.conf :
install udf /bin/false
This effectively prevents usage of this uncommon filesystem.
The udf filesystem type is the universal disk format
used to implement the ISO/IEC 13346 and ECMA-167 specifications.
This is an open vendor filesystem type for data storage on a broad
range of media. This filesystem type is neccessary to support
writing DVDs and newer optical disc formats.Rationale:Removing support for unneeded filesystem types reduces the local
attack surface of the system. References:
1.1.1.6, 11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 3.4.6, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | medium |
---|
Reboot: | true |
---|
Strategy: | disable |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- NIST-800-171-3.4.6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_udf_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
- name: Ensure kernel module 'udf' is disabled
lineinfile:
create: true
dest: /etc/modprobe.d/udf.conf
regexp: install\s+udf
line: install udf /bin/false
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-171-3.4.6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_udf_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
- name: Ensure kernel module 'udf' is blacklisted
lineinfile:
create: true
dest: /etc/modprobe.d/udf.conf
regexp: ^blacklist udf$
line: blacklist udf
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-171-3.4.6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- kernel_module_udf_disabled
- low_complexity
- low_severity
- medium_disruption
- reboot_required
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | medium |
---|
Reboot: | true |
---|
Strategy: | disable |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed; then
if LC_ALL=C grep -q -m 1 "^install udf" /etc/modprobe.d/udf.conf ; then
sed -i 's#^install udf.*#install udf /bin/false#g' /etc/modprobe.d/udf.conf
else
echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/udf.conf
echo "install udf /bin/false" >> /etc/modprobe.d/udf.conf
fi
if ! LC_ALL=C grep -q -m 1 "^blacklist udf$" /etc/modprobe.d/udf.conf ; then
echo "blacklist udf" >> /etc/modprobe.d/udf.conf
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Restrict Partition Mount Options
[ref]groupSystem partitions can be mounted with certain options
that limit what files on those partitions can do. These options
are set in the /etc/fstab configuration file, and can be
used to make certain types of malicious behavior more difficult. |
contains 6 rules |
Add nodev Option to /home
[ref]ruleThe nodev mount option can be used to prevent device files from
being created in /home .
Legitimate character and block devices should exist only in
the /dev directory on the root partition or within chroot
jails built for system services.
Add the nodev option to the fourth column of
/etc/fstab for the line which controls mounting of
/home . Rationale:The only legitimate location for device files is the /dev directory
located on the root partition. The only exception to this is chroot jails. Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | high |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- configure_strategy
- high_disruption
- low_complexity
- mount_option_home_nodev
- no_reboot_needed
- unknown_severity
- name: 'Add nodev Option to /home: Check information associated to mountpoint'
command: findmnt --fstab '/home'
register: device_name
failed_when: device_name.rc > 1
changed_when: false
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/home" in ansible_mounts | map(attribute="mount") | list'
tags:
- configure_strategy
- high_disruption
- low_complexity
- mount_option_home_nodev
- no_reboot_needed
- unknown_severity
- name: 'Add nodev Option to /home: Create mount_info dictionary variable'
set_fact:
mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
with_together:
- '{{ device_name.stdout_lines[0].split() | list | lower }}'
- '{{ device_name.stdout_lines[1].split() | list }}'
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/home" in ansible_mounts | map(attribute="mount") | list'
- device_name.stdout is defined and device_name.stdout_lines is defined
- (device_name.stdout | length > 0)
tags:
- configure_strategy
- high_disruption
- low_complexity
- mount_option_home_nodev
- no_reboot_needed
- unknown_severity
- name: 'Add nodev Option to /home: If /home not mounted, craft mount_info manually'
set_fact:
mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
with_together:
- - target
- source
- fstype
- options
- - /home
- ''
- ''
- defaults
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/home" in ansible_mounts | map(attribute="mount") | list'
- ("--fstab" | length == 0)
- device_name.stdout is defined and device_name.stdout_lines is defined
- (device_name.stdout | length == 0)
tags:
- configure_strategy
- high_disruption
- low_complexity
- mount_option_home_nodev
- no_reboot_needed
- unknown_severity
- name: 'Add nodev Option to /home: Make sure nodev option is part of the to /home
options'
set_fact:
mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev''
}) }}'
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/home" in ansible_mounts | map(attribute="mount") | list'
- mount_info is defined and "nodev" not in mount_info.options
tags:
- configure_strategy
- high_disruption
- low_complexity
- mount_option_home_nodev
- no_reboot_needed
- unknown_severity
- name: 'Add nodev Option to /home: Ensure /home is mounted with nodev option'
mount:
path: /home
src: '{{ mount_info.source }}'
opts: '{{ mount_info.options }}'
state: mounted
fstype: '{{ mount_info.fstype }}'
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/home" in ansible_mounts | map(attribute="mount") | list'
- mount_info is defined
- (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
| length == 0)
tags:
- configure_strategy
- high_disruption
- low_complexity
- mount_option_home_nodev
- no_reboot_needed
- unknown_severity
Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/home" > /dev/null || findmnt --fstab "/home" > /dev/null; }; then
function perform_remediation {
# the mount point /home has to be defined in /etc/fstab
# before this remediation can be executed. In case it is not defined, the
# remediation aborts and no changes regarding the mount point are done.
mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/home")"
grep "$mount_point_match_regexp" -q /etc/fstab \
|| { echo "The mount point '/home' is not even in /etc/fstab, so we can't set up mount options" >&2;
echo "Not remediating, because there is no record of /home in /etc/fstab" >&2; return 1; }
mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /home)"
# If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
if ! grep -q "$mount_point_match_regexp" /etc/fstab; then
# runtime opts without some automatic kernel/userspace-added defaults
previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \
| sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//")
[ "$previous_mount_opts" ] && previous_mount_opts+=","
# In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in
# fstab as "block". The next variable is to satisfy shellcheck SC2050.
fs_type=""
if [ "$fs_type" == "iso9660" ] ; then
previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts")
fi
echo " /home defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab
# If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nodev"; then
previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab
fi
if mkdir -p "/home"; then
if mountpoint -q "/home"; then
mount -o remount --target "/home"
fi
fi
}
perform_remediation
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Add nodev Option to /tmp
[ref]ruleThe nodev mount option can be used to prevent device files from
being created in /tmp . Legitimate character and block devices
should not exist within temporary directories like /tmp .
Add the nodev option to the fourth column of
/etc/fstab for the line which controls mounting of
/tmp . Rationale:The only legitimate location for device files is the /dev directory
located on the root partition. The only exception to this is chroot jails. References:
1.1.3, 11, 13, 14, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS05.06, DSS06.06, CCI-001764, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.11.2.9, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.8.2.1, A.8.2.2, A.8.2.3, A.8.3.1, A.8.3.3, A.9.1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | high |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- NIST-800-53-AC-6
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- NIST-800-53-MP-7
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_tmp_nodev
- no_reboot_needed
- name: 'Add nodev Option to /tmp: Check information associated to mountpoint'
command: findmnt --fstab '/tmp'
register: device_name
failed_when: device_name.rc > 1
changed_when: false
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/tmp" in ansible_mounts | map(attribute="mount") | list'
tags:
- NIST-800-53-AC-6
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- NIST-800-53-MP-7
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_tmp_nodev
- no_reboot_needed
- name: 'Add nodev Option to /tmp: Create mount_info dictionary variable'
set_fact:
mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
with_together:
- '{{ device_name.stdout_lines[0].split() | list | lower }}'
- '{{ device_name.stdout_lines[1].split() | list }}'
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/tmp" in ansible_mounts | map(attribute="mount") | list'
- device_name.stdout is defined and device_name.stdout_lines is defined
- (device_name.stdout | length > 0)
tags:
- NIST-800-53-AC-6
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- NIST-800-53-MP-7
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_tmp_nodev
- no_reboot_needed
- name: 'Add nodev Option to /tmp: If /tmp not mounted, craft mount_info manually'
set_fact:
mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
with_together:
- - target
- source
- fstype
- options
- - /tmp
- ''
- ''
- defaults
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/tmp" in ansible_mounts | map(attribute="mount") | list'
- ("--fstab" | length == 0)
- device_name.stdout is defined and device_name.stdout_lines is defined
- (device_name.stdout | length == 0)
tags:
- NIST-800-53-AC-6
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- NIST-800-53-MP-7
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_tmp_nodev
- no_reboot_needed
- name: 'Add nodev Option to /tmp: Make sure nodev option is part of the to /tmp options'
set_fact:
mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev''
}) }}'
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/tmp" in ansible_mounts | map(attribute="mount") | list'
- mount_info is defined and "nodev" not in mount_info.options
tags:
- NIST-800-53-AC-6
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- NIST-800-53-MP-7
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_tmp_nodev
- no_reboot_needed
- name: 'Add nodev Option to /tmp: Ensure /tmp is mounted with nodev option'
mount:
path: /tmp
src: '{{ mount_info.source }}'
opts: '{{ mount_info.options }}'
state: mounted
fstype: '{{ mount_info.fstype }}'
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/tmp" in ansible_mounts | map(attribute="mount") | list'
- mount_info is defined
- (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
| length == 0)
tags:
- NIST-800-53-AC-6
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- NIST-800-53-MP-7
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_tmp_nodev
- no_reboot_needed
Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null; }; then
function perform_remediation {
# the mount point /tmp has to be defined in /etc/fstab
# before this remediation can be executed. In case it is not defined, the
# remediation aborts and no changes regarding the mount point are done.
mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/tmp")"
grep "$mount_point_match_regexp" -q /etc/fstab \
|| { echo "The mount point '/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2;
echo "Not remediating, because there is no record of /tmp in /etc/fstab" >&2; return 1; }
mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /tmp)"
# If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
if ! grep -q "$mount_point_match_regexp" /etc/fstab; then
# runtime opts without some automatic kernel/userspace-added defaults
previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \
| sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//")
[ "$previous_mount_opts" ] && previous_mount_opts+=","
# In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in
# fstab as "block". The next variable is to satisfy shellcheck SC2050.
fs_type=""
if [ "$fs_type" == "iso9660" ] ; then
previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts")
fi
echo " /tmp defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab
# If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nodev"; then
previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab
fi
if mkdir -p "/tmp"; then
if mountpoint -q "/tmp"; then
mount -o remount --target "/tmp"
fi
fi
}
perform_remediation
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Add nosuid Option to /tmp
[ref]ruleThe nosuid mount option can be used to prevent
execution of setuid programs in /tmp . The SUID and SGID permissions
should not be required in these world-writable directories.
Add the nosuid option to the fourth column of
/etc/fstab for the line which controls mounting of
/tmp . Rationale:The presence of SUID and SGID executables should be tightly controlled. Users
should not be able to execute SUID or SGID binaries from temporary storage partitions. References:
R28, 1.1.4, 11, 13, 14, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS05.06, DSS06.06, CCI-001764, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.11.2.9, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.8.2.1, A.8.2.2, A.8.2.3, A.8.3.1, A.8.3.3, A.9.1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | high |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- NIST-800-53-AC-6
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- NIST-800-53-MP-7
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_tmp_nosuid
- no_reboot_needed
- name: 'Add nosuid Option to /tmp: Check information associated to mountpoint'
command: findmnt --fstab '/tmp'
register: device_name
failed_when: device_name.rc > 1
changed_when: false
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/tmp" in ansible_mounts | map(attribute="mount") | list'
tags:
- NIST-800-53-AC-6
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- NIST-800-53-MP-7
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_tmp_nosuid
- no_reboot_needed
- name: 'Add nosuid Option to /tmp: Create mount_info dictionary variable'
set_fact:
mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
with_together:
- '{{ device_name.stdout_lines[0].split() | list | lower }}'
- '{{ device_name.stdout_lines[1].split() | list }}'
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/tmp" in ansible_mounts | map(attribute="mount") | list'
- device_name.stdout is defined and device_name.stdout_lines is defined
- (device_name.stdout | length > 0)
tags:
- NIST-800-53-AC-6
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- NIST-800-53-MP-7
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_tmp_nosuid
- no_reboot_needed
- name: 'Add nosuid Option to /tmp: If /tmp not mounted, craft mount_info manually'
set_fact:
mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
with_together:
- - target
- source
- fstype
- options
- - /tmp
- ''
- ''
- defaults
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/tmp" in ansible_mounts | map(attribute="mount") | list'
- ("--fstab" | length == 0)
- device_name.stdout is defined and device_name.stdout_lines is defined
- (device_name.stdout | length == 0)
tags:
- NIST-800-53-AC-6
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- NIST-800-53-MP-7
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_tmp_nosuid
- no_reboot_needed
- name: 'Add nosuid Option to /tmp: Make sure nosuid option is part of the to /tmp
options'
set_fact:
mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid''
}) }}'
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/tmp" in ansible_mounts | map(attribute="mount") | list'
- mount_info is defined and "nosuid" not in mount_info.options
tags:
- NIST-800-53-AC-6
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- NIST-800-53-MP-7
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_tmp_nosuid
- no_reboot_needed
- name: 'Add nosuid Option to /tmp: Ensure /tmp is mounted with nosuid option'
mount:
path: /tmp
src: '{{ mount_info.source }}'
opts: '{{ mount_info.options }}'
state: mounted
fstype: '{{ mount_info.fstype }}'
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/tmp" in ansible_mounts | map(attribute="mount") | list'
- mount_info is defined
- (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
| length == 0)
tags:
- NIST-800-53-AC-6
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- NIST-800-53-MP-7
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_tmp_nosuid
- no_reboot_needed
Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null; }; then
function perform_remediation {
# the mount point /tmp has to be defined in /etc/fstab
# before this remediation can be executed. In case it is not defined, the
# remediation aborts and no changes regarding the mount point are done.
mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/tmp")"
grep "$mount_point_match_regexp" -q /etc/fstab \
|| { echo "The mount point '/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2;
echo "Not remediating, because there is no record of /tmp in /etc/fstab" >&2; return 1; }
mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /tmp)"
# If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
if ! grep -q "$mount_point_match_regexp" /etc/fstab; then
# runtime opts without some automatic kernel/userspace-added defaults
previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \
| sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//")
[ "$previous_mount_opts" ] && previous_mount_opts+=","
# In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in
# fstab as "block". The next variable is to satisfy shellcheck SC2050.
fs_type=""
if [ "$fs_type" == "iso9660" ] ; then
previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts")
fi
echo " /tmp defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab
# If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nosuid"; then
previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab
fi
if mkdir -p "/tmp"; then
if mountpoint -q "/tmp"; then
mount -o remount --target "/tmp"
fi
fi
}
perform_remediation
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Add nodev Option to /var/tmp
[ref]ruleThe nodev mount option can be used to prevent device files from
being created in /var/tmp . Legitimate character and block devices
should not exist within temporary directories like /var/tmp .
Add the nodev option to the fourth column of
/etc/fstab for the line which controls mounting of
/var/tmp . Rationale:The only legitimate location for device files is the /dev directory
located on the root partition. The only exception to this is chroot jails. Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | high |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_var_tmp_nodev
- no_reboot_needed
- name: 'Add nodev Option to /var/tmp: Check information associated to mountpoint'
command: findmnt --fstab '/var/tmp'
register: device_name
failed_when: device_name.rc > 1
changed_when: false
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/var/tmp" in ansible_mounts | map(attribute="mount") | list'
tags:
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_var_tmp_nodev
- no_reboot_needed
- name: 'Add nodev Option to /var/tmp: Create mount_info dictionary variable'
set_fact:
mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
with_together:
- '{{ device_name.stdout_lines[0].split() | list | lower }}'
- '{{ device_name.stdout_lines[1].split() | list }}'
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/var/tmp" in ansible_mounts | map(attribute="mount") | list'
- device_name.stdout is defined and device_name.stdout_lines is defined
- (device_name.stdout | length > 0)
tags:
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_var_tmp_nodev
- no_reboot_needed
- name: 'Add nodev Option to /var/tmp: If /var/tmp not mounted, craft mount_info manually'
set_fact:
mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
with_together:
- - target
- source
- fstype
- options
- - /var/tmp
- ''
- ''
- defaults
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/var/tmp" in ansible_mounts | map(attribute="mount") | list'
- ("--fstab" | length == 0)
- device_name.stdout is defined and device_name.stdout_lines is defined
- (device_name.stdout | length == 0)
tags:
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_var_tmp_nodev
- no_reboot_needed
- name: 'Add nodev Option to /var/tmp: Make sure nodev option is part of the to /var/tmp
options'
set_fact:
mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev''
}) }}'
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/var/tmp" in ansible_mounts | map(attribute="mount") | list'
- mount_info is defined and "nodev" not in mount_info.options
tags:
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_var_tmp_nodev
- no_reboot_needed
- name: 'Add nodev Option to /var/tmp: Ensure /var/tmp is mounted with nodev option'
mount:
path: /var/tmp
src: '{{ mount_info.source }}'
opts: '{{ mount_info.options }}'
state: mounted
fstype: '{{ mount_info.fstype }}'
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/var/tmp" in ansible_mounts | map(attribute="mount") | list'
- mount_info is defined
- (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
| length == 0)
tags:
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_var_tmp_nodev
- no_reboot_needed
Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null; }; then
function perform_remediation {
# the mount point /var/tmp has to be defined in /etc/fstab
# before this remediation can be executed. In case it is not defined, the
# remediation aborts and no changes regarding the mount point are done.
mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/var/tmp")"
grep "$mount_point_match_regexp" -q /etc/fstab \
|| { echo "The mount point '/var/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2;
echo "Not remediating, because there is no record of /var/tmp in /etc/fstab" >&2; return 1; }
mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /var/tmp)"
# If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
if ! grep -q "$mount_point_match_regexp" /etc/fstab; then
# runtime opts without some automatic kernel/userspace-added defaults
previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \
| sed -E "s/(rw|defaults|seclabel|nodev)(,|$)//g;s/,$//")
[ "$previous_mount_opts" ] && previous_mount_opts+=","
# In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in
# fstab as "block". The next variable is to satisfy shellcheck SC2050.
fs_type=""
if [ "$fs_type" == "iso9660" ] ; then
previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts")
fi
echo " /var/tmp defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab
# If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nodev"; then
previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab
fi
if mkdir -p "/var/tmp"; then
if mountpoint -q "/var/tmp"; then
mount -o remount --target "/var/tmp"
fi
fi
}
perform_remediation
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Add noexec Option to /var/tmp
[ref]ruleThe noexec mount option can be used to prevent binaries
from being executed out of /var/tmp .
Add the noexec option to the fourth column of
/etc/fstab for the line which controls mounting of
/var/tmp . Rationale:Allowing users to execute binaries from world-writable directories
such as /var/tmp should never be necessary in normal operation and
can expose the system to potential compromise. Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | high |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_var_tmp_noexec
- no_reboot_needed
- name: 'Add noexec Option to /var/tmp: Check information associated to mountpoint'
command: findmnt --fstab '/var/tmp'
register: device_name
failed_when: device_name.rc > 1
changed_when: false
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/var/tmp" in ansible_mounts | map(attribute="mount") | list'
tags:
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_var_tmp_noexec
- no_reboot_needed
- name: 'Add noexec Option to /var/tmp: Create mount_info dictionary variable'
set_fact:
mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
with_together:
- '{{ device_name.stdout_lines[0].split() | list | lower }}'
- '{{ device_name.stdout_lines[1].split() | list }}'
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/var/tmp" in ansible_mounts | map(attribute="mount") | list'
- device_name.stdout is defined and device_name.stdout_lines is defined
- (device_name.stdout | length > 0)
tags:
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_var_tmp_noexec
- no_reboot_needed
- name: 'Add noexec Option to /var/tmp: If /var/tmp not mounted, craft mount_info
manually'
set_fact:
mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
with_together:
- - target
- source
- fstype
- options
- - /var/tmp
- ''
- ''
- defaults
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/var/tmp" in ansible_mounts | map(attribute="mount") | list'
- ("--fstab" | length == 0)
- device_name.stdout is defined and device_name.stdout_lines is defined
- (device_name.stdout | length == 0)
tags:
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_var_tmp_noexec
- no_reboot_needed
- name: 'Add noexec Option to /var/tmp: Make sure noexec option is part of the to
/var/tmp options'
set_fact:
mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec''
}) }}'
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/var/tmp" in ansible_mounts | map(attribute="mount") | list'
- mount_info is defined and "noexec" not in mount_info.options
tags:
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_var_tmp_noexec
- no_reboot_needed
- name: 'Add noexec Option to /var/tmp: Ensure /var/tmp is mounted with noexec option'
mount:
path: /var/tmp
src: '{{ mount_info.source }}'
opts: '{{ mount_info.options }}'
state: mounted
fstype: '{{ mount_info.fstype }}'
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/var/tmp" in ansible_mounts | map(attribute="mount") | list'
- mount_info is defined
- (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
| length == 0)
tags:
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_var_tmp_noexec
- no_reboot_needed
Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null; }; then
function perform_remediation {
# the mount point /var/tmp has to be defined in /etc/fstab
# before this remediation can be executed. In case it is not defined, the
# remediation aborts and no changes regarding the mount point are done.
mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/var/tmp")"
grep "$mount_point_match_regexp" -q /etc/fstab \
|| { echo "The mount point '/var/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2;
echo "Not remediating, because there is no record of /var/tmp in /etc/fstab" >&2; return 1; }
mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /var/tmp)"
# If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
if ! grep -q "$mount_point_match_regexp" /etc/fstab; then
# runtime opts without some automatic kernel/userspace-added defaults
previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \
| sed -E "s/(rw|defaults|seclabel|noexec)(,|$)//g;s/,$//")
[ "$previous_mount_opts" ] && previous_mount_opts+=","
# In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in
# fstab as "block". The next variable is to satisfy shellcheck SC2050.
fs_type=""
if [ "$fs_type" == "iso9660" ] ; then
previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts")
fi
echo " /var/tmp defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab
# If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "noexec"; then
previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,noexec|" /etc/fstab
fi
if mkdir -p "/var/tmp"; then
if mountpoint -q "/var/tmp"; then
mount -o remount --target "/var/tmp"
fi
fi
}
perform_remediation
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Add nosuid Option to /var/tmp
[ref]ruleThe nosuid mount option can be used to prevent
execution of setuid programs in /var/tmp . The SUID and SGID permissions
should not be required in these world-writable directories.
Add the nosuid option to the fourth column of
/etc/fstab for the line which controls mounting of
/var/tmp . Rationale:The presence of SUID and SGID executables should be tightly controlled. Users
should not be able to execute SUID or SGID binaries from temporary storage partitions. Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | high |
---|
Reboot: | false |
---|
Strategy: | configure |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_var_tmp_nosuid
- no_reboot_needed
- name: 'Add nosuid Option to /var/tmp: Check information associated to mountpoint'
command: findmnt --fstab '/var/tmp'
register: device_name
failed_when: device_name.rc > 1
changed_when: false
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/var/tmp" in ansible_mounts | map(attribute="mount") | list'
tags:
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_var_tmp_nosuid
- no_reboot_needed
- name: 'Add nosuid Option to /var/tmp: Create mount_info dictionary variable'
set_fact:
mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
with_together:
- '{{ device_name.stdout_lines[0].split() | list | lower }}'
- '{{ device_name.stdout_lines[1].split() | list }}'
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/var/tmp" in ansible_mounts | map(attribute="mount") | list'
- device_name.stdout is defined and device_name.stdout_lines is defined
- (device_name.stdout | length > 0)
tags:
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_var_tmp_nosuid
- no_reboot_needed
- name: 'Add nosuid Option to /var/tmp: If /var/tmp not mounted, craft mount_info
manually'
set_fact:
mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
with_together:
- - target
- source
- fstype
- options
- - /var/tmp
- ''
- ''
- defaults
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/var/tmp" in ansible_mounts | map(attribute="mount") | list'
- ("--fstab" | length == 0)
- device_name.stdout is defined and device_name.stdout_lines is defined
- (device_name.stdout | length == 0)
tags:
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_var_tmp_nosuid
- no_reboot_needed
- name: 'Add nosuid Option to /var/tmp: Make sure nosuid option is part of the to
/var/tmp options'
set_fact:
mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid''
}) }}'
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/var/tmp" in ansible_mounts | map(attribute="mount") | list'
- mount_info is defined and "nosuid" not in mount_info.options
tags:
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_var_tmp_nosuid
- no_reboot_needed
- name: 'Add nosuid Option to /var/tmp: Ensure /var/tmp is mounted with nosuid option'
mount:
path: /var/tmp
src: '{{ mount_info.source }}'
opts: '{{ mount_info.options }}'
state: mounted
fstype: '{{ mount_info.fstype }}'
when:
- ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
- '"/var/tmp" in ansible_mounts | map(attribute="mount") | list'
- mount_info is defined
- (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
| length == 0)
tags:
- configure_strategy
- high_disruption
- low_complexity
- medium_severity
- mount_option_var_tmp_nosuid
- no_reboot_needed
Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null; }; then
function perform_remediation {
# the mount point /var/tmp has to be defined in /etc/fstab
# before this remediation can be executed. In case it is not defined, the
# remediation aborts and no changes regarding the mount point are done.
mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/var/tmp")"
grep "$mount_point_match_regexp" -q /etc/fstab \
|| { echo "The mount point '/var/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2;
echo "Not remediating, because there is no record of /var/tmp in /etc/fstab" >&2; return 1; }
mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /var/tmp)"
# If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
if ! grep -q "$mount_point_match_regexp" /etc/fstab; then
# runtime opts without some automatic kernel/userspace-added defaults
previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \
| sed -E "s/(rw|defaults|seclabel|nosuid)(,|$)//g;s/,$//")
[ "$previous_mount_opts" ] && previous_mount_opts+=","
# In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in
# fstab as "block". The next variable is to satisfy shellcheck SC2050.
fs_type=""
if [ "$fs_type" == "iso9660" ] ; then
previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts")
fi
echo " /var/tmp defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab
# If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nosuid"; then
previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}')
sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nosuid|" /etc/fstab
fi
if mkdir -p "/var/tmp"; then
if mountpoint -q "/var/tmp"; then
mount -o remount --target "/var/tmp"
fi
fi
}
perform_remediation
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Restrict Programs from Dangerous Execution Patterns
[ref]groupThe recommendations in this section are designed to
ensure that the system's features to protect against potentially
dangerous program execution are activated.
These protections are applied at the system initialization or
kernel level, and defend against certain types of badly-configured
or compromised programs. |
contains 3 rules |
Disable Core Dumps
[ref]groupA core dump file is the memory image of an executable
program when it was terminated by the operating system due to
errant behavior. In most cases, only software developers
legitimately need to access these files. The core dump files may
also contain sensitive information, or unnecessarily occupy large
amounts of disk space.
Once a hard limit is set in /etc/security/limits.conf , or
to a file within the /etc/security/limits.d/ directory, a
user cannot increase that limit within his or her own session. If access
to core dumps is required, consider restricting them to only
certain users or groups. See the limits.conf man page for more
information.
The core dumps of setuid programs are further protected. The
sysctl variable fs.suid_dumpable controls whether
the kernel allows core dumps from these programs at all. The default
value of 0 is recommended. |
contains 2 rules |
Disable core dump backtraces
[ref]ruleThe ProcessSizeMax option in [Coredump] section
of /etc/systemd/coredump.conf
specifies the maximum size in bytes of a core which will be processed.
Core dumps exceeding this size may be stored, but the backtrace will not
be generated. Warning:
If the /etc/systemd/coredump.conf file
does not already contain the [Coredump] section,
the value will not be configured correctly. Rationale:A core dump includes a memory image taken at the time the operating system
terminates an application. The memory image could contain sensitive data
and is generally useful only for developers or system operators trying to
debug problems.
Enabling core dumps on production systems is not recommended,
however there may be overriding operational requirements to enable advanced
debuging. Permitting temporary enablement of core dumps during such situations
should be reviewed through local needs and policy. Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- NIST-800-53-CM-6
- PCI-DSS-Req-3.2
- PCI-DSSv4-3.3
- PCI-DSSv4-3.3.1
- PCI-DSSv4-3.3.1.1
- coredump_disable_backtraces
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Set 'ProcessSizeMax' to '0' in the [Coredump] section of '/etc/systemd/coredump.conf'
ini_file:
path: /etc/systemd/coredump.conf
section: Coredump
option: ProcessSizeMax
value: '0'
create: true
mode: 420
when: '"systemd" in ansible_facts.packages'
tags:
- NIST-800-53-CM-6
- PCI-DSS-Req-3.2
- PCI-DSSv4-3.3
- PCI-DSSv4-3.3.1
- PCI-DSSv4-3.3.1.1
- coredump_disable_backtraces
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}\n' 'systemd' 2>/dev/null | grep -q installed; then
found=false
# set value in all files if they contain section or key
for f in $(echo -n "/etc/systemd/coredump.conf"); do
if [ ! -e "$f" ]; then
continue
fi
# find key in section and change value
if grep -qzosP "[[:space:]]*\[Coredump\]([^\n\[]*\n+)+?[[:space:]]*ProcessSizeMax" "$f"; then
sed -i "s/ProcessSizeMax[^(\n)]*/ProcessSizeMax=0/" "$f"
found=true
# find section and add key = value to it
elif grep -qs "[[:space:]]*\[Coredump\]" "$f"; then
sed -i "/[[:space:]]*\[Coredump\]/a ProcessSizeMax=0" "$f"
found=true
fi
done
# if section not in any file, append section with key = value to FIRST file in files parameter
if ! $found ; then
file=$(echo "/etc/systemd/coredump.conf" | cut -f1 -d ' ')
mkdir -p "$(dirname "$file")"
echo -e "[Coredump]\nProcessSizeMax=0" >> "$file"
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Disable storing core dump
[ref]ruleThe Storage option in [Coredump] sectionof /etc/systemd/coredump.conf
can be set to none to disable storing core dumps permanently. Warning:
If the /etc/systemd/coredump.conf file
does not already contain the [Coredump] section,
the value will not be configured correctly. Rationale:A core dump includes a memory image taken at the time the operating system
terminates an application. The memory image could contain sensitive data
and is generally useful only for developers or system operators trying to
debug problems. Enabling core dumps on production systems is not recommended,
however there may be overriding operational requirements to enable advanced
debuging. Permitting temporary enablement of core dumps during such situations
should be reviewed through local needs and policy. Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- NIST-800-53-CM-6
- PCI-DSS-Req-3.2
- PCI-DSSv4-3.3
- PCI-DSSv4-3.3.1
- PCI-DSSv4-3.3.1.1
- coredump_disable_storage
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Set 'Storage' to 'none' in the [Coredump] section of '/etc/systemd/coredump.conf'
ini_file:
path: /etc/systemd/coredump.conf
section: Coredump
option: Storage
value: none
create: true
mode: 420
when: '"systemd" in ansible_facts.packages'
tags:
- NIST-800-53-CM-6
- PCI-DSS-Req-3.2
- PCI-DSSv4-3.3
- PCI-DSSv4-3.3.1
- PCI-DSSv4-3.3.1.1
- coredump_disable_storage
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}\n' 'systemd' 2>/dev/null | grep -q installed; then
found=false
# set value in all files if they contain section or key
for f in $(echo -n "/etc/systemd/coredump.conf"); do
if [ ! -e "$f" ]; then
continue
fi
# find key in section and change value
if grep -qzosP "[[:space:]]*\[Coredump\]([^\n\[]*\n+)+?[[:space:]]*Storage" "$f"; then
sed -i "s/Storage[^(\n)]*/Storage=none/" "$f"
found=true
# find section and add key = value to it
elif grep -qs "[[:space:]]*\[Coredump\]" "$f"; then
sed -i "/[[:space:]]*\[Coredump\]/a Storage=none" "$f"
found=true
fi
done
# if section not in any file, append section with key = value to FIRST file in files parameter
if ! $found ; then
file=$(echo "/etc/systemd/coredump.conf" | cut -f1 -d ' ')
mkdir -p "$(dirname "$file")"
echo -e "[Coredump]\nStorage=none" >> "$file"
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Enable ExecShield
[ref]groupExecShield describes kernel features that provide
protection against exploitation of memory corruption errors such as buffer
overflows. These features include random placement of the stack and other
memory regions, prevention of execution in memory that should only hold data,
and special handling of text buffers. These protections are enabled by default
on 32-bit systems and controlled through sysctl variables
kernel.exec-shield and kernel.randomize_va_space . On the latest
64-bit systems, kernel.exec-shield cannot be enabled or disabled with
sysctl . |
contains 1 rule |
Enable Randomized Layout of Virtual Address Space
[ref]ruleTo set the runtime status of the kernel.randomize_va_space kernel parameter, run the following command: $ sudo sysctl -w kernel.randomize_va_space=2
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d : kernel.randomize_va_space = 2 Rationale:Address space layout randomization (ASLR) makes it more difficult for an
attacker to predict the location of attack code they have introduced into a
process's address space during an attempt at exploitation. Additionally,
ASLR makes it more difficult for an attacker to know the location of
existing code in order to re-purpose it using return oriented programming
(ROP) techniques. References:
R9, 3.1.7, CCI-000366, CCI-002824, 164.308(a)(1)(ii)(D), 164.308(a)(3), 164.308(a)(4), 164.310(b), 164.310(c), 164.312(a), 164.312(e), CIP-002-5 R1.1, CIP-002-5 R1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 4.1, CIP-004-6 4.2, CIP-004-6 R2.2.3, CIP-004-6 R2.2.4, CIP-004-6 R2.3, CIP-004-6 R4, CIP-005-6 R1, CIP-005-6 R1.1, CIP-005-6 R1.2, CIP-007-3 R3, CIP-007-3 R3.1, CIP-007-3 R5.1, CIP-007-3 R5.1.2, CIP-007-3 R5.1.3, CIP-007-3 R5.2.1, CIP-007-3 R5.2.3, CIP-007-3 R8.4, CIP-009-6 R.1.1, CIP-009-6 R4, SC-30, SC-30(2), CM-6(a), Req-2.2.1, 3.3.1.1, 3.3.1, 3.3, SRG-OS-000433-GPOS-00193, SRG-OS-000480-GPOS-00227, SRG-APP-000450-CTR-001105 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | medium |
---|
Reboot: | true |
---|
Strategy: | disable |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- NIST-800-171-3.1.7
- NIST-800-53-CM-6(a)
- NIST-800-53-SC-30
- NIST-800-53-SC-30(2)
- PCI-DSS-Req-2.2.1
- PCI-DSSv4-3.3
- PCI-DSSv4-3.3.1
- PCI-DSSv4-3.3.1.1
- disable_strategy
- low_complexity
- medium_disruption
- medium_severity
- reboot_required
- sysctl_kernel_randomize_va_space
- name: List /etc/sysctl.d/*.conf files
find:
paths:
- /etc/sysctl.d/
- /run/sysctl.d/
- /usr/local/lib/sysctl.d/
- /usr/lib/sysctl.d/
contains: ^[\s]*kernel.randomize_va_space.*$
patterns: '*.conf'
file_type: any
register: find_sysctl_d
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-171-3.1.7
- NIST-800-53-CM-6(a)
- NIST-800-53-SC-30
- NIST-800-53-SC-30(2)
- PCI-DSS-Req-2.2.1
- PCI-DSSv4-3.3
- PCI-DSSv4-3.3.1
- PCI-DSSv4-3.3.1.1
- disable_strategy
- low_complexity
- medium_disruption
- medium_severity
- reboot_required
- sysctl_kernel_randomize_va_space
- name: Comment out any occurrences of kernel.randomize_va_space from config files
replace:
path: '{{ item.path }}'
regexp: ^[\s]*kernel.randomize_va_space
replace: '#kernel.randomize_va_space'
loop: '{{ find_sysctl_d.files }}'
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-171-3.1.7
- NIST-800-53-CM-6(a)
- NIST-800-53-SC-30
- NIST-800-53-SC-30(2)
- PCI-DSS-Req-2.2.1
- PCI-DSSv4-3.3
- PCI-DSSv4-3.3.1
- PCI-DSSv4-3.3.1.1
- disable_strategy
- low_complexity
- medium_disruption
- medium_severity
- reboot_required
- sysctl_kernel_randomize_va_space
- name: Ensure sysctl kernel.randomize_va_space is set to 2
sysctl:
name: kernel.randomize_va_space
value: '2'
sysctl_file: /etc/sysctl.conf
state: present
reload: true
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-171-3.1.7
- NIST-800-53-CM-6(a)
- NIST-800-53-SC-30
- NIST-800-53-SC-30(2)
- PCI-DSS-Req-2.2.1
- PCI-DSSv4-3.3
- PCI-DSSv4-3.3.1
- PCI-DSSv4-3.3.1.1
- disable_strategy
- low_complexity
- medium_disruption
- medium_severity
- reboot_required
- sysctl_kernel_randomize_va_space
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | medium |
---|
Reboot: | true |
---|
Strategy: | disable |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed; then
# Comment out any occurrences of kernel.randomize_va_space from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf /usr/lib/sysctl.d/*.conf; do
# skip systemd-sysctl symlink (/etc/sysctl.d/99-sysctl.conf -> /etc/sysctl.conf)
if [[ "$(readlink -f "$f")" == "/etc/sysctl.conf" ]]; then continue; fi
matching_list=$(grep -P '^(?!#).*[\s]*kernel.randomize_va_space.*$' $f | uniq )
if ! test -z "$matching_list"; then
while IFS= read -r entry; do
escaped_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
# comment out "kernel.randomize_va_space" matches to preserve user data
sed -i --follow-symlinks "s/^${escaped_entry}$/# &/g" $f
done <<< "$matching_list"
fi
done
#
# Set sysctl config file which to save the desired value
#
SYSCONFIG_FILE="/etc/sysctl.conf"
#
# Set runtime for kernel.randomize_va_space
#
/sbin/sysctl -q -n -w kernel.randomize_va_space="2"
#
# If kernel.randomize_va_space present in /etc/sysctl.conf, change value to "2"
# else, add "kernel.randomize_va_space = 2" to /etc/sysctl.conf
#
# Strip any search characters in the key arg so that the key can be replaced without
# adding any search characters to the config file.
stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^kernel.randomize_va_space")
# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "2"
# If the key exists, change it. Otherwise, add it to the config_file.
# We search for the key string followed by a word boundary (matched by \>),
# so if we search for 'setting', 'setting2' won't match.
if LC_ALL=C grep -q -m 1 -i -e "^kernel.randomize_va_space\\>" "${SYSCONFIG_FILE}"; then
escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
LC_ALL=C sed -i --follow-symlinks "s/^kernel.randomize_va_space\\>.*/$escaped_formatted_output/gi" "${SYSCONFIG_FILE}"
else
if [[ -s "${SYSCONFIG_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG_FILE}" || true)" ]]; then
LC_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG_FILE}"
fi
printf '%s\n' "$formatted_output" >> "${SYSCONFIG_FILE}"
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Services
[ref]groupThe best protection against vulnerable software is running less software. This section describes how to review
the software which Ubuntu 18.04 installs on a system and disable software which is not needed. It
then enumerates the software packages installed on a default Ubuntu 18.04 system and provides guidance about which
ones can be safely disabled.
Ubuntu 18.04 provides a convenient minimal install option that essentially installs the bare necessities for a functional
system. When building Ubuntu 18.04 systems, it is highly recommended to select the minimal packages and then build up
the system from there. |
contains 10 rules |
SSH Server
[ref]groupThe 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,
https://www.openssh.com.
Its server program is called sshd and provided by the RPM package
openssh-server . |
contains 10 rules |
Configure OpenSSH Server if Necessary
[ref]groupIf 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 10 rules |
Set SSH Client Alive Count Max to zero
[ref]ruleThe SSH server sends at most ClientAliveCountMax messages
during a SSH session and waits for a response from the SSH client.
The option ClientAliveInterval configures timeout after
each ClientAliveCountMax message. If the SSH server does not
receive a response from the client, then the connection is considered unresponsive
and terminated.
To ensure the SSH timeout occurs precisely when the
ClientAliveInterval is set, set the ClientAliveCountMax to
value of 0 in
/etc/ssh/sshd_config : Rationale:This ensures a user login will be terminated as soon as the ClientAliveInterval
is reached. References:
1, 12, 13, 14, 15, 16, 18, 3, 5, 7, 8, 5.5.6, APO13.01, BAI03.01, BAI03.02, BAI03.03, DSS01.03, DSS03.05, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 3.1.11, CCI-000879, CCI-001133, CCI-002361, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 6.2, A.12.4.1, A.12.4.3, A.14.1.1, A.14.2.1, A.14.2.5, A.18.1.4, A.6.1.2, A.6.1.5, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, CIP-004-6 R2.2.3, CIP-007-3 R5.1, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, AC-2(5), AC-12, AC-17(a), SC-10, CM-6(a), DE.CM-1, DE.CM-3, PR.AC-1, PR.AC-4, PR.AC-6, PR.AC-7, PR.IP-2, Req-8.1.8, SRG-OS-000126-GPOS-00066, SRG-OS-000163-GPOS-00072, SRG-OS-000279-GPOS-00109 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- CJIS-5.5.6
- NIST-800-171-3.1.11
- NIST-800-53-AC-12
- NIST-800-53-AC-17(a)
- NIST-800-53-AC-2(5)
- NIST-800-53-CM-6(a)
- NIST-800-53-SC-10
- PCI-DSS-Req-8.1.8
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- sshd_set_keepalive_0
- name: Set SSH Client Alive Count Max to zero
block:
- name: Check for duplicate values
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*ClientAliveCountMax\s+
state: absent
check_mode: true
changed_when: false
register: dupes
- name: Deduplicate values from /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*ClientAliveCountMax\s+
state: absent
when: dupes.found is defined and dupes.found > 1
- name: Insert correct line to /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*ClientAliveCountMax\s+
line: ClientAliveCountMax 0
state: present
insertbefore: BOF
validate: /usr/sbin/sshd -t -f %s
when: '"kernel" in ansible_facts.packages'
tags:
- CJIS-5.5.6
- NIST-800-171-3.1.11
- NIST-800-53-AC-12
- NIST-800-53-AC-17(a)
- NIST-800-53-AC-2(5)
- NIST-800-53-CM-6(a)
- NIST-800-53-SC-10
- PCI-DSS-Req-8.1.8
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- sshd_set_keepalive_0
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed; then
if [ -e "/etc/ssh/sshd_config" ] ; then
LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config"
else
touch "/etc/ssh/sshd_config"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/ssh/sshd_config"
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert at the beginning of the file
printf '%s\n' "ClientAliveCountMax 0" > "/etc/ssh/sshd_config"
cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Set SSH Client Alive Interval
[ref]ruleSSH allows administrators to set a network responsiveness timeout interval.
After this interval has passed, the unresponsive client will be automatically logged out.
To set this timeout interval, edit the following line in /etc/ssh/sshd_config as
follows:
ClientAliveInterval 300
The timeout interval is given in seconds. For example, have a timeout
of 10 minutes, set interval to 600.
If a shorter timeout has already been set for the login shell, that value will
preempt any SSH setting made in /etc/ssh/sshd_config . Keep in mind that
some processes may stop SSH from correctly detecting that the user is idle.Warning:
SSH disconnecting unresponsive clients will not have desired effect without also
configuring ClientAliveCountMax in the SSH service configuration. Warning:
Following conditions may prevent the SSH session to time out:
- Remote processes on the remote machine generates output. As the output has to be transferred over the network to the client, the timeout is reset every time such transfer happens.
- Any
scp or sftp activity by the same user to the host resets the timeout.
Rationale:Terminating an idle ssh session within a short time period reduces the window of
opportunity for unauthorized personnel to take control of a management session
enabled on the console or console port that has been let unattended. References:
1, 12, 13, 14, 15, 16, 18, 3, 5, 7, 8, 5.5.6, APO13.01, BAI03.01, BAI03.02, BAI03.03, DSS01.03, DSS03.05, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 3.1.11, CCI-001133, CCI-002361, CCI-002891, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 6.2, A.12.4.1, A.12.4.3, A.14.1.1, A.14.2.1, A.14.2.5, A.18.1.4, A.6.1.2, A.6.1.5, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, CIP-004-6 R2.2.3, CIP-007-3 R5.1, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, CM-6(a), AC-17(a), AC-2(5), AC-12, AC-17(a), SC-10, CM-6(a), DE.CM-1, DE.CM-3, PR.AC-1, PR.AC-4, PR.AC-6, PR.AC-7, PR.IP-2, Req-8.1.8, 8.2.8, 8.2, SRG-OS-000126-GPOS-00066, SRG-OS-000163-GPOS-00072, SRG-OS-000279-GPOS-00109, SRG-OS-000395-GPOS-00175 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- CJIS-5.5.6
- NIST-800-171-3.1.11
- NIST-800-53-AC-12
- NIST-800-53-AC-17(a)
- NIST-800-53-AC-17(a)
- NIST-800-53-AC-2(5)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-SC-10
- PCI-DSS-Req-8.1.8
- PCI-DSSv4-8.2
- PCI-DSSv4-8.2.8
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- sshd_set_idle_timeout
- name: XCCDF Value sshd_idle_timeout_value # promote to variable
set_fact:
sshd_idle_timeout_value: !!str 300
tags:
- always
- name: Set SSH Client Alive Interval
block:
- name: Check for duplicate values
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*ClientAliveInterval\s+
state: absent
check_mode: true
changed_when: false
register: dupes
- name: Deduplicate values from /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*ClientAliveInterval\s+
state: absent
when: dupes.found is defined and dupes.found > 1
- name: Insert correct line to /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*ClientAliveInterval\s+
line: ClientAliveInterval {{ sshd_idle_timeout_value }}
state: present
insertbefore: BOF
validate: /usr/sbin/sshd -t -f %s
when: '"kernel" in ansible_facts.packages'
tags:
- CJIS-5.5.6
- NIST-800-171-3.1.11
- NIST-800-53-AC-12
- NIST-800-53-AC-17(a)
- NIST-800-53-AC-17(a)
- NIST-800-53-AC-2(5)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-SC-10
- PCI-DSS-Req-8.1.8
- PCI-DSSv4-8.2
- PCI-DSSv4-8.2.8
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- sshd_set_idle_timeout
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed; then
sshd_idle_timeout_value='300'
if [ -e "/etc/ssh/sshd_config" ] ; then
LC_ALL=C sed -i "/^\s*ClientAliveInterval\s\+/Id" "/etc/ssh/sshd_config"
else
touch "/etc/ssh/sshd_config"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/ssh/sshd_config"
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert at the beginning of the file
printf '%s\n' "ClientAliveInterval $sshd_idle_timeout_value" > "/etc/ssh/sshd_config"
cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Disable Host-Based Authentication
[ref]ruleSSH's cryptographic host-based authentication is
more secure than .rhosts authentication. However, it is
not recommended that hosts unilaterally trust one another, even
within an organization.
The default SSH configuration disables host-based authentication. The appropriate
configuration is used if no value is set for HostbasedAuthentication .
To explicitly disable host-based authentication, add or correct the
following line in
/etc/ssh/sshd_config :
HostbasedAuthentication no Rationale:SSH trust relationships mean a compromise on one host
can allow an attacker to move trivially to other hosts. References:
11, 12, 14, 15, 16, 18, 3, 5, 9, 5.5.6, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.03, DSS06.06, 3.1.12, CCI-000366, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.6.1.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.2.3, CIP-004-6 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.2, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, AC-3, AC-17(a), CM-7(a), CM-7(b), CM-6(a), PR.AC-4, PR.AC-6, PR.IP-1, PR.PT-3, FIA_UAU.1, 8.3.1, 8.3, SRG-OS-000480-GPOS-00229 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- CJIS-5.5.6
- NIST-800-171-3.1.12
- NIST-800-53-AC-17(a)
- NIST-800-53-AC-3
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.1
- disable_host_auth
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Disable Host-Based Authentication
block:
- name: Check for duplicate values
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*HostbasedAuthentication\s+
state: absent
check_mode: true
changed_when: false
register: dupes
- name: Deduplicate values from /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*HostbasedAuthentication\s+
state: absent
when: dupes.found is defined and dupes.found > 1
- name: Insert correct line to /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*HostbasedAuthentication\s+
line: HostbasedAuthentication no
state: present
insertbefore: BOF
validate: /usr/sbin/sshd -t -f %s
when: '"kernel" in ansible_facts.packages'
tags:
- CJIS-5.5.6
- NIST-800-171-3.1.12
- NIST-800-53-AC-17(a)
- NIST-800-53-AC-3
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.1
- disable_host_auth
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed; then
if [ -e "/etc/ssh/sshd_config" ] ; then
LC_ALL=C sed -i "/^\s*HostbasedAuthentication\s\+/Id" "/etc/ssh/sshd_config"
else
touch "/etc/ssh/sshd_config"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/ssh/sshd_config"
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert at the beginning of the file
printf '%s\n' "HostbasedAuthentication no" > "/etc/ssh/sshd_config"
cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Disable SSH Access via Empty Passwords
[ref]ruleDisallow SSH login with empty passwords.
The default SSH configuration disables logins with empty passwords. The appropriate
configuration is used if no value is set for PermitEmptyPasswords .
To explicitly disallow SSH login from accounts with empty passwords,
add or correct the following line in
/etc/ssh/sshd_config :
PermitEmptyPasswords no
Any accounts with empty passwords should be disabled immediately, and PAM configuration
should prevent users from being able to assign themselves empty passwords.Rationale:Configuring this setting for the SSH daemon provides additional assurance
that remote login via SSH will require a password, even in the event of
misconfiguration elsewhere. References:
11, 12, 13, 14, 15, 16, 18, 3, 5, 9, 5.5.6, APO01.06, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.03, DSS06.06, 3.1.1, 3.1.5, CCI-000766, CCI-000366, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 5.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.2, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.1, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, AC-17(a), CM-7(a), CM-7(b), CM-6(a), PR.AC-4, PR.AC-6, PR.DS-5, PR.IP-1, PR.PT-3, FIA_UAU.1, Req-2.2.4, 2.2.6, 2.2, SRG-OS-000106-GPOS-00053, SRG-OS-000480-GPOS-00229, SRG-OS-000480-GPOS-00227 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- CJIS-5.5.6
- NIST-800-171-3.1.1
- NIST-800-171-3.1.5
- NIST-800-53-AC-17(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- PCI-DSS-Req-2.2.4
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- high_severity
- low_complexity
- low_disruption
- no_reboot_needed
- restrict_strategy
- sshd_disable_empty_passwords
- name: Disable SSH Access via Empty Passwords
block:
- name: Check for duplicate values
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*PermitEmptyPasswords\s+
state: absent
check_mode: true
changed_when: false
register: dupes
- name: Deduplicate values from /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*PermitEmptyPasswords\s+
state: absent
when: dupes.found is defined and dupes.found > 1
- name: Insert correct line to /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*PermitEmptyPasswords\s+
line: PermitEmptyPasswords no
state: present
insertbefore: BOF
validate: /usr/sbin/sshd -t -f %s
when: '"kernel" in ansible_facts.packages'
tags:
- CJIS-5.5.6
- NIST-800-171-3.1.1
- NIST-800-171-3.1.5
- NIST-800-53-AC-17(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- PCI-DSS-Req-2.2.4
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- high_severity
- low_complexity
- low_disruption
- no_reboot_needed
- restrict_strategy
- sshd_disable_empty_passwords
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed; then
if [ -e "/etc/ssh/sshd_config" ] ; then
LC_ALL=C sed -i "/^\s*PermitEmptyPasswords\s\+/Id" "/etc/ssh/sshd_config"
else
touch "/etc/ssh/sshd_config"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/ssh/sshd_config"
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert at the beginning of the file
printf '%s\n' "PermitEmptyPasswords no" > "/etc/ssh/sshd_config"
cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Disable SSH Support for .rhosts Files
[ref]ruleSSH can emulate the behavior of the obsolete rsh
command in allowing users to enable insecure access to their
accounts via .rhosts files.
The default SSH configuration disables support for .rhosts . The appropriate
configuration is used if no value is set for IgnoreRhosts .
To explicitly disable support for .rhosts files, add or correct the following line in
/etc/ssh/sshd_config :
IgnoreRhosts yes Rationale:SSH trust relationships mean a compromise on one host
can allow an attacker to move trivially to other hosts. References:
11, 12, 14, 15, 16, 18, 3, 5, 9, 5.5.6, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.03, DSS06.06, 3.1.12, CCI-000366, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.6.1.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, AC-17(a), CM-7(a), CM-7(b), CM-6(a), PR.AC-4, PR.AC-6, PR.IP-1, PR.PT-3, 2.2.6, 2.2, SRG-OS-000480-GPOS-00227 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- CJIS-5.5.6
- NIST-800-171-3.1.12
- NIST-800-53-AC-17(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- sshd_disable_rhosts
- name: Disable SSH Support for .rhosts Files
block:
- name: Check for duplicate values
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*IgnoreRhosts\s+
state: absent
check_mode: true
changed_when: false
register: dupes
- name: Deduplicate values from /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*IgnoreRhosts\s+
state: absent
when: dupes.found is defined and dupes.found > 1
- name: Insert correct line to /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*IgnoreRhosts\s+
line: IgnoreRhosts yes
state: present
insertbefore: BOF
validate: /usr/sbin/sshd -t -f %s
when: '"kernel" in ansible_facts.packages'
tags:
- CJIS-5.5.6
- NIST-800-171-3.1.12
- NIST-800-53-AC-17(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- sshd_disable_rhosts
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed; then
if [ -e "/etc/ssh/sshd_config" ] ; then
LC_ALL=C sed -i "/^\s*IgnoreRhosts\s\+/Id" "/etc/ssh/sshd_config"
else
touch "/etc/ssh/sshd_config"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/ssh/sshd_config"
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert at the beginning of the file
printf '%s\n' "IgnoreRhosts yes" > "/etc/ssh/sshd_config"
cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Disable SSH Root Login
[ref]ruleThe root user should never be allowed to login to a
system directly over a network.
To disable root login via SSH, add or correct the following line in
/etc/ssh/sshd_config :
PermitRootLogin no Rationale:Even though the communications channel may be encrypted, an additional layer of
security is gained by extending the policy of not logging directly on as root.
In addition, logging in with a user-specific account provides individual
accountability of actions performed on the system and also helps to minimize
direct attack attempts on root's password. References:
R33, 1, 11, 12, 13, 14, 15, 16, 18, 3, 5, 5.5.6, APO01.06, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.02, DSS06.03, DSS06.06, DSS06.10, 3.1.1, 3.1.5, CCI-000366, CCI-004045, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.18.1.4, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.2.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, AC-6(2), AC-17(a), IA-2, IA-2(5), CM-7(a), CM-7(b), CM-6(a), PR.AC-1, PR.AC-4, PR.AC-6, PR.AC-7, PR.DS-5, PR.PT-3, FAU_GEN.1, Req-2.2.4, 2.2.6, 2.2, SRG-OS-000109-GPOS-00056, SRG-OS-000480-GPOS-00227, SRG-APP-000148-CTR-000335, SRG-APP-000190-CTR-000500 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- CJIS-5.5.6
- NIST-800-171-3.1.1
- NIST-800-171-3.1.5
- NIST-800-53-AC-17(a)
- NIST-800-53-AC-6(2)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- NIST-800-53-IA-2
- NIST-800-53-IA-2(5)
- PCI-DSS-Req-2.2.4
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- sshd_disable_root_login
- name: Disable SSH Root Login
block:
- name: Check for duplicate values
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*PermitRootLogin\s+
state: absent
check_mode: true
changed_when: false
register: dupes
- name: Deduplicate values from /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*PermitRootLogin\s+
state: absent
when: dupes.found is defined and dupes.found > 1
- name: Insert correct line to /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*PermitRootLogin\s+
line: PermitRootLogin no
state: present
insertbefore: BOF
validate: /usr/sbin/sshd -t -f %s
when: '"kernel" in ansible_facts.packages'
tags:
- CJIS-5.5.6
- NIST-800-171-3.1.1
- NIST-800-171-3.1.5
- NIST-800-53-AC-17(a)
- NIST-800-53-AC-6(2)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- NIST-800-53-IA-2
- NIST-800-53-IA-2(5)
- PCI-DSS-Req-2.2.4
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- sshd_disable_root_login
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed; then
if [ -e "/etc/ssh/sshd_config" ] ; then
LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config"
else
touch "/etc/ssh/sshd_config"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/ssh/sshd_config"
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert at the beginning of the file
printf '%s\n' "PermitRootLogin no" > "/etc/ssh/sshd_config"
cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Do Not Allow SSH Environment Options
[ref]ruleEnsure that users are not able to override environment variables of the SSH daemon.
The default SSH configuration disables environment processing. The appropriate
configuration is used if no value is set for PermitUserEnvironment .
To explicitly disable Environment options, add or correct the following
/etc/ssh/sshd_config :
PermitUserEnvironment no Rationale:SSH environment options potentially allow users to bypass
access restriction in some configurations. References:
11, 3, 9, 5.5.6, BAI10.01, BAI10.02, BAI10.03, BAI10.05, 3.1.12, CCI-000366, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.4.3.2, 4.3.4.3.3, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, AC-17(a), CM-7(a), CM-7(b), CM-6(a), PR.IP-1, Req-2.2.4, 2.2.6, 2.2, SRG-OS-000480-GPOS-00229 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- CJIS-5.5.6
- NIST-800-171-3.1.12
- NIST-800-53-AC-17(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- PCI-DSS-Req-2.2.4
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- sshd_do_not_permit_user_env
- name: Do Not Allow SSH Environment Options
block:
- name: Check for duplicate values
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*PermitUserEnvironment\s+
state: absent
check_mode: true
changed_when: false
register: dupes
- name: Deduplicate values from /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*PermitUserEnvironment\s+
state: absent
when: dupes.found is defined and dupes.found > 1
- name: Insert correct line to /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*PermitUserEnvironment\s+
line: PermitUserEnvironment no
state: present
insertbefore: BOF
validate: /usr/sbin/sshd -t -f %s
when: '"kernel" in ansible_facts.packages'
tags:
- CJIS-5.5.6
- NIST-800-171-3.1.12
- NIST-800-53-AC-17(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- PCI-DSS-Req-2.2.4
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- sshd_do_not_permit_user_env
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed; then
if [ -e "/etc/ssh/sshd_config" ] ; then
LC_ALL=C sed -i "/^\s*PermitUserEnvironment\s\+/Id" "/etc/ssh/sshd_config"
else
touch "/etc/ssh/sshd_config"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/ssh/sshd_config"
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert at the beginning of the file
printf '%s\n' "PermitUserEnvironment no" > "/etc/ssh/sshd_config"
cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Enable SSH Warning Banner
[ref]ruleTo enable the warning banner and ensure it is consistent
across the system, add or correct the following line in
/etc/ssh/sshd_config :
Banner /etc/issue
Another section contains information on how to create an
appropriate system-wide warning banner.Rationale:The warning message reinforces policy awareness during the logon process and
facilitates possible legal action against attackers. Alternatively, systems
whose ownership should not be obvious should ensure usage of a banner that does
not provide easy attribution. References:
1, 12, 15, 16, 5.5.6, DSS05.04, DSS05.10, DSS06.10, 3.1.9, CCI-001387, CCI-001384, CCI-000048, CCI-001386, CCI-001388, CCI-001385, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, AC-8(a), AC-8(c), AC-17(a), CM-6(a), PR.AC-7, FTA_TAB.1, Req-2.2.4, SRG-OS-000023-GPOS-00006, SRG-OS-000228-GPOS-00088 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- CJIS-5.5.6
- NIST-800-171-3.1.9
- NIST-800-53-AC-17(a)
- NIST-800-53-AC-8(a)
- NIST-800-53-AC-8(c)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-2.2.4
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- sshd_enable_warning_banner
- name: Enable SSH Warning Banner
block:
- name: Check for duplicate values
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*Banner\s+
state: absent
check_mode: true
changed_when: false
register: dupes
- name: Deduplicate values from /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*Banner\s+
state: absent
when: dupes.found is defined and dupes.found > 1
- name: Insert correct line to /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*Banner\s+
line: Banner /etc/issue
state: present
insertbefore: BOF
validate: /usr/sbin/sshd -t -f %s
when: '"kernel" in ansible_facts.packages'
tags:
- CJIS-5.5.6
- NIST-800-171-3.1.9
- NIST-800-53-AC-17(a)
- NIST-800-53-AC-8(a)
- NIST-800-53-AC-8(c)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-2.2.4
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- sshd_enable_warning_banner
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed; then
if [ -e "/etc/ssh/sshd_config" ] ; then
LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config"
else
touch "/etc/ssh/sshd_config"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/ssh/sshd_config"
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert at the beginning of the file
printf '%s\n' "Banner /etc/issue" > "/etc/ssh/sshd_config"
cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Set LogLevel to INFO
[ref]ruleThe INFO parameter specifices that record login and logout activity will be logged.
The default SSH configuration sets the log level to INFO. The appropriate
configuration is used if no value is set for LogLevel .
To explicitly specify the log level in SSH, add or correct the following line in
/etc/ssh/sshd_config :
LogLevel INFO Rationale:SSH provides several logging levels with varying amounts of verbosity. DEBUG is specifically
not recommended other than strictly for debugging SSH communications since it provides
so much data that it is difficult to identify important security information. INFO level is the
basic level that only records login activity of SSH users. In many situations, such as Incident
Response, it is important to determine when a particular user was active on a system. The
logout record can eliminate those users who disconnected, which helps narrow the field. Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- NIST-800-53-AC-17(a)
- NIST-800-53-CM-6(a)
- low_complexity
- low_disruption
- low_severity
- no_reboot_needed
- restrict_strategy
- sshd_set_loglevel_info
- name: Set LogLevel to INFO
block:
- name: Check for duplicate values
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*LogLevel\s+
state: absent
check_mode: true
changed_when: false
register: dupes
- name: Deduplicate values from /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*LogLevel\s+
state: absent
when: dupes.found is defined and dupes.found > 1
- name: Insert correct line to /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*LogLevel\s+
line: LogLevel INFO
state: present
insertbefore: BOF
validate: /usr/sbin/sshd -t -f %s
when: '"kernel" in ansible_facts.packages'
tags:
- NIST-800-53-AC-17(a)
- NIST-800-53-CM-6(a)
- low_complexity
- low_disruption
- low_severity
- no_reboot_needed
- restrict_strategy
- sshd_set_loglevel_info
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed; then
if [ -e "/etc/ssh/sshd_config" ] ; then
LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config"
else
touch "/etc/ssh/sshd_config"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/ssh/sshd_config"
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert at the beginning of the file
printf '%s\n' "LogLevel INFO" > "/etc/ssh/sshd_config"
cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Set SSH authentication attempt limit
[ref]ruleThe MaxAuthTries parameter specifies the maximum number of authentication attempts
permitted per connection. Once the number of failures reaches half this value, additional failures are logged.
to set MaxAUthTries edit /etc/ssh/sshd_config as follows:
MaxAuthTries 4 Rationale:Setting the MaxAuthTries parameter to a low number will minimize the risk of successful
brute force attacks to the SSH server. References:
0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, 2.2.6, 2.2 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- sshd_set_max_auth_tries
- name: XCCDF Value sshd_max_auth_tries_value # promote to variable
set_fact:
sshd_max_auth_tries_value: !!str 4
tags:
- always
- name: Set SSH authentication attempt limit
block:
- name: Check for duplicate values
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*MaxAuthTries\s+
state: absent
check_mode: true
changed_when: false
register: dupes
- name: Deduplicate values from /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*MaxAuthTries\s+
state: absent
when: dupes.found is defined and dupes.found > 1
- name: Insert correct line to /etc/ssh/sshd_config
lineinfile:
path: /etc/ssh/sshd_config
create: true
regexp: (?i)(?i)^\s*MaxAuthTries\s+
line: MaxAuthTries {{ sshd_max_auth_tries_value }}
state: present
insertbefore: BOF
validate: /usr/sbin/sshd -t -f %s
when: '"kernel" in ansible_facts.packages'
tags:
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- sshd_set_max_auth_tries
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed; then
sshd_max_auth_tries_value='4'
if [ -e "/etc/ssh/sshd_config" ] ; then
LC_ALL=C sed -i "/^\s*MaxAuthTries\s\+/Id" "/etc/ssh/sshd_config"
else
touch "/etc/ssh/sshd_config"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/ssh/sshd_config"
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert at the beginning of the file
printf '%s\n' "MaxAuthTries $sshd_max_auth_tries_value" > "/etc/ssh/sshd_config"
cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
System Accounting with auditd
[ref]groupThe 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 Red Hat Enterprise Linux 7 Documentation available at
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html-single/selinux_users_and_administrators_guide/index#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 11 rules |
Configure auditd Rules for Comprehensive Auditing
[ref]groupThe 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 5 rules |
Records Events that Modify Date and Time Information
[ref]groupArbitrary changes to the system time can be used to obfuscate
nefarious activities in log files, as well as to confuse network services that
are highly dependent upon an accurate system time. All changes to the system
time should be audited. |
contains 1 rule |
Record attempts to alter time through adjtimex
[ref]ruleIf the auditd daemon is configured to use the
augenrules program to read audit rules during daemon startup (the
default), add the following line to a file with suffix .rules in the
directory /etc/audit/rules.d :
-a always,exit -F arch=b32 -S adjtimex -F key=audit_time_rules
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S adjtimex -F key=audit_time_rules
If the auditd daemon is configured to use the auditctl
utility to read audit rules during daemon startup, add the following line to
/etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S adjtimex -F key=audit_time_rules
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S adjtimex -F key=audit_time_rules
The -k option allows for the specification of a key in string form that can be
used for better reporting capability through ausearch and aureport. Multiple
system calls can be defined on the same line to save space if desired, but is
not required. See an example of multiple combined syscalls:
-a always,exit -F arch=b64 -S adjtimex,settimeofday -F key=audit_time_rules Rationale:Arbitrary changes to the system time can be used to obfuscate
nefarious activities in log files, as well as to confuse network services that
are highly dependent upon an accurate system time (such as sshd). All changes
to the system time should be audited. References:
R73, 1, 11, 12, 13, 14, 15, 16, 19, 2, 3, 4, 5, 6, 7, 8, 9, 5.4.1.1, APO10.01, APO10.03, APO10.04, APO10.05, APO11.04, APO12.06, APO13.01, BAI03.05, BAI08.02, DSS01.03, DSS01.04, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS03.05, DSS05.02, DSS05.03, DSS05.04, DSS05.05, DSS05.07, MEA01.01, MEA01.02, MEA01.03, MEA01.04, MEA01.05, MEA02.01, 3.1.7, CCI-001487, CCI-000169, 164.308(a)(1)(ii)(D), 164.308(a)(3)(ii)(A), 164.308(a)(5)(ii)(C), 164.312(a)(2)(i), 164.312(b), 164.312(d), 164.312(e), 4.2.3.10, 4.3.2.6.7, 4.3.3.3.9, 4.3.3.5.8, 4.3.3.6.6, 4.3.4.4.7, 4.3.4.5.6, 4.3.4.5.7, 4.3.4.5.8, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 1.13, SR 2.10, SR 2.11, SR 2.12, SR 2.6, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.1, SR 6.2, SR 7.1, SR 7.6, A.11.2.6, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.7, A.15.2.1, A.15.2.2, A.16.1.4, A.16.1.5, A.16.1.7, A.6.2.1, A.6.2.2, AU-2(d), AU-12(c), AC-6(9), CM-6(a), DE.AE-3, DE.AE-5, DE.CM-1, DE.CM-3, DE.CM-7, ID.SC-4, PR.AC-3, PR.PT-1, PR.PT-4, RS.AN-1, RS.AN-4, Req-10.4.2.b, 10.6.3, 10.6 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.1.7
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-2(d)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-10.4.2.b
- PCI-DSSv4-10.6
- PCI-DSSv4-10.6.3
- audit_rules_time_adjtimex
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Set architecture for audit tasks
set_fact:
audit_arch: b64
when:
- '"auditd" in ansible_facts.packages'
- '"kernel" in ansible_facts.packages'
- ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture
== "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64"
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.1.7
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-2(d)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-10.4.2.b
- PCI-DSSv4-10.6
- PCI-DSSv4-10.6.3
- audit_rules_time_adjtimex
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Perform remediation of Audit rules for adjtimex for 32bit platform
block:
- name: Declare list of syscalls
set_fact:
syscalls:
- adjtimex
syscall_grouping:
- adjtimex
- settimeofday
- stime
- name: Check existence of adjtimex in /etc/audit/rules.d/
find:
paths: /etc/audit/rules.d
contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S
|,)\w+)* (-k\s+|-F\s+key=)\S+\s*$
patterns: '*.rules'
register: find_command
loop: '{{ (syscall_grouping + syscalls) | unique }}'
- name: Reset syscalls found per file
set_fact:
syscalls_per_file: {}
found_paths_dict: {}
- name: Declare syscalls found per file
set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path
:[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}"
loop: '{{ find_command.results | selectattr(''matched'') | list }}'
- name: Declare files where syscalls were found
set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten
| map(attribute='path') | list }}"
- name: Count occurrences of syscalls in paths
set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item,
0) }) }}"
loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'')
| list }}'
- name: Get path with most syscalls
set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value')
| last).key }}"
when: found_paths | length >= 1
- name: No file with syscall found, set path to /etc/audit/rules.d/audit_time_rules.rules
set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules"
when: found_paths | length == 0
- name: Declare found syscalls
set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item')
| list }}"
- name: Declare missing syscalls
set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}"
- name: Replace the audit rule in {{ audit_file }}
lineinfile:
path: '{{ audit_file }}'
regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file]
| join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+)
line: \1\2\3{{ missing_syscalls | join("\3") }}\4
backrefs: true
state: present
when: syscalls_found | length > 0 and missing_syscalls | length > 0
- name: Add the audit rule to {{ audit_file }}
lineinfile:
path: '{{ audit_file }}'
line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules
create: true
mode: o-rwx
state: present
when: syscalls_found | length == 0
- name: Declare list of syscalls
set_fact:
syscalls:
- adjtimex
syscall_grouping:
- adjtimex
- settimeofday
- stime
- name: Check existence of adjtimex in /etc/audit/audit.rules
find:
paths: /etc/audit
contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S
|,)\w+)* (-k\s+|-F\s+key=)\S+\s*$
patterns: audit.rules
register: find_command
loop: '{{ (syscall_grouping + syscalls) | unique }}'
- name: Set path to /etc/audit/audit.rules
set_fact: audit_file="/etc/audit/audit.rules"
- name: Declare found syscalls
set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item')
| list }}"
- name: Declare missing syscalls
set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}"
- name: Replace the audit rule in {{ audit_file }}
lineinfile:
path: '{{ audit_file }}'
regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found |
join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+)
line: \1\2\3{{ missing_syscalls | join("\3") }}\4
backrefs: true
state: present
when: syscalls_found | length > 0 and missing_syscalls | length > 0
- name: Add the audit rule to {{ audit_file }}
lineinfile:
path: '{{ audit_file }}'
line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules
create: true
mode: o-rwx
state: present
when: syscalls_found | length == 0
when:
- '"auditd" in ansible_facts.packages'
- '"kernel" in ansible_facts.packages'
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.1.7
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-2(d)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-10.4.2.b
- PCI-DSSv4-10.6
- PCI-DSSv4-10.6.3
- audit_rules_time_adjtimex
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Perform remediation of Audit rules for adjtimex for 64bit platform
block:
- name: Declare list of syscalls
set_fact:
syscalls:
- adjtimex
syscall_grouping:
- adjtimex
- settimeofday
- name: Check existence of adjtimex in /etc/audit/rules.d/
find:
paths: /etc/audit/rules.d
contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S
|,)\w+)* (-k\s+|-F\s+key=)\S+\s*$
patterns: '*.rules'
register: find_command
loop: '{{ (syscall_grouping + syscalls) | unique }}'
- name: Reset syscalls found per file
set_fact:
syscalls_per_file: {}
found_paths_dict: {}
- name: Declare syscalls found per file
set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path
:[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}"
loop: '{{ find_command.results | selectattr(''matched'') | list }}'
- name: Declare files where syscalls were found
set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten
| map(attribute='path') | list }}"
- name: Count occurrences of syscalls in paths
set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item,
0) }) }}"
loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'')
| list }}'
- name: Get path with most syscalls
set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value')
| last).key }}"
when: found_paths | length >= 1
- name: No file with syscall found, set path to /etc/audit/rules.d/audit_time_rules.rules
set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules"
when: found_paths | length == 0
- name: Declare found syscalls
set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item')
| list }}"
- name: Declare missing syscalls
set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}"
- name: Replace the audit rule in {{ audit_file }}
lineinfile:
path: '{{ audit_file }}'
regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file]
| join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+)
line: \1\2\3{{ missing_syscalls | join("\3") }}\4
backrefs: true
state: present
when: syscalls_found | length > 0 and missing_syscalls | length > 0
- name: Add the audit rule to {{ audit_file }}
lineinfile:
path: '{{ audit_file }}'
line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_time_rules
create: true
mode: o-rwx
state: present
when: syscalls_found | length == 0
- name: Declare list of syscalls
set_fact:
syscalls:
- adjtimex
syscall_grouping:
- adjtimex
- settimeofday
- stime
- name: Check existence of adjtimex in /etc/audit/audit.rules
find:
paths: /etc/audit
contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S
|,)\w+)* (-k\s+|-F\s+key=)\S+\s*$
patterns: audit.rules
register: find_command
loop: '{{ (syscall_grouping + syscalls) | unique }}'
- name: Set path to /etc/audit/audit.rules
set_fact: audit_file="/etc/audit/audit.rules"
- name: Declare found syscalls
set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item')
| list }}"
- name: Declare missing syscalls
set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}"
- name: Replace the audit rule in {{ audit_file }}
lineinfile:
path: '{{ audit_file }}'
regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found |
join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+)
line: \1\2\3{{ missing_syscalls | join("\3") }}\4
backrefs: true
state: present
when: syscalls_found | length > 0 and missing_syscalls | length > 0
- name: Add the audit rule to {{ audit_file }}
lineinfile:
path: '{{ audit_file }}'
line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_time_rules
create: true
mode: o-rwx
state: present
when: syscalls_found | length == 0
when:
- '"auditd" in ansible_facts.packages'
- '"kernel" in ansible_facts.packages'
- audit_arch == "b64"
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.1.7
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-2(d)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-10.4.2.b
- PCI-DSSv4-10.6
- PCI-DSSv4-10.6.3
- audit_rules_time_adjtimex
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed && dpkg-query --show --showformat='${db:Status-Status}\n' 'auditd' 2>/dev/null | grep -q installed; then
# Retrieve hardware architecture of the underlying system
[ "$(getconf LONG_BIT)" = "32" ] && RULE_ARCHS=("b32") || RULE_ARCHS=("b32" "b64")
for ARCH in "${RULE_ARCHS[@]}"
do
# Create expected audit group and audit rule form for particular system call & architecture
if [ ${ARCH} = "b32" ]
then
ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH"
# stime system call is known at 32-bit arch (see e.g "$ ausyscall i386 stime" 's output)
# so append it to the list of time group system calls to be audited
SYSCALL="adjtimex settimeofday stime"
SYSCALL_GROUPING="adjtimex settimeofday stime"
elif [ ${ARCH} = "b64" ]
then
ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH"
# stime system call isn't known at 64-bit arch (see "$ ausyscall x86_64 stime" 's output)
# therefore don't add it to the list of time group system calls to be audited
SYSCALL="adjtimex settimeofday"
SYSCALL_GROUPING="adjtimex settimeofday"
fi
OTHER_FILTERS=""
AUID_FILTERS=""
KEY="audit_time_rules"
# Perform the remediation for both possible tools: 'auditctl' and 'augenrules'
unset syscall_a
unset syscall_grouping
unset syscall_string
unset syscall
unset file_to_edit
unset rule_to_edit
unset rule_syscalls_to_edit
unset other_string
unset auid_string
unset full_rule
# Load macro arguments into arrays
read -a syscall_a <<< $SYSCALL
read -a syscall_grouping <<< $SYSCALL_GROUPING
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
#
files_to_inspect=()
# If audit tool is 'augenrules', then check if the audit rule is defined
# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection
# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection
default_file="/etc/audit/rules.d/$KEY.rules"
# As other_filters may include paths, lets use a different delimiter for it
# The "F" script expression tells sed to print the filenames where the expressions matched
readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules)
# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet
if [ ${#files_to_inspect[@]} -eq "0" ]
then
file_to_inspect="/etc/audit/rules.d/$KEY.rules"
files_to_inspect=("$file_to_inspect")
if [ ! -e "$file_to_inspect" ]
then
touch "$file_to_inspect"
chmod 0640 "$file_to_inspect"
fi
fi
# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead
skip=1
for audit_file in "${files_to_inspect[@]}"
do
# Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern,
# i.e, collect rules that match:
# * the action, list and arch, (2-nd argument)
# * the other filters, (3-rd argument)
# * the auid filters, (4-rd argument)
readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file")
candidate_rules=()
# Filter out rules that have more fields then required. This will remove rules more specific than the required scope
for s_rule in "${similar_rules[@]}"
do
# Strip all the options and fields we know of,
# than check if there was any field left over
extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule")
grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule")
done
if [[ ${#syscall_a[@]} -ge 1 ]]
then
# Check if the syscall we want is present in any of the similar existing rules
for rule in "${candidate_rules[@]}"
do
rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs)
all_syscalls_found=0
for syscall in "${syscall_a[@]}"
do
grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || {
# A syscall was not found in the candidate rule
all_syscalls_found=1
}
done
if [[ $all_syscalls_found -eq 0 ]]
then
# We found a rule with all the syscall(s) we want; skip rest of macro
skip=0
break
fi
# Check if this rule can be grouped with our target syscall and keep track of it
for syscall_g in "${syscall_grouping[@]}"
do
if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls"
then
file_to_edit=${audit_file}
rule_to_edit=${rule}
rule_syscalls_to_edit=${rule_syscalls}
fi
done
done
else
# If there is any candidate rule, it is compliant; skip rest of macro
if [ "${#candidate_rules[@]}" -gt 0 ]
then
skip=0
fi
fi
if [ "$skip" -eq 0 ]; then
break
fi
done
if [ "$skip" -ne 0 ]; then
# We checked all rules that matched the expected resemblance pattern (action, arch & auid)
# At this point we know if we need to either append the $full_rule or group
# the syscall together with an exsiting rule
# Append the full_rule if it cannot be grouped to any other rule
if [ -z ${rule_to_edit+x} ]
then
# Build full_rule while avoid adding double spaces when other_filters is empty
if [ "${#syscall_a[@]}" -gt 0 ]
then
syscall_string=""
for syscall in "${syscall_a[@]}"
do
syscall_string+=" -S $syscall"
done
fi
other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true
auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true
full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true
echo "$full_rule" >> "$default_file"
chmod o-rwx ${default_file}
else
# Check if the syscalls are declared as a comma separated list or
# as multiple -S parameters
if grep -q -- "," <<< "${rule_syscalls_to_edit}"
then
delimiter=","
else
delimiter=" -S "
fi
new_grouped_syscalls="${rule_syscalls_to_edit}"
for syscall in "${syscall_a[@]}"
do
grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || {
# A syscall was not found in the candidate rule
new_grouped_syscalls+="${delimiter}${syscall}"
}
done
# Group the syscall in the rule
sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit"
fi
fi
unset syscall_a
unset syscall_grouping
unset syscall_string
unset syscall
unset file_to_edit
unset rule_to_edit
unset rule_syscalls_to_edit
unset other_string
unset auid_string
unset full_rule
# Load macro arguments into arrays
read -a syscall_a <<< $SYSCALL
read -a syscall_grouping <<< $SYSCALL_GROUPING
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
#
files_to_inspect=()
# If audit tool is 'auditctl', then add '/etc/audit/audit.rules'
# file to the list of files to be inspected
default_file="/etc/audit/audit.rules"
files_to_inspect+=('/etc/audit/audit.rules' )
# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead
skip=1
for audit_file in "${files_to_inspect[@]}"
do
# Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern,
# i.e, collect rules that match:
# * the action, list and arch, (2-nd argument)
# * the other filters, (3-rd argument)
# * the auid filters, (4-rd argument)
readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file")
candidate_rules=()
# Filter out rules that have more fields then required. This will remove rules more specific than the required scope
for s_rule in "${similar_rules[@]}"
do
# Strip all the options and fields we know of,
# than check if there was any field left over
extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule")
grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule")
done
if [[ ${#syscall_a[@]} -ge 1 ]]
then
# Check if the syscall we want is present in any of the similar existing rules
for rule in "${candidate_rules[@]}"
do
rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs)
all_syscalls_found=0
for syscall in "${syscall_a[@]}"
do
grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || {
# A syscall was not found in the candidate rule
all_syscalls_found=1
}
done
if [[ $all_syscalls_found -eq 0 ]]
then
# We found a rule with all the syscall(s) we want; skip rest of macro
skip=0
break
fi
# Check if this rule can be grouped with our target syscall and keep track of it
for syscall_g in "${syscall_grouping[@]}"
do
if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls"
then
file_to_edit=${audit_file}
rule_to_edit=${rule}
rule_syscalls_to_edit=${rule_syscalls}
fi
done
done
else
# If there is any candidate rule, it is compliant; skip rest of macro
if [ "${#candidate_rules[@]}" -gt 0 ]
then
skip=0
fi
fi
if [ "$skip" -eq 0 ]; then
break
fi
done
if [ "$skip" -ne 0 ]; then
# We checked all rules that matched the expected resemblance pattern (action, arch & auid)
# At this point we know if we need to either append the $full_rule or group
# the syscall together with an exsiting rule
# Append the full_rule if it cannot be grouped to any other rule
if [ -z ${rule_to_edit+x} ]
then
# Build full_rule while avoid adding double spaces when other_filters is empty
if [ "${#syscall_a[@]}" -gt 0 ]
then
syscall_string=""
for syscall in "${syscall_a[@]}"
do
syscall_string+=" -S $syscall"
done
fi
other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true
auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true
full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true
echo "$full_rule" >> "$default_file"
chmod o-rwx ${default_file}
else
# Check if the syscalls are declared as a comma separated list or
# as multiple -S parameters
if grep -q -- "," <<< "${rule_syscalls_to_edit}"
then
delimiter=","
else
delimiter=" -S "
fi
new_grouped_syscalls="${rule_syscalls_to_edit}"
for syscall in "${syscall_a[@]}"
do
grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || {
# A syscall was not found in the candidate rule
new_grouped_syscalls+="${delimiter}${syscall}"
}
done
# Group the syscall in the rule
sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit"
fi
fi
done
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Record Events that Modify the System's Mandatory Access Controls
[ref]ruleIf the auditd daemon is configured to use the
augenrules program to read audit rules during daemon startup (the
default), add the following line to a file with suffix .rules in the
directory /etc/audit/rules.d :
-w /etc/selinux/ -p wa -k MAC-policy
If the auditd daemon is configured to use the auditctl
utility to read audit rules during daemon startup, add the following line to
/etc/audit/audit.rules file:
-w /etc/selinux/ -p wa -k MAC-policy Rationale:The system's mandatory access policy (SELinux) should not be
arbitrarily changed by anything other than administrator action. All changes to
MAC policy should be audited. References:
R73, 1, 11, 12, 13, 14, 15, 16, 19, 2, 3, 4, 5, 6, 7, 8, 9, 5.4.1.1, APO10.01, APO10.03, APO10.04, APO10.05, APO11.04, APO12.06, APO13.01, BAI03.05, BAI08.02, DSS01.03, DSS01.04, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS03.05, DSS05.02, DSS05.03, DSS05.04, DSS05.05, DSS05.07, MEA01.01, MEA01.02, MEA01.03, MEA01.04, MEA01.05, MEA02.01, 3.1.8, 164.308(a)(1)(ii)(D), 164.308(a)(3)(ii)(A), 164.308(a)(5)(ii)(C), 164.312(a)(2)(i), 164.312(b), 164.312(d), 164.312(e), 4.2.3.10, 4.3.2.6.7, 4.3.3.3.9, 4.3.3.5.8, 4.3.3.6.6, 4.3.4.4.7, 4.3.4.5.6, 4.3.4.5.7, 4.3.4.5.8, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 1.13, SR 2.10, SR 2.11, SR 2.12, SR 2.6, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.1, SR 6.2, SR 7.1, SR 7.6, A.11.2.6, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.7, A.15.2.1, A.15.2.2, A.16.1.4, A.16.1.5, A.16.1.7, A.6.2.1, A.6.2.2, AU-2(d), AU-12(c), CM-6(a), DE.AE-3, DE.AE-5, DE.CM-1, DE.CM-3, DE.CM-7, ID.SC-4, PR.AC-3, PR.PT-1, PR.PT-4, RS.AN-1, RS.AN-4, Req-10.5.5, 10.3.4, 10.3 Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed && dpkg-query --show --showformat='${db:Status-Status}\n' 'auditd' 2>/dev/null | grep -q installed; then
# Perform the remediation for both possible tools: 'auditctl' and 'augenrules'
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules'
# into the list of files to be inspected
files_to_inspect+=('/etc/audit/audit.rules')
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/etc/selinux/" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/selinux/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/etc/selinux/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /etc/selinux/ -p wa -k MAC-policy" >> "$audit_rules_file"
fi
done
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit is 'augenrules', then check if rule is already defined
# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection.
# If rule isn't defined, add '/etc/audit/rules.d/MAC-policy.rules' to list of files for inspection.
readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/selinux/" /etc/audit/rules.d/*.rules)
# For each of the matched entries
for match in "${matches[@]}"
do
# Extract filepath from the match
rulesd_audit_file=$(echo $match | cut -f1 -d ':')
# Append that path into list of files for inspection
files_to_inspect+=("$rulesd_audit_file")
done
# Case when particular audit rule isn't defined yet
if [ "${#files_to_inspect[@]}" -eq "0" ]
then
# Append '/etc/audit/rules.d/MAC-policy.rules' into list of files for inspection
key_rule_file="/etc/audit/rules.d/MAC-policy.rules"
# If the MAC-policy.rules file doesn't exist yet, create it with correct permissions
if [ ! -e "$key_rule_file" ]
then
touch "$key_rule_file"
chmod 0640 "$key_rule_file"
fi
files_to_inspect+=("$key_rule_file")
fi
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/etc/selinux/" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/selinux/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/etc/selinux/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /etc/selinux/ -p wa -k MAC-policy" >> "$audit_rules_file"
fi
done
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Record Events that Modify the System's Network Environment
[ref]ruleIf the auditd daemon is configured to use the
augenrules program to read audit rules during daemon startup (the
default), add the following lines to a file with suffix .rules in the
directory /etc/audit/rules.d , setting ARCH to either b32 or b64 as
appropriate for your system:
-a always,exit -F arch=ARCH -S sethostname,setdomainname -F key=audit_rules_networkconfig_modification
-w /etc/issue -p wa -k audit_rules_networkconfig_modification
-w /etc/issue.net -p wa -k audit_rules_networkconfig_modification
-w /etc/hosts -p wa -k audit_rules_networkconfig_modification
-w /etc/networks -p wa -k audit_rules_networkconfig_modification
-w /etc/network/ -p wa -k audit_rules_networkconfig_modification
If the auditd daemon is configured to use the auditctl
utility to read audit rules during daemon startup, add the following lines to
/etc/audit/audit.rules file, setting ARCH to either b32 or b64 as
appropriate for your system:
-a always,exit -F arch=ARCH -S sethostname,setdomainname -F key=audit_rules_networkconfig_modification
-w /etc/issue -p wa -k audit_rules_networkconfig_modification
-w /etc/issue.net -p wa -k audit_rules_networkconfig_modification
-w /etc/hosts -p wa -k audit_rules_networkconfig_modification
-w /etc/networks -p wa -k audit_rules_networkconfig_modification
-w /etc/network/ -p wa -k audit_rules_networkconfig_modification Rationale:The network environment should not be modified by anything other
than administrator action. Any change to network parameters should be
audited. References:
R73, 1, 11, 12, 13, 14, 15, 16, 19, 2, 3, 4, 5, 6, 7, 8, 9, 5.4.1.1, APO10.01, APO10.03, APO10.04, APO10.05, APO11.04, APO12.06, APO13.01, BAI03.05, BAI08.02, DSS01.03, DSS01.04, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS03.05, DSS05.02, DSS05.03, DSS05.04, DSS05.05, DSS05.07, MEA01.01, MEA01.02, MEA01.03, MEA01.04, MEA01.05, MEA02.01, 3.1.7, 164.308(a)(1)(ii)(D), 164.308(a)(3)(ii)(A), 164.308(a)(5)(ii)(C), 164.312(a)(2)(i), 164.312(b), 164.312(d), 164.312(e), 4.2.3.10, 4.3.2.6.7, 4.3.3.3.9, 4.3.3.5.8, 4.3.3.6.6, 4.3.4.4.7, 4.3.4.5.6, 4.3.4.5.7, 4.3.4.5.8, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 1.13, SR 2.10, SR 2.11, SR 2.12, SR 2.6, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.1, SR 6.2, SR 7.1, SR 7.6, A.11.2.6, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.7, A.15.2.1, A.15.2.2, A.16.1.4, A.16.1.5, A.16.1.7, A.6.2.1, A.6.2.2, AU-2(d), AU-12(c), AC-6(9), CM-6(a), DE.AE-3, DE.AE-5, DE.CM-1, DE.CM-3, DE.CM-7, ID.SC-4, PR.AC-3, PR.PT-1, PR.PT-4, RS.AN-1, RS.AN-4, Req-10.5.5, 10.3.4, 10.3 Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed && dpkg-query --show --showformat='${db:Status-Status}\n' 'auditd' 2>/dev/null | grep -q installed; then
# First perform the remediation of the syscall rule
# Retrieve hardware architecture of the underlying system
[ "$(getconf LONG_BIT)" = "32" ] && RULE_ARCHS=("b32") || RULE_ARCHS=("b32" "b64")
for ARCH in "${RULE_ARCHS[@]}"
do
ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH"
OTHER_FILTERS=""
AUID_FILTERS=""
SYSCALL="sethostname setdomainname"
KEY="audit_rules_networkconfig_modification"
SYSCALL_GROUPING="sethostname setdomainname"
# Perform the remediation for both possible tools: 'auditctl' and 'augenrules'
unset syscall_a
unset syscall_grouping
unset syscall_string
unset syscall
unset file_to_edit
unset rule_to_edit
unset rule_syscalls_to_edit
unset other_string
unset auid_string
unset full_rule
# Load macro arguments into arrays
read -a syscall_a <<< $SYSCALL
read -a syscall_grouping <<< $SYSCALL_GROUPING
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
#
files_to_inspect=()
# If audit tool is 'augenrules', then check if the audit rule is defined
# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection
# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection
default_file="/etc/audit/rules.d/$KEY.rules"
# As other_filters may include paths, lets use a different delimiter for it
# The "F" script expression tells sed to print the filenames where the expressions matched
readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules)
# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet
if [ ${#files_to_inspect[@]} -eq "0" ]
then
file_to_inspect="/etc/audit/rules.d/$KEY.rules"
files_to_inspect=("$file_to_inspect")
if [ ! -e "$file_to_inspect" ]
then
touch "$file_to_inspect"
chmod 0640 "$file_to_inspect"
fi
fi
# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead
skip=1
for audit_file in "${files_to_inspect[@]}"
do
# Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern,
# i.e, collect rules that match:
# * the action, list and arch, (2-nd argument)
# * the other filters, (3-rd argument)
# * the auid filters, (4-rd argument)
readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file")
candidate_rules=()
# Filter out rules that have more fields then required. This will remove rules more specific than the required scope
for s_rule in "${similar_rules[@]}"
do
# Strip all the options and fields we know of,
# than check if there was any field left over
extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule")
grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule")
done
if [[ ${#syscall_a[@]} -ge 1 ]]
then
# Check if the syscall we want is present in any of the similar existing rules
for rule in "${candidate_rules[@]}"
do
rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs)
all_syscalls_found=0
for syscall in "${syscall_a[@]}"
do
grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || {
# A syscall was not found in the candidate rule
all_syscalls_found=1
}
done
if [[ $all_syscalls_found -eq 0 ]]
then
# We found a rule with all the syscall(s) we want; skip rest of macro
skip=0
break
fi
# Check if this rule can be grouped with our target syscall and keep track of it
for syscall_g in "${syscall_grouping[@]}"
do
if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls"
then
file_to_edit=${audit_file}
rule_to_edit=${rule}
rule_syscalls_to_edit=${rule_syscalls}
fi
done
done
else
# If there is any candidate rule, it is compliant; skip rest of macro
if [ "${#candidate_rules[@]}" -gt 0 ]
then
skip=0
fi
fi
if [ "$skip" -eq 0 ]; then
break
fi
done
if [ "$skip" -ne 0 ]; then
# We checked all rules that matched the expected resemblance pattern (action, arch & auid)
# At this point we know if we need to either append the $full_rule or group
# the syscall together with an exsiting rule
# Append the full_rule if it cannot be grouped to any other rule
if [ -z ${rule_to_edit+x} ]
then
# Build full_rule while avoid adding double spaces when other_filters is empty
if [ "${#syscall_a[@]}" -gt 0 ]
then
syscall_string=""
for syscall in "${syscall_a[@]}"
do
syscall_string+=" -S $syscall"
done
fi
other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true
auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true
full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true
echo "$full_rule" >> "$default_file"
chmod o-rwx ${default_file}
else
# Check if the syscalls are declared as a comma separated list or
# as multiple -S parameters
if grep -q -- "," <<< "${rule_syscalls_to_edit}"
then
delimiter=","
else
delimiter=" -S "
fi
new_grouped_syscalls="${rule_syscalls_to_edit}"
for syscall in "${syscall_a[@]}"
do
grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || {
# A syscall was not found in the candidate rule
new_grouped_syscalls+="${delimiter}${syscall}"
}
done
# Group the syscall in the rule
sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit"
fi
fi
unset syscall_a
unset syscall_grouping
unset syscall_string
unset syscall
unset file_to_edit
unset rule_to_edit
unset rule_syscalls_to_edit
unset other_string
unset auid_string
unset full_rule
# Load macro arguments into arrays
read -a syscall_a <<< $SYSCALL
read -a syscall_grouping <<< $SYSCALL_GROUPING
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
#
files_to_inspect=()
# If audit tool is 'auditctl', then add '/etc/audit/audit.rules'
# file to the list of files to be inspected
default_file="/etc/audit/audit.rules"
files_to_inspect+=('/etc/audit/audit.rules' )
# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead
skip=1
for audit_file in "${files_to_inspect[@]}"
do
# Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern,
# i.e, collect rules that match:
# * the action, list and arch, (2-nd argument)
# * the other filters, (3-rd argument)
# * the auid filters, (4-rd argument)
readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file")
candidate_rules=()
# Filter out rules that have more fields then required. This will remove rules more specific than the required scope
for s_rule in "${similar_rules[@]}"
do
# Strip all the options and fields we know of,
# than check if there was any field left over
extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule")
grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule")
done
if [[ ${#syscall_a[@]} -ge 1 ]]
then
# Check if the syscall we want is present in any of the similar existing rules
for rule in "${candidate_rules[@]}"
do
rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs)
all_syscalls_found=0
for syscall in "${syscall_a[@]}"
do
grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || {
# A syscall was not found in the candidate rule
all_syscalls_found=1
}
done
if [[ $all_syscalls_found -eq 0 ]]
then
# We found a rule with all the syscall(s) we want; skip rest of macro
skip=0
break
fi
# Check if this rule can be grouped with our target syscall and keep track of it
for syscall_g in "${syscall_grouping[@]}"
do
if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls"
then
file_to_edit=${audit_file}
rule_to_edit=${rule}
rule_syscalls_to_edit=${rule_syscalls}
fi
done
done
else
# If there is any candidate rule, it is compliant; skip rest of macro
if [ "${#candidate_rules[@]}" -gt 0 ]
then
skip=0
fi
fi
if [ "$skip" -eq 0 ]; then
break
fi
done
if [ "$skip" -ne 0 ]; then
# We checked all rules that matched the expected resemblance pattern (action, arch & auid)
# At this point we know if we need to either append the $full_rule or group
# the syscall together with an exsiting rule
# Append the full_rule if it cannot be grouped to any other rule
if [ -z ${rule_to_edit+x} ]
then
# Build full_rule while avoid adding double spaces when other_filters is empty
if [ "${#syscall_a[@]}" -gt 0 ]
then
syscall_string=""
for syscall in "${syscall_a[@]}"
do
syscall_string+=" -S $syscall"
done
fi
other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true
auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true
full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true
echo "$full_rule" >> "$default_file"
chmod o-rwx ${default_file}
else
# Check if the syscalls are declared as a comma separated list or
# as multiple -S parameters
if grep -q -- "," <<< "${rule_syscalls_to_edit}"
then
delimiter=","
else
delimiter=" -S "
fi
new_grouped_syscalls="${rule_syscalls_to_edit}"
for syscall in "${syscall_a[@]}"
do
grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || {
# A syscall was not found in the candidate rule
new_grouped_syscalls+="${delimiter}${syscall}"
}
done
# Group the syscall in the rule
sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit"
fi
fi
done
# Then perform the remediations for the watch rules
# Perform the remediation for both possible tools: 'auditctl' and 'augenrules'
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules'
# into the list of files to be inspected
files_to_inspect+=('/etc/audit/audit.rules')
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/etc/issue" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/issue $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/etc/issue$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /etc/issue -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file"
fi
done
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit is 'augenrules', then check if rule is already defined
# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection.
# If rule isn't defined, add '/etc/audit/rules.d/audit_rules_networkconfig_modification.rules' to list of files for inspection.
readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/issue" /etc/audit/rules.d/*.rules)
# For each of the matched entries
for match in "${matches[@]}"
do
# Extract filepath from the match
rulesd_audit_file=$(echo $match | cut -f1 -d ':')
# Append that path into list of files for inspection
files_to_inspect+=("$rulesd_audit_file")
done
# Case when particular audit rule isn't defined yet
if [ "${#files_to_inspect[@]}" -eq "0" ]
then
# Append '/etc/audit/rules.d/audit_rules_networkconfig_modification.rules' into list of files for inspection
key_rule_file="/etc/audit/rules.d/audit_rules_networkconfig_modification.rules"
# If the audit_rules_networkconfig_modification.rules file doesn't exist yet, create it with correct permissions
if [ ! -e "$key_rule_file" ]
then
touch "$key_rule_file"
chmod 0640 "$key_rule_file"
fi
files_to_inspect+=("$key_rule_file")
fi
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/etc/issue" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/issue $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/etc/issue$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /etc/issue -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file"
fi
done
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules'
# into the list of files to be inspected
files_to_inspect+=('/etc/audit/audit.rules')
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/etc/issue.net" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/issue.net $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/etc/issue.net$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /etc/issue.net -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file"
fi
done
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit is 'augenrules', then check if rule is already defined
# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection.
# If rule isn't defined, add '/etc/audit/rules.d/audit_rules_networkconfig_modification.rules' to list of files for inspection.
readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/issue.net" /etc/audit/rules.d/*.rules)
# For each of the matched entries
for match in "${matches[@]}"
do
# Extract filepath from the match
rulesd_audit_file=$(echo $match | cut -f1 -d ':')
# Append that path into list of files for inspection
files_to_inspect+=("$rulesd_audit_file")
done
# Case when particular audit rule isn't defined yet
if [ "${#files_to_inspect[@]}" -eq "0" ]
then
# Append '/etc/audit/rules.d/audit_rules_networkconfig_modification.rules' into list of files for inspection
key_rule_file="/etc/audit/rules.d/audit_rules_networkconfig_modification.rules"
# If the audit_rules_networkconfig_modification.rules file doesn't exist yet, create it with correct permissions
if [ ! -e "$key_rule_file" ]
then
touch "$key_rule_file"
chmod 0640 "$key_rule_file"
fi
files_to_inspect+=("$key_rule_file")
fi
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/etc/issue.net" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/issue.net $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/etc/issue.net$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /etc/issue.net -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file"
fi
done
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules'
# into the list of files to be inspected
files_to_inspect+=('/etc/audit/audit.rules')
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/etc/hosts" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/hosts $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/etc/hosts$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /etc/hosts -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file"
fi
done
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit is 'augenrules', then check if rule is already defined
# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection.
# If rule isn't defined, add '/etc/audit/rules.d/audit_rules_networkconfig_modification.rules' to list of files for inspection.
readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/hosts" /etc/audit/rules.d/*.rules)
# For each of the matched entries
for match in "${matches[@]}"
do
# Extract filepath from the match
rulesd_audit_file=$(echo $match | cut -f1 -d ':')
# Append that path into list of files for inspection
files_to_inspect+=("$rulesd_audit_file")
done
# Case when particular audit rule isn't defined yet
if [ "${#files_to_inspect[@]}" -eq "0" ]
then
# Append '/etc/audit/rules.d/audit_rules_networkconfig_modification.rules' into list of files for inspection
key_rule_file="/etc/audit/rules.d/audit_rules_networkconfig_modification.rules"
# If the audit_rules_networkconfig_modification.rules file doesn't exist yet, create it with correct permissions
if [ ! -e "$key_rule_file" ]
then
touch "$key_rule_file"
chmod 0640 "$key_rule_file"
fi
files_to_inspect+=("$key_rule_file")
fi
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/etc/hosts" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/hosts $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/etc/hosts$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /etc/hosts -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file"
fi
done
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules'
# into the list of files to be inspected
files_to_inspect+=('/etc/audit/audit.rules')
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/etc/networks" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/networks $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/etc/networks$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /etc/networks -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file"
fi
done
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit is 'augenrules', then check if rule is already defined
# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection.
# If rule isn't defined, add '/etc/audit/rules.d/audit_rules_networkconfig_modification.rules' to list of files for inspection.
readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/networks" /etc/audit/rules.d/*.rules)
# For each of the matched entries
for match in "${matches[@]}"
do
# Extract filepath from the match
rulesd_audit_file=$(echo $match | cut -f1 -d ':')
# Append that path into list of files for inspection
files_to_inspect+=("$rulesd_audit_file")
done
# Case when particular audit rule isn't defined yet
if [ "${#files_to_inspect[@]}" -eq "0" ]
then
# Append '/etc/audit/rules.d/audit_rules_networkconfig_modification.rules' into list of files for inspection
key_rule_file="/etc/audit/rules.d/audit_rules_networkconfig_modification.rules"
# If the audit_rules_networkconfig_modification.rules file doesn't exist yet, create it with correct permissions
if [ ! -e "$key_rule_file" ]
then
touch "$key_rule_file"
chmod 0640 "$key_rule_file"
fi
files_to_inspect+=("$key_rule_file")
fi
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/etc/networks" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/networks $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/etc/networks$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /etc/networks -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file"
fi
done
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules'
# into the list of files to be inspected
files_to_inspect+=('/etc/audit/audit.rules')
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/etc/network/" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/network/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/etc/network/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /etc/network/ -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file"
fi
done
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit is 'augenrules', then check if rule is already defined
# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection.
# If rule isn't defined, add '/etc/audit/rules.d/audit_rules_networkconfig_modification.rules' to list of files for inspection.
readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/network/" /etc/audit/rules.d/*.rules)
# For each of the matched entries
for match in "${matches[@]}"
do
# Extract filepath from the match
rulesd_audit_file=$(echo $match | cut -f1 -d ':')
# Append that path into list of files for inspection
files_to_inspect+=("$rulesd_audit_file")
done
# Case when particular audit rule isn't defined yet
if [ "${#files_to_inspect[@]}" -eq "0" ]
then
# Append '/etc/audit/rules.d/audit_rules_networkconfig_modification.rules' into list of files for inspection
key_rule_file="/etc/audit/rules.d/audit_rules_networkconfig_modification.rules"
# If the audit_rules_networkconfig_modification.rules file doesn't exist yet, create it with correct permissions
if [ ! -e "$key_rule_file" ]
then
touch "$key_rule_file"
chmod 0640 "$key_rule_file"
fi
files_to_inspect+=("$key_rule_file")
fi
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/etc/network/" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/network/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/etc/network/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /etc/network/ -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file"
fi
done
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Record Attempts to Alter Process and Session Initiation Information
[ref]ruleThe audit system already collects process information for all
users and root. If the auditd daemon is configured to use the
augenrules program to read audit rules during daemon startup (the
default), add the following lines to a file with suffix .rules in the
directory /etc/audit/rules.d in order to watch for attempted manual
edits of files involved in storing such process information:
-w /var/run/utmp -p wa -k session
-w /var/log/btmp -p wa -k session
-w /var/log/wtmp -p wa -k session
If the auditd daemon is configured to use the auditctl
utility to read audit rules during daemon startup, add the following lines to
/etc/audit/audit.rules file in order to watch for attempted manual
edits of files involved in storing such process information:
-w /var/run/utmp -p wa -k session
-w /var/log/btmp -p wa -k session
-w /var/log/wtmp -p wa -k session Rationale:Manual editing of these files may indicate nefarious activity, such
as an attacker attempting to remove evidence of an intrusion. References:
R73, 1, 11, 12, 13, 14, 15, 16, 19, 2, 3, 4, 5, 6, 7, 8, 9, 5.4.1.1, APO10.01, APO10.03, APO10.04, APO10.05, APO11.04, APO12.06, APO13.01, BAI03.05, BAI08.02, DSS01.03, DSS01.04, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS03.05, DSS05.02, DSS05.03, DSS05.04, DSS05.05, DSS05.07, MEA01.01, MEA01.02, MEA01.03, MEA01.04, MEA01.05, MEA02.01, 3.1.7, 164.308(a)(1)(ii)(D), 164.308(a)(3)(ii)(A), 164.308(a)(5)(ii)(C), 164.312(a)(2)(i), 164.312(b), 164.312(d), 164.312(e), 4.2.3.10, 4.3.2.6.7, 4.3.3.3.9, 4.3.3.5.8, 4.3.3.6.6, 4.3.4.4.7, 4.3.4.5.6, 4.3.4.5.7, 4.3.4.5.8, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 1.13, SR 2.10, SR 2.11, SR 2.12, SR 2.6, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.1, SR 6.2, SR 7.1, SR 7.6, 0582, 0584, 05885, 0586, 0846, 0957, A.11.2.6, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.7, A.15.2.1, A.15.2.2, A.16.1.4, A.16.1.5, A.16.1.7, A.6.2.1, A.6.2.2, AU-2(d), AU-12(c), CM-6(a), DE.AE-3, DE.AE-5, DE.CM-1, DE.CM-3, DE.CM-7, ID.SC-4, PR.AC-3, PR.PT-1, PR.PT-4, RS.AN-1, RS.AN-4, Req-10.2.3, 10.2.1.3, 10.2.1, 10.2, SRG-APP-000505-CTR-001285 Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed && dpkg-query --show --showformat='${db:Status-Status}\n' 'auditd' 2>/dev/null | grep -q installed; then
# Perform the remediation for both possible tools: 'auditctl' and 'augenrules'
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules'
# into the list of files to be inspected
files_to_inspect+=('/etc/audit/audit.rules')
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/var/run/utmp" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/run/utmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/var/run/utmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /var/run/utmp -p wa -k session" >> "$audit_rules_file"
fi
done
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit is 'augenrules', then check if rule is already defined
# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection.
# If rule isn't defined, add '/etc/audit/rules.d/session.rules' to list of files for inspection.
readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/run/utmp" /etc/audit/rules.d/*.rules)
# For each of the matched entries
for match in "${matches[@]}"
do
# Extract filepath from the match
rulesd_audit_file=$(echo $match | cut -f1 -d ':')
# Append that path into list of files for inspection
files_to_inspect+=("$rulesd_audit_file")
done
# Case when particular audit rule isn't defined yet
if [ "${#files_to_inspect[@]}" -eq "0" ]
then
# Append '/etc/audit/rules.d/session.rules' into list of files for inspection
key_rule_file="/etc/audit/rules.d/session.rules"
# If the session.rules file doesn't exist yet, create it with correct permissions
if [ ! -e "$key_rule_file" ]
then
touch "$key_rule_file"
chmod 0640 "$key_rule_file"
fi
files_to_inspect+=("$key_rule_file")
fi
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/var/run/utmp" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/run/utmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/var/run/utmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /var/run/utmp -p wa -k session" >> "$audit_rules_file"
fi
done
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules'
# into the list of files to be inspected
files_to_inspect+=('/etc/audit/audit.rules')
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/var/log/btmp" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/btmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/var/log/btmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /var/log/btmp -p wa -k session" >> "$audit_rules_file"
fi
done
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit is 'augenrules', then check if rule is already defined
# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection.
# If rule isn't defined, add '/etc/audit/rules.d/session.rules' to list of files for inspection.
readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/btmp" /etc/audit/rules.d/*.rules)
# For each of the matched entries
for match in "${matches[@]}"
do
# Extract filepath from the match
rulesd_audit_file=$(echo $match | cut -f1 -d ':')
# Append that path into list of files for inspection
files_to_inspect+=("$rulesd_audit_file")
done
# Case when particular audit rule isn't defined yet
if [ "${#files_to_inspect[@]}" -eq "0" ]
then
# Append '/etc/audit/rules.d/session.rules' into list of files for inspection
key_rule_file="/etc/audit/rules.d/session.rules"
# If the session.rules file doesn't exist yet, create it with correct permissions
if [ ! -e "$key_rule_file" ]
then
touch "$key_rule_file"
chmod 0640 "$key_rule_file"
fi
files_to_inspect+=("$key_rule_file")
fi
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/var/log/btmp" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/btmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/var/log/btmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /var/log/btmp -p wa -k session" >> "$audit_rules_file"
fi
done
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules'
# into the list of files to be inspected
files_to_inspect+=('/etc/audit/audit.rules')
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/var/log/wtmp" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/wtmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/var/log/wtmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /var/log/wtmp -p wa -k session" >> "$audit_rules_file"
fi
done
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit is 'augenrules', then check if rule is already defined
# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection.
# If rule isn't defined, add '/etc/audit/rules.d/session.rules' to list of files for inspection.
readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/wtmp" /etc/audit/rules.d/*.rules)
# For each of the matched entries
for match in "${matches[@]}"
do
# Extract filepath from the match
rulesd_audit_file=$(echo $match | cut -f1 -d ':')
# Append that path into list of files for inspection
files_to_inspect+=("$rulesd_audit_file")
done
# Case when particular audit rule isn't defined yet
if [ "${#files_to_inspect[@]}" -eq "0" ]
then
# Append '/etc/audit/rules.d/session.rules' into list of files for inspection
key_rule_file="/etc/audit/rules.d/session.rules"
# If the session.rules file doesn't exist yet, create it with correct permissions
if [ ! -e "$key_rule_file" ]
then
touch "$key_rule_file"
chmod 0640 "$key_rule_file"
fi
files_to_inspect+=("$key_rule_file")
fi
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/var/log/wtmp" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/wtmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/var/log/wtmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /var/log/wtmp -p wa -k session" >> "$audit_rules_file"
fi
done
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Ensure auditd Collects System Administrator Actions
[ref]ruleAt a minimum, the audit system should collect administrator actions
for all users and root. If the auditd daemon is configured to use the
augenrules program to read audit rules during daemon startup (the default),
add the following line to a file with suffix .rules in the directory
/etc/audit/rules.d :
-w /etc/sudoers -p wa -k actions
-w /etc/sudoers.d/ -p wa -k actions
If the auditd daemon is configured to use the auditctl
utility to read audit rules during daemon startup, add the following line to
/etc/audit/audit.rules file:
-w /etc/sudoers -p wa -k actions
-w /etc/sudoers.d/ -p wa -k actions Rationale:The actions taken by system administrators should be audited to keep a record
of what was executed on the system, as well as, for accountability purposes. References:
R73, 1, 11, 12, 13, 14, 15, 16, 18, 19, 2, 3, 4, 5, 6, 7, 8, 9, 5.4.1.1, APO10.01, APO10.03, APO10.04, APO10.05, APO11.04, APO12.06, APO13.01, BAI03.05, BAI08.02, DSS01.03, DSS01.04, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS03.05, DSS05.02, DSS05.03, DSS05.04, DSS05.05, DSS05.07, DSS06.03, MEA01.01, MEA01.02, MEA01.03, MEA01.04, MEA01.05, MEA02.01, 3.1.7, CCI-000126, CCI-000130, CCI-000135, CCI-000169, CCI-000172, CCI-002884, 164.308(a)(1)(ii)(D), 164.308(a)(3)(ii)(A), 164.308(a)(5)(ii)(C), 164.312(a)(2)(i), 164.312(b), 164.312(d), 164.312(e), 4.2.3.10, 4.3.2.6.7, 4.3.3.2.2, 4.3.3.3.9, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.8, 4.3.3.6.6, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.4.7, 4.3.4.5.6, 4.3.4.5.7, 4.3.4.5.8, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 1.1, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.10, SR 2.11, SR 2.12, SR 2.6, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.1, SR 6.2, SR 7.1, SR 7.6, A.11.2.6, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.7, A.15.2.1, A.15.2.2, A.16.1.4, A.16.1.5, A.16.1.7, A.6.1.2, A.6.2.1, A.6.2.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, AC-2(7)(b), AU-2(d), AU-12(c), AC-6(9), CM-6(a), DE.AE-3, DE.AE-5, DE.CM-1, DE.CM-3, DE.CM-7, ID.SC-4, PR.AC-1, PR.AC-3, PR.AC-4, PR.AC-6, PR.PT-1, PR.PT-4, RS.AN-1, RS.AN-4, Req-10.2.2, Req-10.2.5.b, 10.2.1.5, 10.2.1, 10.2, SRG-OS-000004-GPOS-00004, SRG-OS-000037-GPOS-00015, SRG-OS-000042-GPOS-00020, SRG-OS-000062-GPOS-00031, SRG-OS-000304-GPOS-00121, SRG-OS-000392-GPOS-00172, SRG-OS-000462-GPOS-00206, SRG-OS-000470-GPOS-00214, SRG-OS-000471-GPOS-00215, SRG-OS-000239-GPOS-00089, SRG-OS-000240-GPOS-00090, SRG-OS-000241-GPOS-00091, SRG-OS-000303-GPOS-00120, SRG-OS-000304-GPOS-00121, SRG-OS-000466-GPOS-00210, SRG-OS-000476-GPOS-00221, SRG-APP-000026-CTR-000070, SRG-APP-000027-CTR-000075, SRG-APP-000028-CTR-000080, SRG-APP-000291-CTR-000675, SRG-APP-000292-CTR-000680, SRG-APP-000293-CTR-000685, SRG-APP-000294-CTR-000690, SRG-APP-000319-CTR-000745, SRG-APP-000320-CTR-000750, SRG-APP-000509-CTR-001305 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | restrict |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.1.7
- NIST-800-53-AC-2(7)(b)
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-2(d)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-10.2.2
- PCI-DSS-Req-10.2.5.b
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.5
- audit_rules_sysadmin_actions
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Check if watch rule for /etc/sudoers already exists in /etc/audit/audit.rules
find:
paths: /etc/audit/
contains: ^\s*-w\s+/etc/sudoers\s+-p\s+wa(\s|$)+
patterns: audit.rules
register: find_existing_watch_audit_rules
when:
- '"auditd" in ansible_facts.packages'
- '"kernel" in ansible_facts.packages'
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.1.7
- NIST-800-53-AC-2(7)(b)
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-2(d)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-10.2.2
- PCI-DSS-Req-10.2.5.b
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.5
- audit_rules_sysadmin_actions
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Add watch rule for /etc/sudoers in /etc/audit/audit.rules
lineinfile:
line: -w /etc/sudoers -p wa -k actions
state: present
dest: /etc/audit/audit.rules
create: true
mode: '0640'
when:
- '"auditd" in ansible_facts.packages'
- '"kernel" in ansible_facts.packages'
- find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched
== 0
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.1.7
- NIST-800-53-AC-2(7)(b)
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-2(d)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-10.2.2
- PCI-DSS-Req-10.2.5.b
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.5
- audit_rules_sysadmin_actions
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Check if watch rule for /etc/sudoers already exists in /etc/audit/rules.d/
find:
paths: /etc/audit/rules.d
contains: ^\s*-w\s+/etc/sudoers\s+-p\s+wa(\s|$)+
patterns: '*.rules'
register: find_existing_watch_rules_d
when:
- '"auditd" in ansible_facts.packages'
- '"kernel" in ansible_facts.packages'
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.1.7
- NIST-800-53-AC-2(7)(b)
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-2(d)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-10.2.2
- PCI-DSS-Req-10.2.5.b
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.5
- audit_rules_sysadmin_actions
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Search /etc/audit/rules.d for other rules with specified key actions
find:
paths: /etc/audit/rules.d
contains: ^.*(?:-F key=|-k\s+)actions$
patterns: '*.rules'
register: find_watch_key
when:
- '"auditd" in ansible_facts.packages'
- '"kernel" in ansible_facts.packages'
- find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched
== 0
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.1.7
- NIST-800-53-AC-2(7)(b)
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-2(d)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-10.2.2
- PCI-DSS-Req-10.2.5.b
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.5
- audit_rules_sysadmin_actions
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Use /etc/audit/rules.d/actions.rules as the recipient for the rule
set_fact:
all_files:
- /etc/audit/rules.d/actions.rules
when:
- '"auditd" in ansible_facts.packages'
- '"kernel" in ansible_facts.packages'
- find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched
is defined and find_existing_watch_rules_d.matched == 0
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.1.7
- NIST-800-53-AC-2(7)(b)
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-2(d)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-10.2.2
- PCI-DSS-Req-10.2.5.b
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.5
- audit_rules_sysadmin_actions
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Use matched file as the recipient for the rule
set_fact:
all_files:
- '{{ find_watch_key.files | map(attribute=''path'') | list | first }}'
when:
- '"auditd" in ansible_facts.packages'
- '"kernel" in ansible_facts.packages'
- find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched
is defined and find_existing_watch_rules_d.matched == 0
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.1.7
- NIST-800-53-AC-2(7)(b)
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-2(d)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-10.2.2
- PCI-DSS-Req-10.2.5.b
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.5
- audit_rules_sysadmin_actions
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Add watch rule for /etc/sudoers in /etc/audit/rules.d/
lineinfile:
path: '{{ all_files[0] }}'
line: -w /etc/sudoers -p wa -k actions
create: true
mode: '0640'
when:
- '"auditd" in ansible_facts.packages'
- '"kernel" in ansible_facts.packages'
- find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched
== 0
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.1.7
- NIST-800-53-AC-2(7)(b)
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-2(d)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-10.2.2
- PCI-DSS-Req-10.2.5.b
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.5
- audit_rules_sysadmin_actions
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Check if watch rule for /etc/sudoers.d/ already exists in /etc/audit/audit.rules
find:
paths: /etc/audit/
contains: ^\s*-w\s+/etc/sudoers.d/\s+-p\s+wa(\s|$)+
patterns: audit.rules
register: find_existing_watch_audit_rules
when:
- '"auditd" in ansible_facts.packages'
- '"kernel" in ansible_facts.packages'
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.1.7
- NIST-800-53-AC-2(7)(b)
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-2(d)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-10.2.2
- PCI-DSS-Req-10.2.5.b
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.5
- audit_rules_sysadmin_actions
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Add watch rule for /etc/sudoers.d/ in /etc/audit/audit.rules
lineinfile:
line: -w /etc/sudoers.d/ -p wa -k actions
state: present
dest: /etc/audit/audit.rules
create: true
mode: '0640'
when:
- '"auditd" in ansible_facts.packages'
- '"kernel" in ansible_facts.packages'
- find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched
== 0
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.1.7
- NIST-800-53-AC-2(7)(b)
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-2(d)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-10.2.2
- PCI-DSS-Req-10.2.5.b
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.5
- audit_rules_sysadmin_actions
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Check if watch rule for /etc/sudoers.d/ already exists in /etc/audit/rules.d/
find:
paths: /etc/audit/rules.d
contains: ^\s*-w\s+/etc/sudoers.d/\s+-p\s+wa(\s|$)+
patterns: '*.rules'
register: find_existing_watch_rules_d
when:
- '"auditd" in ansible_facts.packages'
- '"kernel" in ansible_facts.packages'
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.1.7
- NIST-800-53-AC-2(7)(b)
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-2(d)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-10.2.2
- PCI-DSS-Req-10.2.5.b
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.5
- audit_rules_sysadmin_actions
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Search /etc/audit/rules.d for other rules with specified key actions
find:
paths: /etc/audit/rules.d
contains: ^.*(?:-F key=|-k\s+)actions$
patterns: '*.rules'
register: find_watch_key
when:
- '"auditd" in ansible_facts.packages'
- '"kernel" in ansible_facts.packages'
- find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched
== 0
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.1.7
- NIST-800-53-AC-2(7)(b)
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-2(d)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-10.2.2
- PCI-DSS-Req-10.2.5.b
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.5
- audit_rules_sysadmin_actions
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Use /etc/audit/rules.d/actions.rules as the recipient for the rule
set_fact:
all_files:
- /etc/audit/rules.d/actions.rules
when:
- '"auditd" in ansible_facts.packages'
- '"kernel" in ansible_facts.packages'
- find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched
is defined and find_existing_watch_rules_d.matched == 0
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.1.7
- NIST-800-53-AC-2(7)(b)
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-2(d)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-10.2.2
- PCI-DSS-Req-10.2.5.b
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.5
- audit_rules_sysadmin_actions
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Use matched file as the recipient for the rule
set_fact:
all_files:
- '{{ find_watch_key.files | map(attribute=''path'') | list | first }}'
when:
- '"auditd" in ansible_facts.packages'
- '"kernel" in ansible_facts.packages'
- find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched
is defined and find_existing_watch_rules_d.matched == 0
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.1.7
- NIST-800-53-AC-2(7)(b)
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-2(d)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-10.2.2
- PCI-DSS-Req-10.2.5.b
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.5
- audit_rules_sysadmin_actions
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Add watch rule for /etc/sudoers.d/ in /etc/audit/rules.d/
lineinfile:
path: '{{ all_files[0] }}'
line: -w /etc/sudoers.d/ -p wa -k actions
create: true
mode: '0640'
when:
- '"auditd" in ansible_facts.packages'
- '"kernel" in ansible_facts.packages'
- find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched
== 0
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.1.7
- NIST-800-53-AC-2(7)(b)
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-2(d)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-10.2.2
- PCI-DSS-Req-10.2.5.b
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.5
- audit_rules_sysadmin_actions
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed && dpkg-query --show --showformat='${db:Status-Status}\n' 'auditd' 2>/dev/null | grep -q installed; then
# Perform the remediation for both possible tools: 'auditctl' and 'augenrules'
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules'
# into the list of files to be inspected
files_to_inspect+=('/etc/audit/audit.rules')
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/etc/sudoers$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /etc/sudoers -p wa -k actions" >> "$audit_rules_file"
fi
done
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit is 'augenrules', then check if rule is already defined
# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection.
# If rule isn't defined, add '/etc/audit/rules.d/actions.rules' to list of files for inspection.
readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/sudoers" /etc/audit/rules.d/*.rules)
# For each of the matched entries
for match in "${matches[@]}"
do
# Extract filepath from the match
rulesd_audit_file=$(echo $match | cut -f1 -d ':')
# Append that path into list of files for inspection
files_to_inspect+=("$rulesd_audit_file")
done
# Case when particular audit rule isn't defined yet
if [ "${#files_to_inspect[@]}" -eq "0" ]
then
# Append '/etc/audit/rules.d/actions.rules' into list of files for inspection
key_rule_file="/etc/audit/rules.d/actions.rules"
# If the actions.rules file doesn't exist yet, create it with correct permissions
if [ ! -e "$key_rule_file" ]
then
touch "$key_rule_file"
chmod 0640 "$key_rule_file"
fi
files_to_inspect+=("$key_rule_file")
fi
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/etc/sudoers$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /etc/sudoers -p wa -k actions" >> "$audit_rules_file"
fi
done
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules'
# into the list of files to be inspected
files_to_inspect+=('/etc/audit/audit.rules')
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers.d/" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers.d/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/etc/sudoers.d/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /etc/sudoers.d/ -p wa -k actions" >> "$audit_rules_file"
fi
done
# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
#
# -----------------------------------------------------------------------------------------
# Tool used to load audit rules | Rule already defined | Audit rules file to inspect |
# -----------------------------------------------------------------------------------------
# auditctl | Doesn't matter | /etc/audit/audit.rules |
# -----------------------------------------------------------------------------------------
# augenrules | Yes | /etc/audit/rules.d/*.rules |
# augenrules | No | /etc/audit/rules.d/$key.rules |
# -----------------------------------------------------------------------------------------
files_to_inspect=()
# If the audit is 'augenrules', then check if rule is already defined
# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection.
# If rule isn't defined, add '/etc/audit/rules.d/actions.rules' to list of files for inspection.
readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/sudoers.d/" /etc/audit/rules.d/*.rules)
# For each of the matched entries
for match in "${matches[@]}"
do
# Extract filepath from the match
rulesd_audit_file=$(echo $match | cut -f1 -d ':')
# Append that path into list of files for inspection
files_to_inspect+=("$rulesd_audit_file")
done
# Case when particular audit rule isn't defined yet
if [ "${#files_to_inspect[@]}" -eq "0" ]
then
# Append '/etc/audit/rules.d/actions.rules' into list of files for inspection
key_rule_file="/etc/audit/rules.d/actions.rules"
# If the actions.rules file doesn't exist yet, create it with correct permissions
if [ ! -e "$key_rule_file" ]
then
touch "$key_rule_file"
chmod 0640 "$key_rule_file"
fi
files_to_inspect+=("$key_rule_file")
fi
# Finally perform the inspection and possible subsequent audit rule
# correction for each of the files previously identified for inspection
for audit_rules_file in "${files_to_inspect[@]}"
do
# Check if audit watch file system object rule for given path already present
if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers.d/" "$audit_rules_file"
then
# Rule is found => verify yet if existing rule definition contains
# all of the required access type bits
# Define BRE whitespace class shortcut
sp="[[:space:]]"
# Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers.d/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
# Split required access bits string into characters array
# (to check bit's presence for one bit at a time)
for access_bit in $(echo "wa" | grep -o .)
do
# For each from the required access bits (e.g. 'w', 'a') check
# if they are already present in current access bits for rule.
# If not, append that bit at the end
if ! grep -q "$access_bit" <<< "$current_access_bits"
then
# Concatenate the existing mask with the missing bit
current_access_bits="$current_access_bits$access_bit"
fi
done
# Propagate the updated rule's access bits (original + the required
# ones) back into the /etc/audit/audit.rules file for that rule
sed -i "s#\($sp*-w$sp\+/etc/sudoers.d/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
else
# Rule isn't present yet. Append it at the end of $audit_rules_file file
# with proper key
echo "-w /etc/sudoers.d/ -p wa -k actions" >> "$audit_rules_file"
fi
done
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Configure auditd Data Retention
[ref]groupThe 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 5 rules |
Configure auditd mail_acct Action on Low Disk Space
[ref]ruleThe 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. References:
1, 11, 12, 13, 14, 15, 16, 19, 2, 3, 4, 5, 6, 7, 8, 5.4.1.1, APO11.04, APO12.06, APO13.01, BAI03.05, BAI04.04, BAI08.02, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS05.04, DSS05.07, MEA02.01, 3.3.1, CCI-001855, CCI-000139, 164.312(a)(2)(ii), 4.2.3.10, 4.3.3.3.9, 4.3.3.5.8, 4.3.4.4.7, 4.3.4.5.6, 4.3.4.5.7, 4.3.4.5.8, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 2.10, SR 2.11, SR 2.12, SR 2.8, SR 2.9, SR 6.1, SR 7.1, SR 7.2, A.12.1.3, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.16.1.4, A.16.1.5, A.16.1.7, A.17.2.1, CIP-003-8 R1.3, CIP-003-8 R3, CIP-003-8 R3.1, CIP-003-8 R3.2, CIP-003-8 R3.3, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.2.3, CIP-004-6 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.2, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, IA-5(1), AU-5(a), AU-5(2), CM-6(a), DE.AE-3, DE.AE-5, PR.DS-4, PR.PT-1, RS.AN-1, RS.AN-4, Req-10.7.a, SRG-OS-000046-GPOS-00022, SRG-OS-000343-GPOS-00134 Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed && dpkg-query --show --showformat='${db:Status-Status}\n' 'auditd' 2>/dev/null | grep -q installed; then
var_auditd_action_mail_acct='root'
AUDITCONFIG=/etc/audit/auditd.conf
# 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' <<< "^action_mail_acct")
# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$var_auditd_action_mail_acct"
# If the key exists, change it. Otherwise, add it to the config_file.
# We search for the key string followed by a word boundary (matched by \>),
# so if we search for 'setting', 'setting2' won't match.
if LC_ALL=C grep -q -m 1 -i -e "^action_mail_acct\\>" "$AUDITCONFIG"; then
escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
LC_ALL=C sed -i --follow-symlinks "s/^action_mail_acct\\>.*/$escaped_formatted_output/gi" "$AUDITCONFIG"
else
if [[ -s "$AUDITCONFIG" ]] && [[ -n "$(tail -c 1 -- "$AUDITCONFIG" || true)" ]]; then
LC_ALL=C sed -i --follow-symlinks '$a'\\ "$AUDITCONFIG"
fi
printf '%s\n' "$formatted_output" >> "$AUDITCONFIG"
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Configure auditd admin_space_left Action on Low Disk Space
[ref]ruleThe 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. References:
1, 11, 12, 13, 14, 15, 16, 19, 2, 3, 4, 5, 6, 7, 8, 5.4.1.1, APO11.04, APO12.06, APO13.01, BAI03.05, BAI04.04, BAI08.02, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS05.04, DSS05.07, MEA02.01, 3.3.1, CCI-001855, 164.312(a)(2)(ii), 4.2.3.10, 4.3.3.3.9, 4.3.3.5.8, 4.3.4.4.7, 4.3.4.5.6, 4.3.4.5.7, 4.3.4.5.8, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 2.10, SR 2.11, SR 2.12, SR 2.8, SR 2.9, SR 6.1, SR 7.1, SR 7.2, A.12.1.3, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.16.1.4, A.16.1.5, A.16.1.7, A.17.2.1, AU-5(b), AU-5(2), AU-5(1), AU-5(4), CM-6(a), DE.AE-3, DE.AE-5, PR.DS-4, PR.PT-1, RS.AN-1, RS.AN-4, Req-10.7, 10.5.1, 10.5, SRG-OS-000343-GPOS-00134 Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed && dpkg-query --show --showformat='${db:Status-Status}\n' 'auditd' 2>/dev/null | grep -q installed; then
var_auditd_admin_space_left_action='halt'
var_auditd_admin_space_left_action="$(echo $var_auditd_admin_space_left_action | cut -d \| -f 1)"
AUDITCONFIG=/etc/audit/auditd.conf
# 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' <<< "^admin_space_left_action")
# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$var_auditd_admin_space_left_action"
# If the key exists, change it. Otherwise, add it to the config_file.
# We search for the key string followed by a word boundary (matched by \>),
# so if we search for 'setting', 'setting2' won't match.
if LC_ALL=C grep -q -m 1 -i -e "^admin_space_left_action\\>" "$AUDITCONFIG"; then
escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
LC_ALL=C sed -i --follow-symlinks "s/^admin_space_left_action\\>.*/$escaped_formatted_output/gi" "$AUDITCONFIG"
else
if [[ -s "$AUDITCONFIG" ]] && [[ -n "$(tail -c 1 -- "$AUDITCONFIG" || true)" ]]; then
LC_ALL=C sed -i --follow-symlinks '$a'\\ "$AUDITCONFIG"
fi
printf '%s\n' "$formatted_output" >> "$AUDITCONFIG"
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Configure auditd Max Log File Size
[ref]ruleDetermine 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. References:
1, 11, 12, 13, 14, 15, 16, 19, 3, 4, 5, 6, 7, 8, 5.4.1.1, APO11.04, APO12.06, BAI03.05, BAI08.02, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS05.04, DSS05.07, MEA02.01, 4.2.3.10, 4.3.3.3.9, 4.3.3.5.8, 4.3.4.4.7, 4.3.4.5.6, 4.3.4.5.7, 4.3.4.5.8, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 2.10, SR 2.11, SR 2.12, SR 2.8, SR 2.9, SR 6.1, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.16.1.4, A.16.1.5, A.16.1.7, CIP-004-6 R2.2.3, CIP-004-6 R3.3, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, CIP-007-3 R6.5, AU-11, CM-6(a), DE.AE-3, DE.AE-5, PR.PT-1, RS.AN-1, RS.AN-4, Req-10.7 Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed && dpkg-query --show --showformat='${db:Status-Status}\n' 'auditd' 2>/dev/null | grep -q installed; then
var_auditd_max_log_file='6'
AUDITCONFIG=/etc/audit/auditd.conf
# 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' <<< "^max_log_file")
# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$var_auditd_max_log_file"
# If the key exists, change it. Otherwise, add it to the config_file.
# We search for the key string followed by a word boundary (matched by \>),
# so if we search for 'setting', 'setting2' won't match.
if LC_ALL=C grep -q -m 1 -i -e "^max_log_file\\>" "$AUDITCONFIG"; then
escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
LC_ALL=C sed -i --follow-symlinks "s/^max_log_file\\>.*/$escaped_formatted_output/gi" "$AUDITCONFIG"
else
if [[ -s "$AUDITCONFIG" ]] && [[ -n "$(tail -c 1 -- "$AUDITCONFIG" || true)" ]]; then
LC_ALL=C sed -i --follow-symlinks '$a'\\ "$AUDITCONFIG"
fi
printf '%s\n' "$formatted_output" >> "$AUDITCONFIG"
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Configure auditd max_log_file_action Upon Reaching Maximum Log Size
[ref]ruleThe 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:
ignore syslog suspend rotate keep_logs
Set the ACTION to rotate .
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. References:
1, 11, 12, 13, 14, 15, 16, 19, 2, 3, 4, 5, 6, 7, 8, 5.4.1.1, APO11.04, APO12.06, APO13.01, BAI03.05, BAI04.04, BAI08.02, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS05.04, DSS05.07, MEA02.01, CCI-000140, 164.312(a)(2)(ii), 4.2.3.10, 4.3.3.3.9, 4.3.3.5.8, 4.3.4.4.7, 4.3.4.5.6, 4.3.4.5.7, 4.3.4.5.8, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 2.10, SR 2.11, SR 2.12, SR 2.8, SR 2.9, SR 6.1, SR 7.1, SR 7.2, A.12.1.3, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.16.1.4, A.16.1.5, A.16.1.7, A.17.2.1, AU-5(b), AU-5(2), AU-5(1), AU-5(4), CM-6(a), DE.AE-3, DE.AE-5, PR.DS-4, PR.PT-1, RS.AN-1, RS.AN-4, Req-10.7, SRG-OS-000047-GPOS-00023 Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed && dpkg-query --show --showformat='${db:Status-Status}\n' 'auditd' 2>/dev/null | grep -q installed; then
var_auditd_max_log_file_action='rotate'
AUDITCONFIG=/etc/audit/auditd.conf
# 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' <<< "^max_log_file_action")
# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$var_auditd_max_log_file_action"
# If the key exists, change it. Otherwise, add it to the config_file.
# We search for the key string followed by a word boundary (matched by \>),
# so if we search for 'setting', 'setting2' won't match.
if LC_ALL=C grep -q -m 1 -i -e "^max_log_file_action\\>" "$AUDITCONFIG"; then
escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
LC_ALL=C sed -i --follow-symlinks "s/^max_log_file_action\\>.*/$escaped_formatted_output/gi" "$AUDITCONFIG"
else
if [[ -s "$AUDITCONFIG" ]] && [[ -n "$(tail -c 1 -- "$AUDITCONFIG" || true)" ]]; then
LC_ALL=C sed -i --follow-symlinks '$a'\\ "$AUDITCONFIG"
fi
printf '%s\n' "$formatted_output" >> "$AUDITCONFIG"
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Configure auditd space_left Action on Low Disk Space
[ref]ruleThe 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. References:
1, 11, 12, 13, 14, 15, 16, 19, 2, 3, 4, 5, 6, 7, 8, 5.4.1.1, APO11.04, APO12.06, APO13.01, BAI03.05, BAI04.04, BAI08.02, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS05.04, DSS05.07, MEA02.01, 3.3.1, CCI-001855, 164.312(a)(2)(ii), 4.2.3.10, 4.3.3.3.9, 4.3.3.5.8, 4.3.4.4.7, 4.3.4.5.6, 4.3.4.5.7, 4.3.4.5.8, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 2.10, SR 2.11, SR 2.12, SR 2.8, SR 2.9, SR 6.1, SR 7.1, SR 7.2, A.12.1.3, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.16.1.4, A.16.1.5, A.16.1.7, A.17.2.1, AU-5(b), AU-5(2), AU-5(1), AU-5(4), CM-6(a), DE.AE-3, DE.AE-5, PR.DS-4, PR.PT-1, RS.AN-1, RS.AN-4, Req-10.7, 10.5.1, 10.5, SRG-OS-000343-GPOS-00134 Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed && dpkg-query --show --showformat='${db:Status-Status}\n' 'auditd' 2>/dev/null | grep -q installed; then
var_auditd_space_left_action='email'
var_auditd_space_left_action="$(echo $var_auditd_space_left_action | cut -d \| -f 1)"
#
# 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
# 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' <<< "^space_left_action")
# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$var_auditd_space_left_action"
# If the key exists, change it. Otherwise, add it to the config_file.
# We search for the key string followed by a word boundary (matched by \>),
# so if we search for 'setting', 'setting2' won't match.
if LC_ALL=C grep -q -m 1 -i -e "^space_left_action\\>" "$AUDITCONFIG"; then
escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
LC_ALL=C sed -i --follow-symlinks "s/^space_left_action\\>.*/$escaped_formatted_output/gi" "$AUDITCONFIG"
else
if [[ -s "$AUDITCONFIG" ]] && [[ -n "$(tail -c 1 -- "$AUDITCONFIG" || true)" ]]; then
LC_ALL=C sed -i --follow-symlinks '$a'\\ "$AUDITCONFIG"
fi
printf '%s\n' "$formatted_output" >> "$AUDITCONFIG"
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
|
Enable auditd Service
[ref]ruleThe auditd service is an essential userspace component of
the Linux Auditing System, as it is responsible for writing audit records to
disk.
The auditd service can be enabled with the following command:
$ sudo systemctl enable auditd.service Rationale:Without establishing what type of events occurred, it would be difficult
to establish, correlate, and investigate the events leading up to an outage or attack.
Ensuring the auditd service is active ensures audit records
generated by the kernel are appropriately recorded.
Additionally, a properly configured audit subsystem ensures that actions of
individual system users can be uniquely traced to those users so they
can be held accountable for their actions. References:
R33, R73, 1, 11, 12, 13, 14, 15, 16, 19, 2, 3, 4, 5, 6, 7, 8, 9, 5.4.1.1, APO10.01, APO10.03, APO10.04, APO10.05, APO11.04, APO12.06, APO13.01, BAI03.05, BAI08.02, DSS01.03, DSS01.04, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS03.05, DSS05.02, DSS05.03, DSS05.04, DSS05.05, DSS05.07, MEA01.01, MEA01.02, MEA01.03, MEA01.04, MEA01.05, MEA02.01, 3.3.1, 3.3.2, 3.3.6, CCI-000133, CCI-001881, CCI-001875, CCI-000154, CCI-001882, CCI-000158, CCI-001914, CCI-000169, CCI-001464, CCI-001878, CCI-001877, CCI-001889, CCI-000135, CCI-002884, CCI-001487, CCI-003938, CCI-000132, CCI-004188, CCI-000134, CCI-000172, CCI-000130, CCI-000131, CCI-001879, CCI-001880, CCI-001876, 164.308(a)(1)(ii)(D), 164.308(a)(5)(ii)(C), 164.310(a)(2)(iv), 164.310(d)(2)(iii), 164.312(b), 4.2.3.10, 4.3.2.6.7, 4.3.3.3.9, 4.3.3.5.8, 4.3.3.6.6, 4.3.4.4.7, 4.3.4.5.6, 4.3.4.5.7, 4.3.4.5.8, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 1.13, SR 2.10, SR 2.11, SR 2.12, SR 2.6, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.1, SR 6.2, SR 7.1, SR 7.6, A.11.2.6, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.7, A.15.2.1, A.15.2.2, A.16.1.4, A.16.1.5, A.16.1.7, A.6.2.1, A.6.2.2, CIP-004-6 R3.3, CIP-007-3 R6.5, AC-2(g), AU-3, AU-10, AU-2(d), AU-12(c), AU-14(1), AC-6(9), CM-6(a), SI-4(23), DE.AE-3, DE.AE-5, DE.CM-1, DE.CM-3, DE.CM-7, ID.SC-4, PR.AC-3, PR.PT-1, PR.PT-4, RS.AN-1, RS.AN-4, FAU_GEN.1, Req-10.1, 10.2.1, 10.2, SRG-OS-000062-GPOS-00031, SRG-OS-000037-GPOS-00015, SRG-OS-000038-GPOS-00016, SRG-OS-000039-GPOS-00017, SRG-OS-000040-GPOS-00018, SRG-OS-000041-GPOS-00019, SRG-OS-000042-GPOS-00021, SRG-OS-000051-GPOS-00024, SRG-OS-000054-GPOS-00025, SRG-OS-000122-GPOS-00063, SRG-OS-000254-GPOS-00095, SRG-OS-000255-GPOS-00096, SRG-OS-000337-GPOS-00129, SRG-OS-000348-GPOS-00136, SRG-OS-000349-GPOS-00137, SRG-OS-000350-GPOS-00138, SRG-OS-000351-GPOS-00139, SRG-OS-000352-GPOS-00140, SRG-OS-000353-GPOS-00141, SRG-OS-000354-GPOS-00142, SRG-OS-000358-GPOS-00145, SRG-OS-000365-GPOS-00152, SRG-OS-000392-GPOS-00172, SRG-OS-000475-GPOS-00220, SRG-APP-000095-CTR-000170, SRG-APP-000409-CTR-000990, SRG-APP-000508-CTR-001300, SRG-APP-000510-CTR-001310 Remediation Ansible snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | enable |
---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.3.1
- NIST-800-171-3.3.2
- NIST-800-171-3.3.6
- NIST-800-53-AC-2(g)
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-10
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-14(1)
- NIST-800-53-AU-2(d)
- NIST-800-53-AU-3
- NIST-800-53-CM-6(a)
- NIST-800-53-SI-4(23)
- PCI-DSS-Req-10.1
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- enable_strategy
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- service_auditd_enabled
- name: Enable auditd Service - Enable service auditd
block:
- name: Gather the package facts
package_facts:
manager: auto
- name: Enable auditd Service - Enable Service auditd
ansible.builtin.systemd:
name: auditd
enabled: true
state: started
masked: false
when:
- '"auditd" in ansible_facts.packages'
when:
- '"kernel" in ansible_facts.packages'
- '"auditd" in ansible_facts.packages'
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.3.1
- NIST-800-171-3.3.2
- NIST-800-171-3.3.6
- NIST-800-53-AC-2(g)
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-10
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-14(1)
- NIST-800-53-AU-2(d)
- NIST-800-53-AU-3
- NIST-800-53-CM-6(a)
- NIST-800-53-SI-4(23)
- PCI-DSS-Req-10.1
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- enable_strategy
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- service_auditd_enabled
Remediation script: (show)
[customizations.services]
enabled = ["auditd"]
Remediation Shell script: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | enable |
---|
# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}
' 'kernel' 2>/dev/null | grep -q installed && { dpkg-query --show --showformat='${db:Status-Status}\n' 'auditd' 2>/dev/null | grep -q installed; }; then
SYSTEMCTL_EXEC='/usr/bin/systemctl'
"$SYSTEMCTL_EXEC" unmask 'auditd.service'
"$SYSTEMCTL_EXEC" start 'auditd.service'
"$SYSTEMCTL_EXEC" enable 'auditd.service'
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation Puppet snippet: (show)
Complexity: | low |
---|
Disruption: | low |
---|
Reboot: | false |
---|
Strategy: | enable |
---|
include enable_auditd
class enable_auditd {
service {'auditd':
enable => true,
ensure => 'running',
}
}
|