From a5d87eac293b2154ebc9cf9a90f464e5b6f9c91e Mon Sep 17 00:00:00 2001 From: Robert Auch Date: Thu, 10 Jan 2019 09:49:54 -0600 Subject: [PATCH 1/2] starter perl to test the ERNW hardening documentation. --- operating_system/linux/hardening-verify.pl | 125 +++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100755 operating_system/linux/hardening-verify.pl diff --git a/operating_system/linux/hardening-verify.pl b/operating_system/linux/hardening-verify.pl new file mode 100755 index 0000000..cb5a38f --- /dev/null +++ b/operating_system/linux/hardening-verify.pl @@ -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 \(); + } +} + + + From 8e65180f913fc043acfcbee63184cce6e70262ff Mon Sep 17 00:00:00 2001 From: Robert Auch Date: Thu, 10 Jan 2019 09:58:30 -0600 Subject: [PATCH 2/2] Add notes for alternate OSes --- operating_system/linux/ERNW_Hardening_Linux.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/operating_system/linux/ERNW_Hardening_Linux.md b/operating_system/linux/ERNW_Hardening_Linux.md index 797ac11..ffdaf33 100644 --- a/operating_system/linux/ERNW_Hardening_Linux.md +++ b/operating_system/linux/ERNW_Hardening_Linux.md @@ -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 @@ -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)