Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ubuntu 24.04: Implement rule 5.3.2.2 Ensure pam_faillock module is enabled #12779

Merged
merged 3 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions components/pam.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ rules:
- accounts_passwords_pam_faillock_interval
- accounts_passwords_pam_faillock_silent
- accounts_passwords_pam_faillock_unlock_time
- accounts_passwords_pam_faillock_enabled
- accounts_passwords_pam_tally2
- accounts_passwords_pam_tally2_deny_root
- accounts_passwords_pam_tally2_unlock_time
Expand Down
5 changes: 3 additions & 2 deletions controls/cis_ubuntu2404.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1863,8 +1863,9 @@ controls:
levels:
- l1_server
- l1_workstation
status: planned
notes: TODO. Rule does not seem to be implemented, nor does it map to any rules in ubuntu2204 profile.
rules:
- accounts_passwords_pam_faillock_enabled
status: automated

- id: 5.3.2.3
title: Ensure pam_pwquality module is enabled (Automated)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# platform = multi_platform_ubuntu

{{{ bash_pam_faillock_enable() }}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<def-group>
<definition class="compliance" id="{{{ rule_id }}}" version="6">
{{{ oval_metadata(description) }}}
<criteria operator="AND" comment="Check the proper configuration of pam_faillock.so">
<!-- pam_unix.so is a control module present in all realistic scenarios and also used
as reference for the correct position of pam_faillock.so in auth section. If the
system is properly configured, it must appear only once in auth section. -->
<criterion test_ref="test_accounts_passwords_pam_faillock_common_pam_unix_auth"
comment="pam_unix.so appears only once in auth section of common-auth"/>
<criterion test_ref="test_accounts_passwords_pam_faillock_common_pam_faillock_auth"
comment="pam_faillock.so is properly defined in auth section of common-auth"/>
<criterion test_ref="test_accounts_passwords_pam_faillock_common_pam_faillock_account"
comment="pam_faillock.so is properly defined in common-account"/>
</criteria>
</definition>

<!-- The following tests demand complex regex which are necessary more than once.
These variables make simpler the usage of regex patterns. -->
<constant_variable id="var_accounts_passwords_pam_faillock_pam_unix_regex"
datatype="string" version="2"
comment="regex to identify pam_unix.so in auth section of pam files">
<value>^\s*auth\N+pam_unix\.so</value>
</constant_variable>

<constant_variable
id="var_accounts_passwords_pam_faillock_pam_faillock_auth_regex"
datatype="string" version="2"
comment="regex to identify pam_faillock.so entries in auth section of pam files">
{{% if 'debian' in product %}}
<value>^\s*auth\s+required\s+pam_faillock\.so.*preauth.*[\s\S]*^\s*auth.*pam_unix\.so[\s\S]*^\s*auth\s+\[default=die\]\s+pam_faillock\.so\s+authfail[\s\S]*^\s*auth\s+sufficient\s+pam_faillock\.so\s+authsucc</value>
{{% elif 'ubuntu' in product %}}
<value>^\s*auth\s+(requisite|required)\s+pam_faillock\.so.*preauth.*[\s\S]*^\s*auth.*pam_unix\.so[\s\S]*^\s*auth\s+\[default=die\]\s+pam_faillock\.so\s+authfail</value>
{{% elif 'openeuler' in product or 'kylinserver' in product %}}
<value>^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)?(?=.*?\bnew_authtok_reqd=ok\b)?(?=.*?\bignore=ignore\b)?(?=.*?\bdefault=bad\b)?.*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)?(?=.*?\bnew_authtok_reqd=done\b)?(?=.*?\bdefault=ignore\b)?.*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)?(?=.*?\bnew_authtok_reqd=ok\b)?(?=.*?\bignore=ignore\b)?(?=.*?\bdefault=die\b)?.*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail</value>
{{% else %}}
<value>^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail</value>
{{% endif %}}
</constant_variable>

<constant_variable
id="var_accounts_passwords_pam_faillock_pam_faillock_account_regex"
datatype="string" version="2"
comment="regex to identify pam_faillock.so entry in account section of pam files">
{{% if 'debian' in product or 'ubuntu' in product %}}
<value>^\s*account\s+required\s+pam_faillock\.so\s*(#.*)?$</value>
{{% elif 'openeuler' in product or 'kylinserver' in product %}}
<value>^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)?(?=.*?\bnew_authtok_reqd=ok\b)?(?=.*?\bignore=ignore\b)?(?=.*?\bdefault=bad\b)?.*\])[\s]+pam_unix\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)?(?=.*?\bnew_authtok_reqd=ok\b)?(?=.*?\bignore=ignore\b)?(?=.*?\bdefault=bad\b)?.*\])[\s]+pam_faillock\.so</value>
{{% else %}}
<value>^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so</value>
{{% endif %}}
</constant_variable>

{{% macro generate_test_faillock_enabled(file_stem) %}}
<!-- Check occurences of pam_unix.so in auth section of {{{ file_stem }}}-auth file -->
<ind:textfilecontent54_test
check="all" check_existence="none_exist" version="2"
id="test_accounts_passwords_pam_faillock_{{{ file_stem }}}_pam_unix_auth"
comment="no more that one pam_unix.so is expected in auth section of {{{ file_stem }}}-auth">
<ind:object object_ref="object_accounts_passwords_pam_faillock_{{{ file_stem }}}_pam_unix_auth"/>
</ind:textfilecontent54_test>

