lynis/include/tests_shells
hlein b595cc0fb5 Various cleanups (#363)
* Typo fix.

* Style change: always use $(), never ``.

The Lynis code already mostly used $(), but backticks were sprinkled
around.  Converted all of them.

* Lots of minor spelling/typo fixes.

FWIW these were found with:

  find . -type f -print0 | xargs -0 cat | aspell list | sort -u | egrep '^[a-z]+$' | less

And then reviewing the list to pick out things that looked like
misspelled words as opposed to variables, etc., and then manual
inspection of context to determine the intention.
2017-03-06 07:41:21 +00:00

413 lines
20 KiB
Bash

#!/bin/sh
#################################################################################
#
# Lynis
# ------------------
#
# Copyright 2007-2013, Michael Boelen
# Copyright 2007-2017, CISOfy
#
# Website : https://cisofy.com
# Blog : http://linux-audit.com
# GitHub : https://github.com/CISOfy/lynis
#
# Lynis comes with ABSOLUTELY NO WARRANTY. This is free software, and you are
# welcome to redistribute it under the terms of the GNU General Public License.
# See LICENSE file for usage of this software.
#
#################################################################################
#
# Shells
#
#################################################################################
#
IDLE_TIMEOUT=0
InsertSection "Shells"
#
#################################################################################
#
# bash
# Files (interactive login shells): /etc/profile $HOME/.bash_profile
# $HOME/.bash_login $HOME/.profile
# Files (interactive non-login shells): $HOME/.bash_rc
# csh/tcsh
# Files: /etc/csh.cshrc /etc/csh.login
# zsh
# Files: /etc/zshenv /etc/zsh/zshenv $HOME/.zshenv /etc/zprofile
# /etc/zsh/zprofile $HOME/.zprofile /etc/zshrc /etc/zsh/zshrc
# $ZDOTDIR/.zshrc /etc/zlogin /etc/zsh/zlogin
SHELL_LOGIN_FILES="/etc/csh.cshrc /etc/csh.login /etc/zshenv /etc/zsh/zshenv
/etc/zprofile /etc/zsh/zprofile /etc/zshrc /etc/zsh/zshrc
/etc/zlogin /etc/zsh/zlogin"
#
#################################################################################
#
# Test : SHLL-6202
# Description : check all console TTYs in which root user can enter single user mode without password
Register --test-no SHLL-6202 --os FreeBSD --weight L --network NO --category security --description "Check console TTYs"
if [ ${SKIPTEST} -eq 0 ]; then
LogText "Test: Checking console TTYs"
FIND=$(${EGREPBINARY} '^console' /etc/ttys | ${GREPBINARY} -v 'insecure')
if [ "${FIND}" = "" ]; then
Display --indent 2 --text "- Checking console TTYs" --result "${STATUS_OK}" --color GREEN
LogText "Result: console is secured against single user mode without password."
else
Display --indent 2 --text "- Checking console TTYs" --result "${STATUS_WARNING}" --color RED
LogText "Result: Found insecure console in /etc/ttys. Single user mode login without password allowed!"
LogText "Output /etc/ttys:"
LogText "${FIND}"
ReportWarning ${TEST_NO} "Found unprotected console in /etc/ttys"
LogText "Possible solution: Change the console line from 'secure' to 'insecure'."
fi
fi
#
#################################################################################
#
# Test : SHLL-6211
# Description : which shells are available according /etc/shells
Register --test-no SHLL-6211 --weight L --network NO --category security --description "Checking available and valid shells"
if [ ${SKIPTEST} -eq 0 ]; then
LogText "Test: Searching for /etc/shells"
if [ -f /etc/shells ]; then
LogText "Result: Found /etc/shells file"
LogText "Test: Reading available shells from /etc/shells"
SSHELLS=$(${GREPBINARY} "^/" /etc/shells)
CSSHELLS=0; CSSHELLS_ALL=0
Display --indent 2 --text "- Checking shells from /etc/shells"
for I in ${SSHELLS}; do
CSSHELLS_ALL=$((CSSHELLS_ALL + 1))
Report "available_shell[]=${I}"
# YYY add check for symlinked shells
if [ -f ${I} ]; then
LogText "Found installed shell: ${I}"
CSSHELLS=$((CSSHELLS + 1))
else
LogText "Shell ${I} not installed. Probably a dummy or non existing shell."
fi
done
Display --indent 4 --text "Result: found ${CSSHELLS_ALL} shells (valid shells: ${CSSHELLS})."
else
LogText "Result: /etc/shells not found, skipping test"
fi
fi
#
#################################################################################
#
# Test : SHLL-6220
# Description : check for idle session killing tools or settings
Register --test-no SHLL-6220 --weight L --network NO --category security --description "Checking available and valid shells"
if [ ${SKIPTEST} -eq 0 ]; then
LogText "Test: Search for session timeout tools or settings in shell"
IsRunning timeoutd
if [ ${RUNNING} -eq 1 ]; then
IDLE_TIMEOUT=1
LogText "Result: found timeoutd process to kill idle sesions"
Report="session_timeout_method=timeout daemon"
fi
IsRunning autolog
if [ ${RUNNING} -eq 1 ]; then
IDLE_TIMEOUT=1
LogText "Result: found autolog process to kill idle sesions"
Report="session_timeout_method[]=autolog"
fi
if [ -f /etc/profile ]; then
# Determine if we can find a TMOUT value
FIND=$(${GREPBINARY} 'TMOUT=' /etc/profile | ${TRBINARY} -d ' ' | ${TRBINARY} -d '\t' | ${GREPBINARY} -v "^#" | ${SEDBINARY} 's/export//' | ${SEDBINARY} 's/#.*//' | ${AWKBINARY} -F= '{ print $2 }')
# Determine if the value is exported (with export, readonly, or typeset)
FIND2=$(${GREPBINARY} '\(export\|readonly\|typeset -r\)[ \t]*TMOUT' /etc/profile | ${GREPBINARY} -v "^#" | ${SEDBINARY} 's/#.*//' | ${AWKBINARY} '{ print $1 }')
if [ ! "${FIND}" = "" ]; then
N=0; IDLE_TIMEOUT=1
for I in ${FIND}; do
LogText "Output: ${I}"
Report "session_timeout_value[]=${I}"
N=$((N + 1))
done
if [ ${N} -eq 1 ]; then
LogText "Result: found TMOUT value configured in /etc/profile"
else
LogText "Result: found several TMOUT values configured in /etc/profile"
fi
Report "session_timeout_method[]=profile"
else
LogText "Result: could not find TMOUT setting in /etc/profile"
fi
if [ ! "${FIND2}" = "" ]; then
N=0;
for I in ${FIND2}; do
LogText "Output: ${I}"
if [ "${I}" = "readonly" -o "${I}" = "typeset" ]; then
N=$((N + 1))
fi
done
if [ ${N} -gt 0 ]; then
LogText "Result: found readonly setting in /etc/profile (readonly or typeset -r)"
Report "session_timeout_set_readonly=1"
else
LogText "Result: NO readonly setting found in /etc/profile (readonly or typeset -r)"
Report "session_timeout_set_readonly=0"
fi
else
LogText "Result: could not find export, readonly or typeset -r in /etc/profile"
fi
else
LogText "Result: skip /etc/profile test, file not available on this system"
fi
if [ -d /etc/profile.d ]; then
FIND=$(ls /etc/profile.d/*.sh 2> /dev/null)
if [ ! "${FIND}" = "" ]; then
# Determine if we can find a TMOUT value
FIND=$(cat /etc/profile.d/*.sh 2> /dev/null | ${GREPBINARY} 'TMOUT=' | ${TRBINARY} -d ' ' | ${TRBINARY} -d '\t' | ${GREPBINARY} -v "^#" | ${SEDBINARY} 's/export//' | ${SEDBINARY} 's/#.*//' | ${AWKBINARY} -F= '{ print $2 }')
# Determine if the value is exported (with export, readonly, or typeset)
FIND2=$(cat /etc/profile.d/*.sh 2> /dev/null | ${GREPBINARY} '\(export\|readonly\|typeset -r\)[ \t]*TMOUT' | ${GREPBINARY} -v "^#" | ${SEDBINARY} 's/#.*//' | ${AWKBINARY} '{ print $1 }')
if [ ! "${FIND}" = "" ]; then
N=0; IDLE_TIMEOUT=1
for I in ${FIND}; do
LogText "Output: ${I}"
Report "session_timeout_value[]=${I}"
N=$((N + 1))
done
if [ ${N} -eq 1 ]; then
LogText "Result: found TMOUT value configured in one of the files in /etc/profile.d directory"
else
LogText "Result: found several TMOUT values configured in one of the files in /etc/profile.d directory"
fi
Report "session_timeout_method[]=profile"
else
LogText "Result: could not find TMOUT setting in /etc/profile.d/*.sh"
fi
# Check for readonly
if [ ! "${FIND2}" = "" ]; then
N=0;
for I in ${FIND2}; do
LogText "Output: ${I}"
if [ "${I}" = "readonly" -o "${I}" = "typeset" ]; then
N=$((N + 1))
fi
done
if [ ${N} -gt 0 ]; then
LogText "Result: found readonly setting in /etc/profile (readonly or typeset -r)"
Report "session_timeout_set_readonly=1"
else
LogText "Result: NO readonly setting found in /etc/profile (readonly or typeset -r)"
Report "session_timeout_set_readonly=0"
fi
else
LogText "Result: could not find export, readonly or typeset -r in /etc/profile"
fi
fi
else
LogText "Result: skip /etc/profile.d directory test, directory not available on this system"
fi
if [ ${IDLE_TIMEOUT} -eq 1 ]; then
Display --indent 4 --text "- Session timeout settings/tools" --result "${STATUS_FOUND}" --color GREEN
AddHP 3 3
else
Display --indent 4 --text "- Session timeout settings/tools" --result "${STATUS_NONE}" --color YELLOW
AddHP 1 3
fi
fi
#
#################################################################################
#
# Test : SHLL-6230
# Description : Check for umask values in shell configurations
SHELL_CONFIG_FILES="/etc/bashrc /etc/bash.bashrc /etc/csh.cshrc /etc/profile"
Register --test-no SHLL-6230 --weight H --network NO --category security --description "Perform umask check for shell configurations"
if [ ${SKIPTEST} -eq 0 ]; then
FOUND=0
HARDENING_POSSIBLE=0
Display --indent 2 --text "- Checking default umask values"
for FILE in ${SHELL_CONFIG_FILES}; do
FIND=""
if [ -f ${FILE} ]; then
LogText "Result: file ${FILE} exists"
FOUND=1
FIND=$(${GREPBINARY} umask ${FILE} | ${SEDBINARY} 's/^[ \t]*//g' | ${SEDBINARY} 's/#.*$//' | ${GREPBINARY} -v "^$" | ${AWKBINARY} '{ print $2 }')
if [ "${FIND}" = "" ]; then
LogText "Result: did not find umask configured in ${FILE}"
Display --indent 4 --text "- Checking default umask in ${FILE}" --result "${STATUS_NONE}" --color YELLOW
else
for UMASKVALUE in ${FIND}; do
LogText "Result: found umask ${UMASKVALUE} in ${FILE}"
case ${UMASKVALUE} in
027|0027|077|0077)
LogText "Result: umask ${UMASKVALUE} is considered a properly hardened value"
;;
*)
LogText "Result: umask ${UMASKVALUE} can be hardened "
HARDENING_POSSIBLE=1
;;
esac
done
if [ ${HARDENING_POSSIBLE} -eq 0 ]; then
Display --indent 4 --text "- Checking default umask in ${FILE}" --result "${STATUS_OK}" --color GREEN
AddHP 3 3
else
Display --indent 4 --text "- Checking default umask in ${FILE}" --result WEAK --color YELLOW
AddHP 1 3
fi
fi
else
LogText "Result: file ${FILE} not found"
fi
done
#if [ ${FOUND} -eq 1 ]; then
# if [ ${HARDENING_POSSIBLE} -eq 0 ]; then
# LogText "Result: all shell files found, contain a proper umask"
# Display --indent 4 --text "- Default umask" --result "${STATUS_OK}" --color GREEN
# fi
#fi
fi
#
#################################################################################
#
# Test : SHLL-6290
# Description : Check for Shellshock vulnerability
Register --test-no SHLL-6290 --weight H --network NO --category security --description "Perform Shellshock vulnerability tests"
if [ ${SKIPTEST} -eq 0 ]; then
FOUND=0
x=""
#Display --indent 2 --text "- Testing for Shellshock vulnerability"
LogText "Test: Check if bash is in the list of shells."
if [ -f /etc/shells ]; then
LogText "Test: checking for bash shell in /etc/shells"
FIND=$(${EGREPBINARY} '(/usr)?(/local)?/bin/bash' /etc/shells | ${GREPBINARY} -v "^#" | head -1)
else
LogText "Test: checking if bash is available via which command"
FIND=$(which bash 2> /dev/null | head -1)
fi
LogText "Result: command revealed ${FIND} as output"
if [ ! "${FIND}" = "" ]; then
if [ -x "${FIND}" -a ! -L "${FIND}" ]; then
LogText "Result: found ${FIND} as a valid shell"
CreateTempFile || ExitFatal
SHELLSHOCK_TMP="${TEMP_FILE}"
# CVE-2014-6271
LogText "Test: Check for first exploit (CVE-2014-6271)"
echo "env 'x=() { :;}; echo vulnerable' 'BASH_FUNC_x()=() { :;}; echo vulnerable' bash -c \"echo test\" 2>&1 | ${GREPBINARY} 'vulnerable'" > ${SHELLSHOCK_TMP}
VULNERABLE=$(${FIND} ${SHELLSHOCK_TMP} 2> /dev/null)
rm -f ${SHELLSHOCK_TMP}
if [ ! "${VULNERABLE}" = "" ]; then
LogText "Output: ${VULNERABLE}"
LogText "Result: Vulnerable to original shellshock (CVE-2014-6271)"
Display --indent 2 --text "- Shellshock: CVE-2014-6271 (original shellshocker)" --result "${STATUS_WARNING}" --color RED
FOUND=1
else
LogText "Result: Not vulnerable to original shellshock (CVE-2014-6271)"
#Display --indent 4 --text "- CVE-2014-6271 (original shellshocker)" --result "${STATUS_OK}" --color GREEN
fi
# CVE-2014-6277 (disabled, as this test was giving too much false positives)
# CVE-2014-6278
LogText "Test: Check for CVE-2014-6278"
echo "shellshocker='() { echo vulnerable; }' bash -c shellshocker 2>/dev/null | ${GREPBINARY} 'vulnerable'" > ${SHELLSHOCK_TMP}
VULNERABLE=$(${FIND} ${SHELLSHOCK_TMP} 2> /dev/null)
rm -f ${SHELLSHOCK_TMP}
if [ ! "${VULNERABLE}" = "" ]; then
LogText "Output: ${VULNERABLE}"
LogText "Result: Vulnerable to CVE-2014-6278"
Display --indent 2 --text "- Shellshock: CVE-2014-6278 (Florian's patch, lcamtuf bug #2)" --result "${STATUS_WARNING}" --color RED
FOUND=1
else
LogText "Result: Not vulnerable to CVE-2014-6278"
#Display --indent 4 --text "- CVE-2014-6278 (Florian's patch, lcamtuf bug #2)" --result "${STATUS_OK}" --color GREEN
fi
# CVE-2014-7169
LogText "Test: Check for taviso bug CVE-2014-7169"
echo "(cd /tmp; rm -f /tmp/echo; env X='() { (a)=>\' bash -c "echo echo nonvuln" 2>/dev/null; [[ \"\$(cat echo 2> /dev/null)\" == \"nonvuln\" ]] && echo \"vulnerable\" 2> /dev/null) | ${GREPBINARY} ' vulnerable'" > ${SHELLSHOCK_TMP}
VULNERABLE=$(${FIND} ${SHELLSHOCK_TMP} 2> /dev/null)
rm -f ${SHELLSHOCK_TMP}
if [ ! "${VULNERABLE}" = "" ]; then
LogText "Output: ${VULNERABLE}"
LogText "Result: Vulnerable to taviso bug (CVE-2014-7169)"
Display --indent 2 --text "- Shellshock: CVE-2014-7169 (taviso bug)" --result "${STATUS_WARNING}" --color RED
FOUND=1
else
LogText "Result: Not vulnerable to taviso bug (CVE-2014-7169)"
#Display --indent 4 --text "- CVE-2014-7169 (taviso bug)" --result "${STATUS_OK}" --color GREEN
fi
# CVE-2014-7186
LogText "Test: Check for CVE-2014-7186"
echo "(bash -c 'true <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF' 2>/dev/null || echo \"vulnerable\") | ${GREPBINARY} 'vulnerable'" > ${SHELLSHOCK_TMP}
VULNERABLE=$(${FIND} ${SHELLSHOCK_TMP} 2> /dev/null)
rm -f ${SHELLSHOCK_TMP}
if [ ! "${VULNERABLE}" = "" ]; then
LogText "Output: ${VULNERABLE}"
LogText "Result: Vulnerable to CVE-2014-7186"
Display --indent 2 --text "- Shellshock: CVE-2014-7186 redir_stack bug" --result "${STATUS_WARNING}" --color RED
FOUND=1
else
LogText "Result: Not vulnerable to CVE-2014-7186"
#Display --indent 4 --text "- CVE-2014-7186 redir_stack bug" --result "${STATUS_OK}" --color GREEN
fi
# CVE-2014-7187
LogText "Test: Check for CVE-2014-7187"
echo "((for x in {1..200}; do echo \"for x$x in ; do :\"; done; for x in {1..200}; do echo done; done) | bash || echo \"vulnerable\") | ${GREPBINARY} 'vulnerable'" > ${SHELLSHOCK_TMP}
VULNERABLE=$(${FIND} ${SHELLSHOCK_TMP} 2> /dev/null)
rm -f ${SHELLSHOCK_TMP}
if [ ! "${VULNERABLE}" = "" ]; then
LogText "Output: ${VULNERABLE}"
LogText "Result: Vulnerable to CVE-2014-7187"
Display --indent 2 --text "- Shellshock: CVE-2014-7187 nested loops off by one bug" --result "${STATUS_WARNING}" --color RED
FOUND=1
else
LogText "Result: Not vulnerable to CVE-2014-7187"
#Display --indent 4 --text "- CVE-2014-7187 nested loops off by one bug" --result "${STATUS_OK}" --color GREEN
fi
# CVE-2014-////
LogText "Test: Check for bug Exploit #3 - shellshocker.net (no CVE)"
echo "env X=' () { }; echo hello' bash -c 'date'| ${GREPBINARY} 'hello'" > ${SHELLSHOCK_TMP}
VULNERABLE=$(${FIND} ${SHELLSHOCK_TMP} 2> /dev/null)
rm -f ${SHELLSHOCK_TMP}
if [ ! "${VULNERABLE}" = "" ]; then
LogText "Output: ${VULNERABLE}"
LogText "Result: Vulnerable to CVE-2014-//// (exploit #3 on shellshocker.net)"
Display --indent 2 --text "- Shellshock: Exploit #3 on shellshocker.net (no CVE)" --result "${STATUS_WARNING}" --color RED
FOUND=1
else
LogText "Result: Not vulnerable to exploit #3 on shellshocker.net (no CVE)"
#Display --indent 4 --text "- Exploit#3 on shellshocker.net (no CVE)" --result "${STATUS_OK}" --color GREEN
fi
else
LogText "Result: bash binary found, but not executable, or it is symlinked"
fi
else
LogText "Result: could not find bash to be a valid shell"
fi
if [ ${FOUND} -eq 1 ]; then
ReportWarning ${TEST_NO} "System vulnerable to Shellshock (bash)"
AddHP 0 25
else
AddHP 5 5
fi
unset x
fi
#
#################################################################################
#
Report "session_timeout_enabled=${IDLE_TIMEOUT}"
WaitForKeyPress
#
#================================================================================
# Lynis - Copyright 2007-2017, CISOfy - http://cisofy.com