From 0e3dac575801dc3ce89b099e4f4889ef72730bba Mon Sep 17 00:00:00 2001 From: mboelen Date: Thu, 8 Oct 2015 22:36:20 +0200 Subject: Adding new plugin for parsing PAM configurations --- plugins/plugin_pam_phase1 | 325 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 plugins/plugin_pam_phase1 (limited to 'plugins') diff --git a/plugins/plugin_pam_phase1 b/plugins/plugin_pam_phase1 new file mode 100644 index 00000000..f271460a --- /dev/null +++ b/plugins/plugin_pam_phase1 @@ -0,0 +1,325 @@ +#!/bin/sh + +######################################################################### +# +# * DO NOT REMOVE * +#----------------------------------------------------- +# PLUGIN_AUTHOR=Michael Boelen +# PLUGIN_CATEGORY=authentication +# PLUGIN_DATE=2015-10-01 +# PLUGIN_DESC=PAM +# PLUGIN_NAME=pam +# PLUGIN_PACKAGE=all +# PLUGIN_REQUIRED_TESTS= +# PLUGIN_VERSION=1.0.0 +#----------------------------------------------------- +######################################################################### +# + PAM_DIRECTORY="/root/pam.d" + # Test : PLGN-0010 + # Description : Check PAM configuration + if [ -f /etc/pam.conf -o -d /etc/pam.d ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi + Register --test-no PLGN-0010 --preqs-met ${PREQS_MET} --weight L --network NO --description "Check PAM configuration" --progress + if [ ${SKIPTEST} -eq 0 ]; then + FOUNDPROBLEM=0 + # Check if the PAM directory structure exists + if [ -d ${PAM_DIRECTORY} ]; then + logtext "Result: /etc/pam.d exists" + FIND_FILES=`find ${PAM_DIRECTORY} -type f -print` + # First check /etc/pam.conf if it exists. + #if [ -f /etc/pam.conf ]; then FIND="/etc/pam.conf ${FIND}"; fi + for PAM_FILE in ${FIND_FILES}; do + #echo "" + #echo "* ${PAM_FILE}" + while read line; do + # Strip empty lines, commented lines, tabs, line breaks (\), then finally remove all double spaces + LINE=`echo $line | grep -v "^#" | grep -v "^$" | tr '\011' ' ' | sed 's/\\\n/ /' | sed 's/ / /g'` + if [ ! "${LINE}" = "" ]; then + PAM_SERVICE=`echo ${PAM_FILE} | awk -F/ '{ print $NF }'` + PAM_CONTROL_FLAG="-" + PAM_CONTROL_OPTIONS="-" + PAM_MODULE="-" + PAM_MODULE_OPTIONS="-" + PAM_TYPE=`echo ${LINE} | awk '{ print $1 }'` + PARSELINE=0 + case ${PAM_TYPE} in + "@include") + FILE=`echo ${LINE} | awk '{ print $2 }'` + #echo "Found @include. Including PAM configuration from file ${FILE}" + ;; + "account") + PARSELINE=1 + ;; + "auth") + PARSELINE=1 + ;; + "password") + PARSELINE=1 + ;; + "session") + PARSELINE=1 + ;; + *) + logtext "Exception: Unknown PAM type found" + ;; + esac + if [ ${PARSELINE} -eq 1 ]; then + MULTIPLE_OPTIONS=`echo ${LINE} | awk '$2 ~ /^\[/'` + if [ ! "${MULTIPLE_OPTIONS}" = "" ]; then + # Needs more parsing, depending on the options found + logtext "Result: Found brackets, indicating multiple options for control flags" + PAM_CONTROL_OPTIONS=`echo ${LINE} | sed "s/^.*\[//" | sed "s/\].*$//"` + else + PAM_CONTROL_FLAG=`echo ${LINE} | awk '{ print $2 }'` + case ${PAM_CONTROL_FLAG} in + "optional"|"required"|"requisite"|"sufficient") + logtext "Result: Found known control flag: ${PAM_CONTROL_FLAG}" + PAM_MODULE=`echo ${LINE} | awk '{ print $3 }'` + PAM_MODULE_OPTIONS=`echo ${LINE} | cut -d ' ' -f 4-` + if [ ! "${PAM_MODULE_OPTIONS}" = "" ]; then + logtext "Result: using module ${PAM_MODULE} (${PAM_CONTROL_FLAG}) with options ${PAM_MODULE_OPTIONS}" + else + PAM_MODULE_OPTIONS="-" + logtext "Result: using module ${PAM_MODULE} (${PAM_CONTROL_FLAG}) without options configured" + fi + ;; + *) + logtext "Unknown control flag found (${PAM_CONTROL_FLAG})" + ;; + esac + fi + PAM_MODULE_NAME=`echo ${PAM_MODULE} | sed 's/.so$//'` + # + # Specific PAMs are commonly seen on these platforms: + # + # FreeBSD Linux + # pam_access v + # pam_deny v v + # pam_group v + # pam_krb5 v + # pam_lastlog v + # pam_login_access v + # pam_nologin v + # pam_opie v + # pam_opieaccess v + # pam_passwdqc v + # pam_permit v + # pam_rhosts v + # pam_rootok v + # pam_securetty v + # pam_self v + # pam_ssh v + # pam_unix v + + case ${PAM_MODULE_NAME} in + pam_access) ;; + pam_cap) ;; + pam_debug | pam_deny) ;; + pam_echo| pam_env | pam_exec | pam_faildelay) ;; + pam_filter | pam_ftp) ;; + # Google Authenticator / YubiKey + # Common to find it only enabled for SSH + pam_google_authenticator | pam_yubico) + logtext "Result: found pam_google_authenticator" + if [ "${PAM_CONTROL_FLAG}" = "required" ]; then + PAM_2F_AUTH_ENABLED=1 + PAM_2F_AUTH_REQUIRED=1 + report "authentication_2f_provider[]=${PAM_MODULE_NAME}" + report "authentication_2f_service[]=${PAM_SERVICE}" + elif -o "${PAM_CONTROL_FLAG}" = "sufficient" ]; then + PAM_2F_AUTH_ENABLED=1 + report "authentication_2f_provider[]=${PAM_MODULE_NAME}" + report "authentication_2f_service[]=${PAM_SERVICE}" + else + logtext "exception: found 2F authenticator enabled with uncommon control flag: ${PAM_CONTROL_FLAG}" + fi + ;; + pam_group) ;; + pam_issue) ;; + pam_keyinit | pam_krb5) ;; + pam_lastlog | pam_limits) ;; + # Log UID for auditd + pam_loginuid) + PAM_LOGINUID_FOUND=1 + ;; + pam_listfile | pam_localuser) ;; + pam_mail | pam_mkhomedir | pam_motd) ;; + pam_namespace | pam_nologin) ;; + pam_permit) ;; + pam_rootok) ;; + pam_rhosts) ;; + pam_securetty) ;; + pam_self) ;; + pam_shells) ;; + pam_stress | pam_succeed_if | pam_systemd) ;; + pam_time | pam_timestamp) ;; + pam_umask) ;; + # Password history + # Can be configured via pam_unix or pam_pwhistory + pam_unix | pam_pwhistory) + logtext "Result: found ${PAM_MODULE} module (generic)" + if [ ! "${PAM_MODULE_OPTIONS}" = "" ]; then + for I in ${PAM_MODULE_OPTIONS}; do + OPTION=`echo ${PAM_FILE} | awk -F= '{ print $1 }'` + VALUE=`echo ${PAM_FILE} | awk -F= '{ print $2 }'` + CREDITS_CONFIGURED=0 + case ${OPTION} in + # pam_pwhistory / pam_unix + remember) + # Minimum length (remove 1 if credits are configured, at later stage in function) + logtext "Result: password history configured" + DigitsOnly ${VALUE} + PAM_PASSWORD_HISTORY_AMOUNT=${VALUE} + PAM_PASSWORD_HISTORY_ENABLED=1 + Debug "Found password history enabled with module ${PAM_MODULE_NAME} and password amount ${PAM_PASSWORD_HISTORY_AMOUNT}" + ;; + esac + done + fi + ;; + pam_unix_acct| pam_unix_auth | pam_unix_passwd | pam_unix_session | pam_unix2) ;; + pam_vbox) ;; + pam_warn | pam_wheel) ;; + pam_xauth) ;; + + # Password strength testing + pam_cracklib | pam_pwquality) + logtext "Result: found module ${PAM_MODULE} for password strength testing" + PAM_MODULE_PASSWORD_STRENGTH_TESTED=1 + if [ ! "${PAM_MODULE_OPTIONS}" = "" ]; then + for I in ${PAM_MODULE_OPTIONS}; do + OPTION=`echo ${PAM_FILE} | awk -F= '{ print $1 }'` + VALUE=`echo ${PAM_FILE} | awk -F= '{ print $2 }'` + CREDITS_CONFIGURED=0 + case ${OPTION} in + minlen) + # Minimum length (remove 1 if credits are configured, at later stage in function) + logtext "Result: minlen configured" + DigitsOnly ${VALUE} + MIN_PASSWORD_LENGTH=${VALUE} + ;; + dccredit) + # Digits only + DigitsOnly ${VALUE} + # Digital characters + if [ ${VALUE} -gt 0 ]; then CREDITS_CONFIGURED=1; fi + ;; + lccredit) + # Digits only + DigitsOnly ${VALUE} + # Lowercase characters + if [ ${VALUE} -gt 0 ]; then CREDITS_CONFIGURED=1; fi + ;; + occredit) + # Digits only + DigitsOnly ${VALUE} + # Other characters + if [ ${VALUE} -gt 0 ]; then CREDITS_CONFIGURED=1; fi + ;; + uccredit) + # Digits only + DigitsOnly ${VALUE} + # Uppercase characters + if [ ${VALUE} -gt 0 ]; then CREDITS_CONFIGURED=1; fi + ;; + esac + if [ ${CREDITS_CONFIGURED} -eq 1 ]; then + logtext "Result: Credits are configured, password length minus 1" + MIN_PASSWORD_LENGTH=`expr ${MIN_PASSWORD_LENGTH} - 1` + fi + done + fi + ;; + + pam_tally | pam_tally2) + if [ "${PAM_CONTROL_FLAG}" = "required" ]; then + logtext "Result: found a required module for countering brute force cracking attempts" + report "pam_auth_brute_force_protection_module[]=${PAM_MODULE_NAME}" + PAM_AUTH_BRUTE_FORCE_PROTECTION=1 + fi + if [ ! "${PAM_MODULE_OPTIONS}" = "" ]; then + for I in ${PAM_MODULE_OPTIONS}; do + OPTION=`echo ${PAM_FILE} | awk -F= '{ print $1 }'` + VALUE=`echo ${PAM_FILE} | awk -F= '{ print $2 }'` + case ${OPTION} in + deny) + AUTH_BLOCK_BAD_LOGIN_ATTEMPTS="${VALUE}" + ;; + unlock_time) + AUTH_UNLOCK_TIME="${VALUE}" + ;; + esac + done + fi + ;; + *) + logtext "Result: found pluggable authentication module ${PAM_MODULE}, which is unknown" + ;; + esac + fi + Debug "Service: ${PAM_SERVICE}" + Debug "Type: ${PAM_TYPE}" + Debug "Control: ${PAM_CONTROL_FLAG}" + Debug "Control options: ${PAM_CONTROL_OPTIONS}" + Debug "Module: ${PAM_MODULE_NAME}" + Debug "Module options: ${PAM_MODULE_OPTIONS}" + fi + done < ${PAM_FILE} + #ParsePAMLine ${J} + #StoreSetting "pam" " + done + fi + fi +# +################################################################################# +# + +# /etc/security/opasswd should exist when: +# password history is enabled via pam_unix +# pam_cracklib or pam_pwquality is used +# In that case, the file should be owned by root, with 440/640/660 permissions + +logtext "[PAM] PAM 2F authentication enabled: ${PAM_2F_AUTH_ENABLED}" +report "authentication_two_factor_enabled=${PAM_2F_AUTH_ENABLED}" + +logtext "[PAM] PAM 2F authentication required: ${PAM_2F_AUTH_REQUIRED}" +report "authentication_two_factor_required=${PAM_2F_AUTH_ENABLED}" + +if [ ! "${AUTH_UNLOCK_TIME}" = "" ]; then + logtext "[PAM] Authentication unlock time: ${AUTH_UNLOCK_TIME}" + report "authentication_unlock_time=${AUTH_UNLOCK_TIME}" + else + logtext "[PAM] Authentication unlock time: not configured" +fi + +logtext "[PAM] Password strength testing enabled: ${PAM_PASSWORD_STRENGTH_TESTED}" + +if [ ${PAM_PASSWORD_STRENGTH_TESTED} -eq 1 ]; then + report "password_strength_tested=1" +fi + +logtext "[PAM] Password brute force protection: ${PAM_AUTH_BRUTE_FORCE_PROTECTION}" + +if [ ${PAM_AUTH_BRUTE_FORCE_PROTECTION} -eq 1 ]; then + report "authentication_brute_force_protection=1" +fi + +if [ ! "${MIN_PASSWORD_LENGTH}" = "" ]; then + logtext "[PAM] Minimum password length: ${MIN_PASSWORD_LENGTH}" + report "minimum_password_length=${MIN_PASSWORD_LENGTH}" + else + logtext "[PAM] Minimum password length: not configured" +fi + +# If auditd is running, but pam_loginuid not, events might not be properly logged +if [ ${AUDITD_RUNNING} -eq 1 ]; then + if [ ${PAM_LOGINUID_FOUND} -eq 0 ]; then + report "pam_issue[]=pam_loginuid is missing" + fi +fi + +logtext "[PAM] Password history enabled: ${PAM_PASSWORD_HISTORY_ENABLED}" +logtext "[PAM] Password history amount: ${PAM_PASSWORD_HISTORY_AMOUNT}" + + +#EOF -- cgit v1.2.3