<ind:textfilecontent54_object
version="2"
id="object_accounts_passwords_pam_faillock_{{{ file_stem }}}_pam_unix_auth"
comment="Get the second and subsequent occurrences of pam_unix.so in auth section of {{{ file_stem}}}-auth">
<ind:filepath>/etc/pam.d/{{{file_stem}}}-auth</ind:filepath>
<ind:pattern operation="pattern match" var_ref="var_accounts_passwords_pam_faillock_pam_unix_regex"/>
<ind:instance datatype="int" operation="greater than">1</ind:instance>
</ind:textfilecontent54_object>

<!-- Check common definition of pam_faillock.so in {{{ file_stem }}}-auth file -->
<ind:textfilecontent54_test
check="all" check_existence="only_one_exists" version="2"
id="test_accounts_passwords_pam_faillock_{{{ file_stem }}}_pam_faillock_auth"
comment="One and only one occurrence is expected in auth section of {{{ file_stem }}}-auth">
<ind:object
object_ref="object_accounts_passwords_pam_faillock_{{{ file_stem }}}_pam_faillock_auth"/>
</ind:textfilecontent54_test>

<ind:textfilecontent54_object
version="2"
id="object_accounts_passwords_pam_faillock_{{{ file_stem }}}_pam_faillock_auth"
comment="Check common definition of pam_faillock.so in auth section of common-auth">
<ind:filepath>/etc/pam.d/{{{ file_stem }}}-auth</ind:filepath>
<ind:pattern operation="pattern match"
var_ref="var_accounts_passwords_pam_faillock_pam_faillock_auth_regex"/>
<ind:instance datatype="int" operation="equals">1</ind:instance>
</ind:textfilecontent54_object>
{{% endmacro %}}

{{{ generate_test_faillock_enabled (file_stem="common") }}}

{{% macro generate_test_faillock_account(file_stem, file) %}}
<!-- Check common definition of pam_faillock.so in {{{ file_stem }}}-account -->
<ind:textfilecontent54_test
check="all" check_existence="only_one_exists" version="2"
id="test_accounts_passwords_pam_faillock_{{{ file_stem }}}_pam_faillock_account"
comment="One and only one occurrence is expected in {{{ file }}}">
<ind:object
object_ref="object_accounts_passwords_pam_faillock_{{{ file_stem }}}_pam_faillock_account"/>
</ind:textfilecontent54_test>

<ind:textfilecontent54_object
version="2"
id="object_accounts_passwords_pam_faillock_{{{ file_stem }}}_pam_faillock_account"
comment="Check common definition of pam_faillock.so in account section of {{{ file }}}">
<ind:filepath>/etc/pam.d/{{{ file }}}</ind:filepath>
<ind:pattern operation="pattern match"
var_ref="var_accounts_passwords_pam_faillock_pam_faillock_account_regex"/>
<ind:instance datatype="int" operation="equals">1</ind:instance>
</ind:textfilecontent54_object>
{{% endmacro %}}

{{{ generate_test_faillock_account (file_stem="common", file="common-account") }}}

</def-group>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
documentation_complete: true


title: 'Ensure pam_faillock module is enabled'

description: |-
The <tt>pam_faillock.so</tt> module maintains a list of failed authentication attempts per
user during a specified interval and locks the account in case there were more than the
configured number of consecutive failed authentications (this is defined by the <tt>deny</tt>
parameter in the faillock configuration). It stores the failure records into per-user files in
the tally directory.

rationale: |-
Locking out user IDs after n unsuccessful consecutive login attempts mitigates brute
force password attacks against your systems.

severity: medium

platform: package[pam]
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash
# platform = multi_platform_ubuntu
# packages = pam

echo 'auth requisite pam_faillock.so preauth' >> /etc/pam.d/common-auth
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash
# platform = multi_platform_ubuntu
# packages = pam

{{{ bash_enable_pam_faillock_directly_in_pam_files() }}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash
# platform = multi_platform_ubuntu

{{{ bash_enable_pam_faillock_directly_in_pam_files() }}}

echo > /etc/security/faillock.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash
# platform = multi_platform_ubuntu
# packages = pam

sed '/pam_faillock.so/d' /etc/pam.d/common-auth
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/bin/bash
# platform = multi_platform_ubuntu
# packages = pam

# Multiple instances of pam_unix.so in auth section may, intentionally or not, interfere
# in the expected behaviour of pam_faillock.so. Remediation does not solve this automatically
# in order to preserve intentional changes.
cat << EOF > /usr/share/pam-configs/tmp_unix
Name: Unix authentication
Default: yes
Priority: 257
Auth-Type: Primary
Auth:
[success=end default=ignore] pam_unix.so nullok try_first_pass
Auth-Initial:
[success=end default=ignore] pam_unix.so nullok
Account-Type: Primary
Account:
[success=end new_authtok_reqd=done default=ignore] pam_unix.so
Account-Initial:
[success=end new_authtok_reqd=done default=ignore] pam_unix.so
Session-Type: Additional
Session:
required pam_unix.so
Session-Initial:
required pam_unix.so
Password-Type: Primary
Password:
[success=end default=ignore] pam_unix.so obscure use_authtok try_first_pass yescrypt
Password-Initial:
[success=end default=ignore] pam_unix.so obscure yescrypt
auth sufficient pam_unix.so
EOF
DEBIAN_FRONTEND=noninteractive pam-auth-update

rm -f /usr/share/pam-configs/tmp_unix
Loading