1#!/bin/sh 2 3################################################################################# 4# 5# Lynis 6# ------------------ 7# 8# Copyright 2007-2013, Michael Boelen 9# Copyright 2007-2021, CISOfy 10# 11# Website : https://cisofy.com 12# Blog : http://linux-audit.com 13# GitHub : https://github.com/CISOfy/lynis 14# 15# Lynis comes with ABSOLUTELY NO WARRANTY. This is free software, and you are 16# welcome to redistribute it under the terms of the GNU General Public License. 17# See LICENSE file for usage of this software. 18# 19################################################################################# 20# 21# Scheduled tasks 22# 23################################################################################# 24# 25 InsertSection "${SECTION_SCHEDULED_TASKS}" 26# 27################################################################################# 28# 29 ATD_RUNNING=0 30 CROND_RUNNING=0 31# 32################################################################################# 33# 34 # Test : SCHD-7702 35 # Description : Check cron daemon 36 Register --test-no SCHD-7702 --weight L --network NO --category security --description "Check status of cron daemon" 37 if [ ${SKIPTEST} -eq 0 ]; then 38 FIND=$(${PSBINARY} aux | ${EGREPBINARY} "( cron$|/cron(d)? )") 39 if IsEmpty "${FIND}"; then 40 LogText "Result: no cron daemon found" 41 else 42 LogText "Result: cron daemon running" 43 CROND_RUNNING=1 44 Report "crond_running=1" 45 Report "scheduler[]=crond" 46 fi 47 fi 48# 49################################################################################# 50# 51 # Test : SCHD-7704 52 # Description : Check crontab / cronjobs 53 Register --test-no SCHD-7704 --weight L --network NO --category security --description "Check crontab/cronjobs" 54 if [ ${SKIPTEST} -eq 0 ]; then 55 BAD_FILE_PERMISSIONS=0 56 BAD_FILE_OWNERSHIP=0 57 FindCronJob() { 58 sCRONJOBS=$(${EGREPBINARY} '^([0-9*])' $1 | ${TRBINARY} '\t' ' ' | ${TRBINARY} -s ' ' | ${TRBINARY} ' ' ',' | ${SORTBINARY}) 59 } 60 61 CRONTAB_FILE="${ROOTDIR}etc/crontab" 62 if [ -f ${CRONTAB_FILE} ]; then 63 ${EGREPBINARY} -q -s 'lynis audit system' ${CRONTAB_FILE} && LYNIS_CRONJOB="file:/etc/crontab" 64 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 65 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 66 FindCronJob ${CRONTAB_FILE} 67 for ITEM in ${sCRONJOBS}; do 68 LogText "Found cronjob (${CRONTAB_FILE}): ${ITEM}" 69 Report "cronjob[]=${ITEM}" 70 done 71 fi 72 73 CRON_DIRS="${ROOTDIR}etc/cron.d" 74 for DIR in ${CRON_DIRS}; do 75 LogText "Test: checking directory ${DIR}" 76 if [ -d ${DIR} ]; then 77 if FileIsReadable ${DIR}; then 78 LogText "Result: found directory ${DIR}" 79 LogText "Test: searching files in ${DIR}" 80 FIND=$(${FINDBINARY} ${DIR} -type f -print | ${GREPBINARY} -v ".placeholder") 81 if IsEmpty "${FIND}"; then 82 LogText "Result: no files found in ${DIR}" 83 else 84 LogText "Result: found one or more files in ${DIR}. Analyzing files.." 85 for FILE in ${FIND}; do 86 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 87 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 88 FILENAME=$(echo ${FILE} | ${AWKBINARY} -F/ '{print $NF}') 89 if [ "${FILENAME}" = "lynis" ]; then ${EGREPBINARY} -q -s 'lynis audit system' ${CRONTAB_FILE} && LYNIS_CRONJOB="file:${FILE}"; fi 90 FindCronJob ${FILE} 91 if HasData "${sCRONJOBS}"; then 92 for K in ${sCRONJOBS}; do 93 LogText "Result: Found cronjob (${FILE}): ${K}" 94 Report "cronjob[]=${FILE}" 95 done 96 fi 97 done 98 LogText "Result: done with analyzing files in ${DIR}" 99 fi 100 else 101 LogText "Result: can not read file or directory ${DIR}" 102 fi 103 else 104 LogText "Result: directory ${DIR} does not exist" 105 fi 106 done 107 108 CRON_DIRS="${ROOTDIR}etc/cron.hourly ${ROOTDIR}etc/cron.daily ${ROOTDIR}etc/cron.weekly ${ROOTDIR}etc/cron.monthly" 109 for I in ${CRON_DIRS}; do 110 LogText "Test: checking directory ${I}" 111 if [ -d ${I} ]; then 112 LogText "Result: found directory ${I}" 113 if FileIsReadable ${I}; then 114 LogText "Test: searching files in ${I}" 115 FIND=$(${FINDBINARY} ${I} -type f -print 2> /dev/null | ${GREPBINARY} -v ".placeholder") 116 if [ -z "${FIND}" ]; then 117 LogText "Result: no files found in ${I}" 118 else 119 LogText "Result: found one or more files in ${I}. Analyzing files.." 120 for FILE in ${FIND}; do 121 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 122 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 123 FILENAME=$(echo ${FILE} | ${AWKBINARY} -F/ '{print $NF}') 124 if [ "${FILENAME}" = "lynis" ]; then ${EGREPBINARY} -q -s 'lynis audit system' ${CRONTAB_FILE} && LYNIS_CRONJOB="file:${FILE}"; fi 125 LogText "Result: Found cronjob (${I}): ${FILE}" 126 Report "cronjob[]=${FILE}" 127 done 128 LogText "Result: done with analyzing files in ${I}" 129 fi 130 else 131 LogText "Result: directory permissions are too strict to enter it (which might be good)" 132 fi 133 else 134 LogText "Result: directory ${I} does not exist" 135 fi 136 done 137 138 # /var/spool/cron/* and /var/spool/cron/crontabs/* 139 # Search only in one tree, to avoid searching the tree twice 140 if [ -d /var/spool/cron/crontabs ]; then 141 FIND=$(${FINDBINARY} /var/spool/cron/crontabs -xdev -type f -print 2> /dev/null) 142 for I in ${FIND}; do 143 if FileIsReadable ${I}; then 144 ${EGREPBINARY} -q -s 'lynis audit system' ${I} && LYNIS_CRONJOB="file:${I}" 145 FindCronJob ${I} 146 for FILE in ${sCRONJOBS}; do 147 LogText "Found cronjob (/var/spool/cron/crontabs): ${I} (${FILE})" 148 Report "cronjob[]=${I}" 149 done 150 fi 151 done 152 else 153 if [ -d ${ROOTDIR}var/spool/cron ]; then 154 FIND=$(find ${ROOTDIR}var/spool/cron -type f -print) 155 for I in ${FIND}; do 156 if FileIsReadable ${I}; then 157 ${EGREPBINARY} -q -s 'lynis audit system' ${I} && LYNIS_CRONJOB="file:${I}" 158 FindCronJob ${I} 159 for FILE in ${sCRONJOBS}; do 160 LogText "Found cronjob in ${ROOTDIR}var/spool/cron: ${I} (${FILE})" 161 LogText "cronjob[]=${I}" 162 done 163 fi 164 done 165 fi 166 fi 167 168 # Anacron 169 if [ "${OS}" = "Linux" ]; then 170 if [ -f /etc/anacrontab ]; then 171 LogText "Test: checking anacrontab" 172 sANACRONJOBS=$(${EGREPBINARY} '^([0-9@])' /etc/anacrontab | ${TRBINARY} '\t' ' ' | ${TRBINARY} -s ' ' | ${TRBINARY} ' ' ',' | ${SORTBINARY}) 173 if [ -n "${sANACRONJOBS}" ]; then 174 Report "scheduler[]=anacron" 175 for I in ${sANACRONJOBS}; do 176 LogText "Found anacron job (/etc/anacrontab): ${I}" 177 Report "cronjob[]=${I}" 178 done 179 fi 180 fi 181 fi 182 183 # Show warning when an issue shows up. Even if *both* the permissions and ownership are wrong, just show one (prevent overload of warnings). 184 if [ ${BAD_FILE_PERMISSIONS} -eq 1 ]; then 185 ReportWarning "${TEST_NO}" "Found one or more cronjob files with incorrect file permissions (see log for details)" 186 Display --indent 2 --text "- Checking crontab and cronjobs files" --result "${STATUS_WARNING}" --color RED 187 elif [ ${BAD_FILE_OWNERSHIP} -eq 1 ]; then 188 ReportWarning "${TEST_NO}" "Found one or more cronjob files with incorrect ownership (see log for details)" 189 Display --indent 2 --text "- Checking crontab and cronjob files" --result "${STATUS_WARNING}" --color RED 190 else 191 Display --indent 2 --text "- Checking crontab and cronjob files" --result "${STATUS_DONE}" --color GREEN 192 fi 193 194 fi 195# 196################################################################################# 197# 198 # Test : SCHD-7718 199 # Description : Check atd status 200 Register --test-no SCHD-7718 --weight L --network NO --category security --description "Check at users" 201 if [ ${SKIPTEST} -eq 0 ]; then 202 LogText "Test: Checking atd status" 203 FIND=$(${PSBINARY} ax | ${GREPBINARY} "/atd" | ${GREPBINARY} -v "grep") 204 if [ -n "${FIND}" ]; then 205 LogText "Result: at daemon active" 206 Display --indent 2 --text "- Checking atd status" --result "${STATUS_RUNNING}" --color GREEN 207 ATD_RUNNING=1 208 Report "scheduler[]=atd" 209 else 210 LogText "Result: at daemon not active" 211 if IsVerbose; then Display --indent 2 --text "- Checking atd status" --result "${STATUS_NOT_RUNNING}" --color WHITE; fi 212 fi 213 fi 214# 215################################################################################# 216# 217 # Test : SCHD-7720 218 # Description : Check at users 219 # Notes : if at.allow exists, only users listed can schedule at jobs 220 # if at.allow does not exist, but at.deny does, everyone 221 # except the listed ones can schedule jobs. If both can't be 222 # found, only root can schedule jobs. 223 if [ ${ATD_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi 224 Register --test-no SCHD-7720 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check at users" 225 if [ ${SKIPTEST} -eq 0 ]; then 226 AT_UNKNOWN=0 227 case ${OS} in 228 FreeBSD) AT_ALLOW="${ROOTDIR}var/at/at.allow"; AT_DENY="${ROOTDIR}var/at/at.deny" ;; 229 HPUX) AT_ALLOW="${ROOTDIR}usr/lib/cron/at.allow"; AT_DENY="${ROOTDIR}usr/lib/cron/at.deny" ;; 230 Linux) AT_ALLOW="${ROOTDIR}etc/at.allow"; AT_DENY="${ROOTDIR}etc/at.deny" ;; 231 OpenBSD) AT_ALLOW="${ROOTDIR}var/cron/at.allow"; AT_DENY="${ROOTDIR}var/cron/at.deny" ;; 232 SunOS) AT_ALLOW="${ROOTDIR}etc/cron.d/at.allow"; AT_DENY="${ROOTDIR}etc/cron.d/at.deny" ;; 233 *) AT_UNKNOWN=1; LogText "Test skipped, files for at unknown" ;; 234 esac 235 if [ ${AT_UNKNOWN} -eq 0 ]; then 236 LogText "Test: checking for file ${AT_ALLOW}" 237 if [ -f ${AT_ALLOW} ]; then 238 FileIsReadable ${AT_ALLOW} 239 if [ ${CANREAD} -eq 1 ]; then 240 LogText "Result: file ${AT_ALLOW} exists, only listed users can schedule at jobs" 241 FIND=$(${SORTBINARY} ${AT_ALLOW}) 242 if IsEmpty "${FIND}"; then 243 LogText "Result: File empty, no users are allowed to schedule at jobs" 244 else 245 for ITEM in ${FIND}; do 246 LogText "Allowed at user: ${ITEM}" 247 done 248 fi 249 else 250 LogText "Result: can not read ${AT_ALLOW} (no permission)" 251 fi 252 else 253 LogText "Result: file ${AT_ALLOW} does not exist" 254 LogText "Test: checking for file ${AT_DENY}" 255 if [ -f ${AT_DENY} ]; then 256 FileIsReadable ${AT_DENY} 257 if [ ${CANREAD} -eq 1 ]; then 258 LogText "Result: file ${AT_DENY} exists, only non listed users can schedule at jobs" 259 FIND=$(${SORTBINARY} ${AT_DENY}) 260 if [ -z "${FIND}" ]; then 261 LogText "Result: file is empty, no users are denied access to schedule jobs" 262 else 263 for ITEM in ${FIND}; do 264 LogText "Denied at user: ${ITEM}" 265 done 266 fi 267 else 268 LogText "Result: can not read ${AT_DENY} (no permission)" 269 fi 270 else 271 LogText "Result: both ${AT_ALLOW} and ${AT_DENY} do not exist" 272 LogText "Note: only root can schedule at jobs" 273 AddHP 1 1 274 fi 275 fi 276 Display --indent 4 --text "- Checking at users" --result "${STATUS_DONE}" --color GREEN 277 else 278 Display --indent 4 --text "- Checking at users" --result "${STATUS_SKIPPED}" --color YELLOW 279 fi 280 fi 281# 282################################################################################# 283# 284 # Test : SCHD-7724 285 # Description : Check scheduled at jobs 286 if [ ${ATD_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi 287 Register --test-no SCHD-7724 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check at jobs" 288 if [ ${SKIPTEST} -eq 0 ]; then 289 LogText "Test: Check scheduled at jobs" 290 FIND=$(atq | ${GREPBINARY} -v "no files in queue" | ${AWKBINARY} '{gsub("\t"," ");print}' | ${SEDBINARY} 's/ /!space!/g') 291 if HasData "${FIND}"; then 292 LogText "Result: found one or more jobs" 293 for ITEM in ${FIND}; do 294 VALUE=$(echo ${ITEM} | ${SEDBINARY} 's/!space!/ /g') 295 LogText "Found at job: ${VALUE}" 296 done 297 Display --indent 4 --text "- Checking at jobs" --result "${STATUS_FOUND}" --color GREEN 298 else 299 LogText "Result: no pending at jobs" 300 Display --indent 4 --text "- Checking at jobs" --result "${STATUS_NONE}" --color GREEN 301 fi 302 fi 303# 304################################################################################# 305# 306 307if [ -z "${LYNIS_CRONJOB}" ]; then 308 LogText "Result: no scheduled Lynis execution found (e.g. crontab, cronjob)" 309else 310 LogText "Result: found scheduled Lynis execution (${LYNIS_CRONJOB})" 311fi 312 313WaitForKeyPress 314 315# 316#================================================================================ 317# Lynis - Security Auditing and System Hardening for Linux and UNIX - https://cisofy.com 318