#!/bin/sh ################################################################################# # # Lynis # ------------------ # # Copyright 2007-2013, Michael Boelen # Copyright 2007-2021, 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. # ################################################################################# # # Scheduled tasks # ################################################################################# # InsertSection "${SECTION_SCHEDULED_TASKS}" # ################################################################################# # ATD_RUNNING=0 CROND_RUNNING=0 # ################################################################################# # # Test : SCHD-7702 # Description : Check cron daemon Register --test-no SCHD-7702 --weight L --network NO --category security --description "Check status of cron daemon" if [ ${SKIPTEST} -eq 0 ]; then FIND=$(${PSBINARY} aux | ${GREPBINARY} -E "( cron$|/cron(d)? )") if IsEmpty "${FIND}"; then LogText "Result: no cron daemon found" else LogText "Result: cron daemon running" CROND_RUNNING=1 Report "crond_running=1" Report "scheduler[]=crond" fi fi # ################################################################################# # # Test : SCHD-7704 # Description : Check crontab / cronjobs Register --test-no SCHD-7704 --weight L --network NO --category security --description "Check crontab/cronjobs" if [ ${SKIPTEST} -eq 0 ]; then BAD_FILE_PERMISSIONS=0 BAD_FILE_OWNERSHIP=0 FindCronJob() { sCRONJOBS=$(${GREPBINARY} -E '^([0-9*])' $1 | ${TRBINARY} '\t' ' ' | ${TRBINARY} -s ' ' | ${TRBINARY} ' ' ',' | ${SORTBINARY}) } CRONTAB_FILE="${ROOTDIR}etc/crontab" if [ -f ${CRONTAB_FILE} ]; then ${GREPBINARY} -E -q -s 'lynis audit system' ${CRONTAB_FILE} && LYNIS_CRONJOB="file:/etc/crontab" if IsWorldWritable ${CRONTAB_FILE}; then LogText "Result: insecure file permissions for cronjob file ${CRONTAB_FILE}"; Report "insecure_fileperms_cronjob[]=${CRONTAB_FILE}"; BAD_FILE_PERMISSIONS=1; AddHP 0 5; fi if ! IsOwnedByRoot ${CRONTAB_FILE}; then LogText "Result: incorrect owner found for cronjob file ${CRONTAB_FILE}"; Report "bad_fileowner_cronjob[]=${CRONTAB_FILE}"; BAD_FILE_OWNERSHIP=1; AddHP 0 5; fi FindCronJob ${CRONTAB_FILE} for ITEM in ${sCRONJOBS}; do LogText "Found cronjob (${CRONTAB_FILE}): ${ITEM}" Report "cronjob[]=${ITEM}" done fi CRON_DIRS="${ROOTDIR}etc/cron.d" for DIR in ${CRON_DIRS}; do LogText "Test: checking directory ${DIR}" if [ -d ${DIR} ]; then if FileIsReadable ${DIR}; then LogText "Result: found directory ${DIR}" LogText "Test: searching files in ${DIR}" FIND=$(${FINDBINARY} -L ${DIR} -type f -print | ${GREPBINARY} -v ".placeholder") if IsEmpty "${FIND}"; then LogText "Result: no files found in ${DIR}" else LogText "Result: found one or more files in ${DIR}. Analyzing files.." for FILE in ${FIND}; do if IsWorldWritable ${FILE}; then LogText "Result: insecure file permissions for cronjob file ${J}"; Report "insecure_fileperms_cronjob[]=${J}"; BAD_FILE_PERMISSIONS=1; AddHP 0 5; fi if ! IsOwnedByRoot ${FILE}; then LogText "Result: incorrect owner found for cronjob file ${J}"; Report "bad_fileowner_cronjob[]=${J}"; BAD_FILE_OWNERSHIP=1; AddHP 0 5; fi FILENAME=$(echo ${FILE} | ${AWKBINARY} -F/ '{print $NF}') if [ "${FILENAME}" = "lynis" ]; then ${GREPBINARY} -E -q -s 'lynis audit system' ${CRONTAB_FILE} && LYNIS_CRONJOB="file:${FILE}"; fi FindCronJob ${FILE} if HasData "${sCRONJOBS}"; then for K in ${sCRONJOBS}; do LogText "Result: Found cronjob (${FILE}): ${K}" Report "cronjob[]=${FILE}" done fi done LogText "Result: done with analyzing files in ${DIR}" fi else LogText "Result: can not read file or directory ${DIR}" fi else LogText "Result: directory ${DIR} does not exist" fi done CRON_DIRS="${ROOTDIR}etc/cron.hourly ${ROOTDIR}etc/cron.daily ${ROOTDIR}etc/cron.weekly ${ROOTDIR}etc/cron.monthly" for I in ${CRON_DIRS}; do LogText "Test: checking directory ${I}" if [ -d ${I} ]; then LogText "Result: found directory ${I}" if FileIsReadable ${I}; then LogText "Test: searching files in ${I}" FIND=$(${FINDBINARY} -L ${I} -type f -print 2> /dev/null | ${GREPBINARY} -v ".placeholder") if [ -z "${FIND}" ]; then LogText "Result: no files found in ${I}" else LogText "Result: found one or more files in ${I}. Analyzing files.." for FILE in ${FIND}; do if IsWorldWritable ${FILE}; then LogText "Result: insecure file permissions for cronjob file ${FILE}"; Report "insecure_fileperms_cronjob[]=${FILE}"; BAD_FILE_PERMISSIONS=1; AddHP 0 5; fi if ! IsOwnedByRoot ${FILE}; then LogText "Result: incorrect owner found for cronjob file ${FILE}"; Report "bad_fileowner_cronjob[]=${FILE}"; BAD_FILE_OWNERSHIP=1; AddHP 0 5; fi FILENAME=$(echo ${FILE} | ${AWKBINARY} -F/ '{print $NF}') if [ "${FILENAME}" = "lynis" ]; then ${GREPBINARY} -E -q -s 'lynis audit system' ${CRONTAB_FILE} && LYNIS_CRONJOB="file:${FILE}"; fi LogText "Result: Found cronjob (${I}): ${FILE}" Report "cronjob[]=${FILE}" done LogText "Result: done with analyzing files in ${I}" fi else LogText "Result: directory permissions are too strict to enter it (which might be good)" fi else LogText "Result: directory ${I} does not exist" fi done # /var/spool/cron/* and /var/spool/cron/crontabs/* # Search only in one tree, to avoid searching the tree twice if [ -d /var/spool/cron/crontabs ]; then FIND=$(${FINDBINARY} /var/spool/cron/crontabs -xdev -type f -print 2> /dev/null) for I in ${FIND}; do if FileIsReadable ${I}; then ${GREPBINARY} -E -q -s 'lynis audit system' ${I} && LYNIS_CRONJOB="file:${I}" FindCronJob ${I} for FILE in ${sCRONJOBS}; do LogText "Found cronjob (/var/spool/cron/crontabs): ${I} (${FILE})" Report "cronjob[]=${I}" done fi done else if [ -d ${ROOTDIR}var/spool/cron ]; then FIND=$(find ${ROOTDIR}var/spool/cron -type f -print) for I in ${FIND}; do if FileIsReadable ${I}; then ${GREPBINARY} -E -q -s 'lynis audit system' ${I} && LYNIS_CRONJOB="file:${I}" FindCronJob ${I} for FILE in ${sCRONJOBS}; do LogText "Found cronjob in ${ROOTDIR}var/spool/cron: ${I} (${FILE})" LogText "cronjob[]=${I}" done fi done fi fi # Anacron if [ "${OS}" = "Linux" ]; then if [ -f /etc/anacrontab ]; then LogText "Test: checking anacrontab" sANACRONJOBS=$(${GREPBINARY} -E '^([0-9@])' /etc/anacrontab | ${TRBINARY} '\t' ' ' | ${TRBINARY} -s ' ' | ${TRBINARY} ' ' ',' | ${SORTBINARY}) if [ -n "${sANACRONJOBS}" ]; then Report "scheduler[]=anacron" for I in ${sANACRONJOBS}; do LogText "Found anacron job (/etc/anacrontab): ${I}" Report "cronjob[]=${I}" done fi fi fi # Show warning when an issue shows up. Even if *both* the permissions and ownership are wrong, just show one (prevent overload of warnings). if [ ${BAD_FILE_PERMISSIONS} -eq 1 ]; then ReportWarning "${TEST_NO}" "Found one or more cronjob files with incorrect file permissions (see log for details)" Display --indent 2 --text "- Checking crontab and cronjobs files" --result "${STATUS_WARNING}" --color RED elif [ ${BAD_FILE_OWNERSHIP} -eq 1 ]; then ReportWarning "${TEST_NO}" "Found one or more cronjob files with incorrect ownership (see log for details)" Display --indent 2 --text "- Checking crontab and cronjob files" --result "${STATUS_WARNING}" --color RED else Display --indent 2 --text "- Checking crontab and cronjob files" --result "${STATUS_DONE}" --color GREEN fi fi # ################################################################################# # # Test : SCHD-7718 # Description : Check atd status Register --test-no SCHD-7718 --weight L --network NO --category security --description "Check at users" if [ ${SKIPTEST} -eq 0 ]; then LogText "Test: Checking atd status" FIND=$(${PSBINARY} ax | ${GREPBINARY} "/atd" | ${GREPBINARY} -v "grep") if [ -n "${FIND}" ]; then LogText "Result: at daemon active" Display --indent 2 --text "- Checking atd status" --result "${STATUS_RUNNING}" --color GREEN ATD_RUNNING=1 Report "scheduler[]=atd" else LogText "Result: at daemon not active" if IsVerbose; then Display --indent 2 --text "- Checking atd status" --result "${STATUS_NOT_RUNNING}" --color WHITE; fi fi fi # ################################################################################# # # Test : SCHD-7720 # Description : Check at users # Notes : if at.allow exists, only users listed can schedule at jobs # if at.allow does not exist, but at.deny does, everyone # except the listed ones can schedule jobs. If both can't be # found, only root can schedule jobs. if [ ${ATD_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi Register --test-no SCHD-7720 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check at users" if [ ${SKIPTEST} -eq 0 ]; then AT_UNKNOWN=0 case ${OS} in FreeBSD) AT_ALLOW="${ROOTDIR}var/at/at.allow"; AT_DENY="${ROOTDIR}var/at/at.deny" ;; HPUX) AT_ALLOW="${ROOTDIR}usr/lib/cron/at.allow"; AT_DENY="${ROOTDIR}usr/lib/cron/at.deny" ;; Linux) AT_ALLOW="${ROOTDIR}etc/at.allow"; AT_DENY="${ROOTDIR}etc/at.deny" ;; OpenBSD) AT_ALLOW="${ROOTDIR}var/cron/at.allow"; AT_DENY="${ROOTDIR}var/cron/at.deny" ;; SunOS) AT_ALLOW="${ROOTDIR}etc/cron.d/at.allow"; AT_DENY="${ROOTDIR}etc/cron.d/at.deny" ;; *) AT_UNKNOWN=1; LogText "Test skipped, files for at unknown" ;; esac if [ ${AT_UNKNOWN} -eq 0 ]; then LogText "Test: checking for file ${AT_ALLOW}" if [ -f ${AT_ALLOW} ]; then FileIsReadable ${AT_ALLOW} if [ ${CANREAD} -eq 1 ]; then LogText "Result: file ${AT_ALLOW} exists, only listed users can schedule at jobs" FIND=$(${SORTBINARY} ${AT_ALLOW}) if IsEmpty "${FIND}"; then LogText "Result: File empty, no users are allowed to schedule at jobs" else for ITEM in ${FIND}; do LogText "Allowed at user: ${ITEM}" done fi else LogText "Result: can not read ${AT_ALLOW} (no permission)" fi else LogText "Result: file ${AT_ALLOW} does not exist" LogText "Test: checking for file ${AT_DENY}" if [ -f ${AT_DENY} ]; then FileIsReadable ${AT_DENY} if [ ${CANREAD} -eq 1 ]; then LogText "Result: file ${AT_DENY} exists, only non listed users can schedule at jobs" FIND=$(${SORTBINARY} ${AT_DENY}) if [ -z "${FIND}" ]; then LogText "Result: file is empty, no users are denied access to schedule jobs" else for ITEM in ${FIND}; do LogText "Denied at user: ${ITEM}" done fi else LogText "Result: can not read ${AT_DENY} (no permission)" fi else LogText "Result: both ${AT_ALLOW} and ${AT_DENY} do not exist" LogText "Note: only root can schedule at jobs" AddHP 1 1 fi fi Display --indent 4 --text "- Checking at users" --result "${STATUS_DONE}" --color GREEN else Display --indent 4 --text "- Checking at users" --result "${STATUS_SKIPPED}" --color YELLOW fi fi # ################################################################################# # # Test : SCHD-7724 # Description : Check scheduled at jobs if [ ${ATD_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi Register --test-no SCHD-7724 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check at jobs" if [ ${SKIPTEST} -eq 0 ]; then LogText "Test: Check scheduled at jobs" FIND=$(atq | ${GREPBINARY} -v "no files in queue" | ${AWKBINARY} '{gsub("\t"," ");print}' | ${SEDBINARY} 's/ /!space!/g') if HasData "${FIND}"; then LogText "Result: found one or more jobs" for ITEM in ${FIND}; do VALUE=$(echo ${ITEM} | ${SEDBINARY} 's/!space!/ /g') LogText "Found at job: ${VALUE}" done Display --indent 4 --text "- Checking at jobs" --result "${STATUS_FOUND}" --color GREEN else LogText "Result: no pending at jobs" Display --indent 4 --text "- Checking at jobs" --result "${STATUS_NONE}" --color GREEN fi fi # ################################################################################# # if [ -z "${LYNIS_CRONJOB}" ]; then LogText "Result: no scheduled Lynis execution found (e.g. crontab, cronjob)" else LogText "Result: found scheduled Lynis execution (${LYNIS_CRONJOB})" fi WaitForKeyPress # #================================================================================ # Lynis - Security Auditing and System Hardening for Linux and UNIX - https://cisofy.com