mirror of
https://github.com/CISOfy/lynis.git
synced 2026-03-11 08:55:28 +00:00
* 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.
413 lines
20 KiB
Bash
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
|