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

Update PAM configurations for RPM-based distros and initial test script #8

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
10 changes: 8 additions & 2 deletions operating_system/linux/ERNW_Hardening_Linux.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ upper case =1
number = 1
passwords to remember (password history) = 5
```
To enforce this policy, add the following lines to the file **/etc/pam.d/common-password**:
To enforce this policy, add the following lines to the file:
Debian/Ubuntu: **/etc/pam.d/common-password**:
Red Hat 6+ / CentOS 6+/ SuSE: **/etc/pam.d/password-auth-ac**:
Solaris 8-10 /AIX 6+: **/etc/pam.conf** (Has service name as additional first field):
```
password required pam_cracklib.so dcredit=-1 ucredit=-1 lcredit=-1 minlen=8 retry=5
password required pam_pwhistory.so use_authtok remember=3 retry=5
Expand All @@ -101,13 +104,16 @@ password required pam_unix2.so use_authtok
---

## Configure Account Lockout Policies (Mandatory)
The file **/etc/pam.d/common-auth** is used for configuring account lockout policies. We present below example lockout policies, that is, example entries in the **common-auth** file:
The file PAM Auth **/etc/pam.d/common-auth** is used for configuring account lockout policies. We present below example lockout policies, that is, example entries in the **common-auth** file:
Debian/Ubuntu: **/etc/pam.d/common-auth**
Red Hat 6+ / CentOS 6+ / SuSE: **/etc/pam.d/password-auth-ac**:
```
auth required pam_tally.so onerr=fail no_magic_root unlock_time=180
account required pam_tally.so per_user deny=5 no_magic_root reset
```
The first entry configures the system to count failed logins, or failed **su** attempts, on a user basis and sets the account lock timer to 30 minutes. The second entry configures the system to lock accounts after 5 failed logins, or failed **su** attempts (see the "deny" parameter).

pam_tally2.so, and pam_faillock.so also implement this feature.
---

## Enable Password Aging (Mandatory)
Expand Down
125 changes: 125 additions & 0 deletions operating_system/linux/hardening-verify.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#!/usr/bin/env perl

use strict;
use warnings;
use Carp;

my %tests=();
my $debug=0;
# each test will have a shell to run under, a command to run, and an expected output.
# If the command, run under the shell, does not produce the expected output
# then the test fails.

$tests{AdminAccounts}={
'type' => "file",
'file' => "/etc/passwd",
'split' => ":",
'field' => 3,
'search' => '^0$',
'returnfield' => '0',
'returnmatch' => ["root"],
};
$tests{ShadowPasswords}={
'type' => "file",
'file' => "/etc/passwd",
'split' => ":",
'field' => 1,
'search' => '^[^x]+$',
'returnfield' => '0',
'returnmatch' => [],
};
$tests{StrongHash}={
'type' => "file",
'file' => "/etc/login.defs",
'split' => '\s+',
'field' => 1,
'search' => "(DES|MD5)",
'returnfield' => '0',
'returnmatch' => [],
};
my $pampasswdfile = "/doesnotexist";
my $pamauthfile = "/doesnotexist";
$pampasswdfile = "/etc/pam.d/password-auth-ac" if (-f "/etc/pam.d/password-auth-ac");
$pampasswdfile = "/etc/pam.d/common-password" if (-f "/etc/pam.d/common-password");
$pamauthfile = "/etc/pam.d/password-auth-ac" if (-f "/etc/pam.d/password-auth-ac");
$pamauthfile = "/etc/pam.d/common-auth" if (-f "/etc/pam.d/common-auth");
$tests{StrongPasswordPolicy}={
'type' => "file",
'file' => $pampasswdfile,
'split' => '\s+',
'field' => '2',
'search' => '(pam_cracklib|pam_pwhistory|pam_pwcheck)',
'returnfield' => '2',
'returnmatch' => [".*"],
};

$tests{AccountLockoutPolicies}={
'type' => "file",
'file' => $pamauthfile,
'split' => '\s+',
'field' => '2',
'search' => '(pam_tally|pam_faillock)',
'returnfield' => '2',
'returnmatch' => [".*"],
};
foreach my $test (keys(%tests)) {
if ($tests{$test}->{'type'} eq "file") {
$debug && print("Testing file $tests{$test}->{'file'} for $tests{$test}->{'search'}.\n");
my $result=testfile($tests{$test});
if (ref($result) eq "ARRAY") {
if (@$result ne @{$tests{$test}->{'returnmatch'}}) {
print "Test $test failed with result: \n";
print join(" ", @$result), "\n";
} else {
print "Test $test passed.\n";
}
} elsif (ref($result) eq "HASH") {
print "DO NOT HANDLE HASH RETURN YET!\n";
} else {
print "DO NOT HANDLE RETURN TYPE: ".ref($result)." yet!!\n";
}
}
}

sub testfile {
my $test=shift;
my $file=$test->{'file'};
my $split=$test->{'split'};
my $field=$test->{'field'};
my $search=$test->{'search'};
my $return=$test->{'returnfield'};
my $match=$test->{'returnmatch'};
open(my $fh, "<", "$file") or die "Can't read $file!";
if (not defined($search) or ($search eq "")) {
confess("Passed an invalid search parameter!!");
}
my @result=();
while (<$fh>) {
next if ($_=~/^[\s]*[#;]/); #skip comment lines
next if ($_=~/^[\s]*$/); #skip blank lines
my @fields=split(/$split/, $_);
if (defined($fields[$field])) {
if ($fields[$field]=~/$search/) {
push(@result, $fields[$return])
} else {
$debug && print("Field $field does not match '$search'\n");
}
} else {
$debug && print ("Field $field is empty: $_");
if ($search) {
# then we have an undefined field, and an expectation of a match, so this is a failure
push(@result, $fields[$return]);
} else {
$debug && print ("empty field is ok.\n");
}
}
}
if (@result ne $match) {
return \@result;
} else {
return \();
}
}