diff options
Diffstat (limited to 'include')
56 files changed, 1896 insertions, 530 deletions
diff --git a/include/binaries b/include/binaries index f567ed1f..95d56c3d 100644 --- a/include/binaries +++ b/include/binaries @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -30,7 +30,7 @@ ################################################################################# # if [ ${CHECK_BINARIES} -eq 1 ]; then - InsertSection "System Tools" + InsertSection "${SECTION_SYSTEM_TOOLS}" Display --indent 2 --text "- Scanning available tools..." LogText "Start scanning for available audit binaries and tools..." @@ -74,6 +74,10 @@ fi done + NSUID_BINARIES=0 + NSGID_BINARIES=0 + SUID_BINARIES= + SGID_BINARIES= # Now perform binary detection for SCANDIR in ${BIN_PATHS}; do SCANDIR=$(echo "${SCANDIR}" | sed 's/!!space!!/ /g') @@ -115,6 +119,14 @@ COUNT=$((COUNT + 1)) BINARY="${SCANDIR}/${FILENAME}" DISCOVERED_BINARIES="${DISCOVERED_BINARIES}${BINARY} " + if [ -u "${BINARY}" ]; then + NSUID_BINARIES=$((NSUID_BINARIES + 1)) + SUID_BINARIES="${SUID_BINARIES}${BINARY} " + fi + if [ -g "${BINARY}" ]; then + NSGID_BINARIES=$((NSGID_BINARIES + 1)) + SGID_BINARIES="${SGID_BINARIES}${BINARY} " + fi # Optimized, much quicker (limited file access needed) case ${FILENAME} in aa-status) AASTATUSBINARY=${BINARY}; LogText " Found known binary: aa-status (apparmor component) - ${BINARY}" ;; @@ -154,8 +166,10 @@ docker) DOCKERBINARY="${BINARY}"; LogText " Found known binary: docker (container technology) - ${BINARY}" ;; domainname) DOMAINNAMEBINARY="${BINARY}"; LogText " Found known binary: domainname (NIS domain) - ${BINARY}" ;; dpkg) DPKGBINARY="${BINARY}"; LogText " Found known binary: dpkg (package management) - ${BINARY}" ;; + xbps-query) XBPSBINARY="${BINARY}"; LogText " Found known binary: xbps (package management) - ${BINARY}" ;; egrep) EGREPBINARY=${BINARY}; LogText " Found known binary: egrep (text search) - ${BINARY}" ;; equery) EQUERYBINARY="${BINARY}"; LogText " Found known binary: query (package manager) - ${BINARY}" ;; + evmctl) EVMCTLBINARY=${BINARY}; LogText " Found known binary: evmctl (IMA/EVM tool) - ${BINARY}" ;; exim) EXIMBINARY="${BINARY}"; EXIMVERSION=$(${BINARY} -bV | grep 'Exim version' | awk '{ print $3 }' | xargs); LogText " Found known binary ${BINARY} (version ${EXIMVERSION})" ;; fail2ban-server) FAIL2BANBINARY="${BINARY}"; LogText " Found known binary: fail2ban (IPS tool) - ${BINARY}" ;; file) FILEBINARY="${BINARY}"; LogText " Found known binary: file (file type detection) - ${BINARY}" ;; @@ -174,6 +188,7 @@ httpd2-prefork) HTTPDBINARY=${BINARY}; LogText " Found known binary: apache2 (web server) - ${BINARY}" ;; initctl) INITCTLBINARY=${BINARY}; SERVICE_MANAGER="upstart"; LogText " Found known binary: initctl (client to upstart init) - ${BINARY}" ;; ifconfig) IFCONFIGBINARY="${BINARY}"; LogText " Found known binary: ipconfig (IP configuration) - ${BINARY}" ;; + integritysetup) INTEGRITYSETUPBINARY="${BINARY}"; LogText " Found known binary: integritysetup (dm-integrity setup tool) - ${BINARY}" ;; ip) IPBINARY="${BINARY}"; LogText " Found known binary: ip (IP configuration) - ${BINARY}" ;; ipf) IPFBINARY="${BINARY}"; LogText " Found known binary: ipf (firewall) - ${BINARY}" ;; iptables) IPTABLESBINARY="${BINARY}"; LogText " Found known binary: iptables (firewall) - ${BINARY}" ;; @@ -204,6 +219,7 @@ maldet) LMDBINARY="${BINARY}"; MALWARE_SCANNER_INSTALLED=1; LogText " Found known binary: maldet (Linux Malware Detect, malware scanner) - ${BINARY}" ;; md5) MD5BINARY="${BINARY}"; LogText " Found known binary: md5 (hash tool) - ${BINARY}" ;; md5sum) MD5BINARY="${BINARY}"; LogText " Found known binary: md5sum (hash tool) - ${BINARY}" ;; + mdatp) MDATPBINARY="${BINARY}"; MALWARE_SCANNER_INSTALLED=1; LogText " Found known binary: mdatp (Microsoft Defender ATP, malware scanner) - ${BINARY}" ;; modprobe) MODPROBEBINARY="${BINARY}"; LogText " Found known binary: modprobe (kernel modules) - ${BINARY}" ;; mount) MOUNTBINARY="${BINARY}"; LogText " Found known binary: mount (disk utility) - ${BINARY}" ;; mtree) MTREEBINARY="${BINARY}"; LogText " Found known binary: mtree (mapping directory tree) - ${BINARY}" ;; @@ -212,15 +228,22 @@ netstat) NETSTATBINARY="${BINARY}"; LogText " Found known binary: netstat (network statistics) - ${BINARY}" ;; nft) NFTBINARY="${BINARY}"; LogText " Found known binary: nft (nftables client) - ${BINARY}" ;; nmap) NMAPBINARY="${BINARY}"; NMAPVERSION=$(${BINARY} -V | grep "^Nmap version" | awk '{ print $3 }'); LogText "Found ${BINARY} (version ${NMAPVERSION})" ;; + ntpctl) NTPCTLBINARY="${BINARY}"; LogText " Found known binary: ntpctl (openntpd client) - ${BINARY}" ;; ntpq) NTPQBINARY="${BINARY}"; LogText " Found known binary ntpq (time daemon client) - ${BINARY}" ;; osiris) OSIRISBINARY="${BINARY}"; LogText " Found known binary: osiris - ${BINARY}" ;; openssl) OPENSSLBINARY="${BINARY}"; OPENSSLVERSION=$(${BINARY} version 2> /dev/null | head -n 1 | awk '{ print $2 }' | xargs); LogText "Found ${BINARY} (version ${OPENSSLVERSION})" ;; - pacman) PACMANBINARY="${BINARY}"; LogText " Found known binary: pacman (package manager) - ${BINARY}" ;; + pacman) + if [ -z "$(echo "${BINARY}" | grep -E "/usr(/local)?/games")" ]; then + PACMANBINARY="${BINARY}" + LogText " Found known binary: pacman (package manager) - ${BINARY}" + fi + ;; perl) PERLBINARY="${BINARY}"; PERLVERSION=$(${BINARY} -V:version | sed 's/^version=//' | sed 's/;//' | xargs); LogText "Found ${BINARY} (version ${PERLVERSION})" ;; pgrep) PGREPBINARY="${BINARY}"; LogText " Found known binary: pgrep (search in process list) - ${BINARY}" ;; php) PHPBINARY="${BINARY}"; PHPVERSION=$(${BINARY} -v | awk '{ if ($1=="PHP") { print $2 }}' | head -1); LogText "Found known binary: php (programming language interpreter) - ${BINARY} (version ${PHPVERSION})" ;; pkg) PKG_BINARY="${BINARY}"; LogText " Found known binary: pkg (software package administration) - ${BINARY}" ;; pkg_admin) PKGADMINBINARY="${BINARY}"; LogText " Found known binary: pkg_admin (software package administration) - ${BINARY}" ;; + pkg_info) PKGINFOBINARY="${BINARY}"; LogText " Found known binary: pkg_info (software package information) - ${BINARY}" ;; postconf) POSTCONFBINARY="${BINARY}"; LogText " Found known binary: postconf (postfix configuration) - ${BINARY}" ;; postfix) POSTFIXBINARY="${BINARY}"; LogText " Found known binary: postfix (postfix binary) - ${BINARY}" ;; prelink) PRELINKBINARY="${BINARY}"; LogText " Found known binary: prelink (system optimizer) - ${BINARY}" ;; @@ -233,6 +256,7 @@ python3) PYTHON3BINARY="${BINARY}"; PYTHON3VERSION=$(${BINARY} --version 2>&1 | sed 's/^Python //'); LogText "Found known binary: ${FILENAME} (programming language interpreter) - ${BINARY} (version ${PYTHON3VERSION})" ;; rcctl) RCCTLBINARY="${BINARY}"; LogText " Found known binary: rcctl (services and daemons configuration and control) - ${BINARY}" ;; readlink) READLINKBINARY="${BINARY}"; LogText " Found known binary: readlink (follows symlinks) - ${BINARY}" ;; + resolvectl) RESOLVECTLBINARY="${BINARY}"; LogText " Found known binary: resolvectl (systemd-resolved DNS resolver manager) - ${BINARY}" ;; rkhunter) RKHUNTERBINARY="${BINARY}"; MALWARE_SCANNER_INSTALLED=1; LogText " Found known binary: rkhunter (malware scanner) - ${BINARY}" ;; rootsh) ROOTSHBINARY="${BINARY}"; LogText " Found known binary: rootsh (wrapper for shells) - ${BINARY}" ;; rpcinfo) RPCINFOBINARY="${BINARY}"; LogText " Found known binary: rpcinfo (RPC information) - ${BINARY}" ;; @@ -243,7 +267,8 @@ samhain) SAMHAINBINARY="${BINARY}"; LogText " Found known binary: samhain (integrity tool) - ${BINARY}" ;; service) SERVICEBINARY="${BINARY}"; LogText " Found known binary: service (system services) - ${BINARY}" ;; sed) SEDBINARY="${BINARY}"; LogText " Found known binary: sed (text stream editor) - ${BINARY}" ;; - sestatus) SESTATUSBINARY="${BINARY}"; LogText " Found known binary: sestatus (SELinux client) - ${BINARY}" ;; + semanage) SEMANAGEBINARY="${BINARY}"; LogText " Found known binary: semanage (SELinux policy management tool) - ${BINARY}" ;; + sestatus) SESTATUSBINARY="${BINARY}"; LogText " Found known binary: sestatus (SELinux status tool) - ${BINARY}" ;; slocate) LOCATEBINARY="${BINARY}"; LogText " Found known binary: slocate (file database) - ${BINARY}" ;; smbd) SMBDBINARY="${BINARY}"; if [ "${OS}" = "macOS" ]; then SMBDVERSION="unknown"; else SMBDVERSION=$(${BINARY} -V | grep "^Version" | awk '{ print $2 }'); fi; LogText "Found ${BINARY} (version ${SMBDVERSION})" ;; smtpctl) SMTPCTLBINARY="${BINARY}"; LogText " Found known binary: smtpctl (OpenSMTPD client) - ${BINARY}" ;; @@ -260,19 +285,25 @@ sha256|sha256sum) SHA256SUMBINARY="${BINARY}"; LogText " Found known binary: sha256/sha256sum (crypto hashing) - ${BINARY}" ;; ssh-keyscan) SSHKEYSCANBINARY="${BINARY}"; LogText " Found known binary: ssh-keyscan (scanner for SSH keys) - ${BINARY}" ;; suricata) SURICATABINARY="${BINARY}"; LogText " Found known binary: suricata (IDS) - ${BINARY}" ;; + swapon) SWAPONBINARY="${BINARY}"; LogText " Found known binary: swapon (swap device tool) - ${BINARY}" ;; + svcs) SVCSBINARY="${BINARY}" ; LogText " Found known binary: svcs (service manager) - ${BINARY}" ;; swupd) SWUPDBINARY="${BINARY}"; LogText " Found known binary: swupd (package manager) - ${BINARY}" ;; + synoavd) SYNOAVDBINARY=${BINARY}; LogText " Found known binary: synoavd (Synology AV scanner) - ${BINARY}" ;; sysctl) SYSCTLBINARY="${BINARY}"; LogText " Found known binary: sysctl (kernel parameters) - ${BINARY}" ;; syslog-ng) SYSLOGNGBINARY="${BINARY}"; SYSLOGNGVERSION=$(${BINARY} -V 2>&1 | grep "^syslog-ng" | awk '{ print $2 }'); LogText "Found ${BINARY} (version ${SYSLOGNGVERSION})" ;; systemctl) SYSTEMCTLBINARY="${BINARY}"; LogText " Found known binary: systemctl (client to systemd) - ${BINARY}" ;; + systemd-analyze) SYSTEMDANALYZEBINARY="${BINARY}"; LogText " Found known binary: systemd-analyze (systemd service analysis tool) - ${BINARY}" ;; tail) TAILBINARY="${BINARY}"; LogText " Found known binary: tail (text filter) - ${BINARY}" ;; timedatectl) TIMEDATECTL="${BINARY}"; LogText " Found known binary: timedatectl (timedate client) - ${BINARY}" ;; tomoyo-init) TOMOYOINITBINARY=${BINARY}; LogText " Found known binary: tomoyo-init (tomoyo component) - ${BINARY}" ;; + tomoyo-pstree) TOMOYOPSTREEBINARY=${BINARY}; LogText " Found known binary: tomoyo-pstree (tomoyo process tree) - ${BINARY}" ;; tr) TRBINARY="${BINARY}"; LogText " Found known binary: tr (text transformation) - ${BINARY}" ;; tripwire) TRIPWIREBINARY="${BINARY}"; LogText " Found known binary: tripwire (file integrity) - ${BINARY}" ;; tune2fs) TUNE2FSBINARY="${BINARY}"; LogText " Found known binary: tune2fs (file system tool) - ${BINARY}" ;; uname) UNAMEBINARY="${BINARY}"; LogText " Found known binary: uname (operating system details) - ${BINARY}" ;; uniq) UNIQBINARY="${BINARY}"; LogText " Found known binary: uniq (text manipulation utility) - ${BINARY}";; usbguard) USBGUARDBINARY="${BINARY}"; LogText " Found known binary: usbguard (USB security tool) - ${BINARY}" ;; + veritysetup) VERITYSETUPBINARY="${BINARY}"; LogText " Found known binary: veritysetup (dm-verity setup tool) - ${BINARY}" ;; vgdisplay) VGDISPLAYBINARY="${BINARY}"; LogText " Found known binary: vgdisplay (LVM tool) - ${BINARY}" ;; vmtoolsd) VMWARETOOLSDBINARY="${BINARY}"; LogText " Found known binary: vmtoolsd (VMWare tools) - ${BINARY}" ;; wc) WCBINARY="${BINARY}"; LogText " Found known binary: wc (word count) - ${BINARY}" ;; @@ -296,12 +327,17 @@ BINARY_SCAN_FINISHED=1 BINARY_PATHS_FOUND=$(echo ${BINARY_PATHS_FOUND} | sed 's/^, //g' | sed 's/, /,/g') LogText "Discovered directories: ${BINARY_PATHS_FOUND}" - LogText "Result: found ${COUNT} binaries" + LogText "Result: found ${COUNT} binaries including ${NSUID_BINARIES} set-uid and ${NSGID_BINARIES} set-gid" + LogText "Result: set-uid binaries: ${SUID_BINARIES}" + LogText "Result: set-gid binaries: ${SGID_BINARIES}" Report "binaries_count=${COUNT}" + Report "binaries_suid_count=${SUID_BINARIES}" + Report "binaries_sgid_count=${SGID_BINARIES}" Report "binary_paths=${BINARY_PATHS_FOUND}" # Test if the basic system tools are defined. These will be used during the audit. [ "${AWKBINARY:-}" ] || ExitFatal "awk binary not found" + [ "${CAT_BINARY:-}" ] || ExitFatal "cat binary not found" [ "${CUTBINARY:-}" ] || ExitFatal "cut binary not found" [ "${EGREPBINARY:-}" ] || ExitFatal "grep binary not found" [ "${FINDBINARY:-}" ] || ExitFatal "find binary not found" diff --git a/include/consts b/include/consts index 9d99f606..bb1d63ff 100644 --- a/include/consts +++ b/include/consts @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -33,10 +33,6 @@ BIN_PATHS="/bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin \ ETC_PATHS="/etc /usr/local/etc" -# Do not use specific language, fall back to default -# Some tools with translated strings are very hard to parse -unset LANG - # ################################################################################# # @@ -62,6 +58,7 @@ unset LANG APPLICATION_FIREWALL_ACTIVE=0 BINARY_SCAN_FINISHED=0 BLKIDBINARY="" + BOOTCTLBINARY="" CAT_BINARY="" CFAGENTBINARY="" CHECK=0 @@ -85,6 +82,7 @@ unset LANG CONTROL_URL_PROTOCOL="" CONTAINER_TYPE="" CREATE_REPORT_FILE=1 + CRYPTSETUPBINARY="" CSUMBINARY="" CURRENT_TS=0 CUSTOM_URL_APPEND="" @@ -98,16 +96,19 @@ unset LANG DEBSUMSBINARY="" DEVELOPER_MODE=0 DEVOPS_MODE=0 + DIGBINARY="" DISABLED_PLUGINS="" DISCOVERED_BINARIES="" DMIDECODEBINARY="" DNFBINARY="" + DNSDOMAINNAMEBINARY="" DOCKERBINARY="" DOCKER_DAEMON_RUNNING=0 DPKGBINARY="" ECHOCMD="" ERROR_ON_WARNINGS=0 EQUERYBINARY="" + EVMCTLBINARY="" EXIMBINARY="" FAIL2BANBINARY="" FILEBINARY="" @@ -124,6 +125,7 @@ unset LANG GRSEC_FOUND=0 GRUBCONFFILE="" GRUB2INSTALLBINARY="" + HAS_PACKAGE_MANAGER=0 HAS_SYSTEMD=0 HEADBINARY="" HELPER="" @@ -132,6 +134,7 @@ unset LANG HTTPDBINARY="" IDS_IPS_TOOL_FOUND=0 IFCONFIGBINARY="" + INTEGRITYSETUPBINARY="" IPBINARY="" IPFBINARY="" IPTABLESBINARY="" @@ -148,7 +151,9 @@ unset LANG LOCATEBINARY="" LOGFILE="" LOGDIR="" + LOGROTATEBINARY="" LOGTEXT=1 + LSBLKBINARY="" LSMODBINARY="" LSOFBINARY="" LSOF_EXTRA_OPTIONS="" @@ -192,6 +197,7 @@ unset LANG NGINX_RETURN_FOUND=0 NGINX_ROOT_FOUND=0 NGINX_WEAK_SSL_PROTOCOL_FOUND=0 + NTPCTLBINARY="" NTPD_ROLE="" NTPQBINARY="" OPENSSLBINARY="" @@ -205,6 +211,7 @@ unset LANG OS_REDHAT_OR_CLONE=0 OSIRISBINARY="" PACMANBINARY="" + PAM_PASSWORD_PWHISTORY_AMOUNT="" PASSWORD_MAXIMUM_DAYS=-1 PASSWORD_MINIMUM_DAYS=-1 PAM_2F_AUTH_ENABLED=0 @@ -220,6 +227,7 @@ unset LANG PGREPBINARY="" PIDFILE="" PKG_BINARY="" + PKGINFOBINARY="" PKGADMINBINARY="" PLUGINDIR="" PLUGIN_PHASE=0 @@ -238,6 +246,7 @@ unset LANG REFRESH_REPOSITORIES=1 REMOTE_LOGGING_ENABLED=0 RESOLV_DOMAINNAME="" + RESOLVECTLBINARY="" RKHUNTERBINARY="" ROOTDIR="/" ROOTSHBINARY="" @@ -273,16 +282,20 @@ unset LANG SKIP_VM_DETECTION=0 SKIPREASON="" SKIPPED_TESTS_ROOTONLY="" + SLOW_TEST_THRESHOLD=10 SMTPCTLBINARY="" SNORTBINARY="" + SSBINARY="" SSHKEYSCANBINARY="" SSHKEYSCANFOUND=0 + SSL_CERTIFICATE_INCLUDE_PACKAGES=0 SSL_CERTIFICATE_PATHS="" SSL_CERTIFICATE_PATHS_TO_IGNORE="" STUNNELBINARY="" SWUPDBINARY="" SYSLOGNGBINARY="" SYSTEMCTLBINARY="" + SYSTEMDANALYZEBINARY="" SYSTEM_IS_NOTEBOOK=255 TEMP_FILE="" TEMP_FILES="" @@ -292,6 +305,7 @@ unset LANG TEST_GROUP_TO_CHECK="all" TESTS_EXECUTED="" TESTS_SKIPPED="" + TIMEDATECTL="" TMPFILE="" TOMOYOINITBINARY="" TOOLTIP_SHOWED=0 @@ -317,11 +331,13 @@ unset LANG USBGUARD_ROOT="" VALUE="" VERBOSE=0 + VERITYSETUPBINARY="" VGDISPLAYBINARY="" VMTYPE="" VULNERABLE_PACKAGES_FOUND=0 WCBINARY="" XARGSBINARY="" + XBPSBINARY="" YUMBINARY="" ZYPPERBINARY="" diff --git a/include/data_upload b/include/data_upload index cdc84ff0..eae2b5cc 100644 --- a/include/data_upload +++ b/include/data_upload @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -77,6 +77,10 @@ ExitFatal else Output "License key = ${LICENSE_KEY}" + # Create a temporary file to use during upload (prevent license key being displayed in process table) + CreateTempFile || ExitFatal + LICENSE_KEY_FILE="${TEMP_FILE}" + echo "${LICENSE_KEY}" | ${TRBINARY} -cd '[a-f0-9-]' > ${LICENSE_KEY_FILE} fi @@ -129,8 +133,9 @@ # License check - LogText "Command used: ${CURLBINARY}${CURL_OPTIONS} -s -S --data-urlencode "licensekey=${LICENSE_KEY}" --data-urlencode "collector_version=${PROGRAM_VERSION}" ${LICENSE_SERVER_URL} 2> /dev/null" - UPLOAD=$(${CURLBINARY}${CURL_OPTIONS} -s -S --data-urlencode "licensekey=${LICENSE_KEY}" --data-urlencode "collector_version=${PROGRAM_VERSION}" ${LICENSE_SERVER_URL} 2> /dev/null) + LogText "Command used: ${CURLBINARY}${CURL_OPTIONS} -s -S --data-urlencode "licensekey@${LICENSE_KEY_FILE}" --data-urlencode "collector_version=${PROGRAM_VERSION}" ${LICENSE_SERVER_URL} 2> /dev/null" + UPLOAD=$(${CURLBINARY}${CURL_OPTIONS} -s -S --data-urlencode "licensekey@${LICENSE_KEY_FILE}" --data-urlencode "collector_version=${PROGRAM_VERSION}" ${LICENSE_SERVER_URL} 2> /dev/null) + EXITCODE=$? LogText "Exit code: ${EXITCODE}" if [ ${EXITCODE} -gt 0 ]; then @@ -225,10 +230,10 @@ Output "${WHITE}Found hostid: ${HOSTID}${NORMAL}" # Try to connect Output "Uploading data.." - LogText "Command used: ${CURLBINARY}${CURL_OPTIONS} -s -S --data-urlencode \"data@${REPORTFILE}\" --data-urlencode \"licensekey=${LICENSE_KEY}\" --data-urlencode \"hostid=${HOSTID}\" ${UPLOAD_URL}" - LogText "Tip: try running ${CURLBINARY}${CURL_OPTIONS} --data-urlencode \"data@${REPORTFILE}\" --data-urlencode \"licensekey=${LICENSE_KEY}\" --data-urlencode \"hostid=${HOSTID}\" ${UPLOAD_URL}" + LogText "Command used: ${CURLBINARY}${CURL_OPTIONS} -s -S --data-urlencode \"data@${REPORTFILE}\" --data-urlencode \"licensekey@${LICENSE_KEY_FILE}\" --data-urlencode \"hostid=${HOSTID}\" ${UPLOAD_URL}" + LogText "Tip: try running ${CURLBINARY}${CURL_OPTIONS} --data-urlencode \"data@${REPORTFILE}\" --data-urlencode \"licensekey@${LICENSE_KEY_FILE}\" --data-urlencode \"hostid=${HOSTID}\" ${UPLOAD_URL}" LogText "Tip: to just retry an upload, use: lynis upload-only" - UPLOAD=$(${CURLBINARY}${CURL_OPTIONS} -s -S --data-urlencode "data@${REPORTFILE}" --data-urlencode "licensekey=${LICENSE_KEY}" --data-urlencode "hostid=${HOSTID}" --data-urlencode "hostid2=${HOSTID2}" ${UPLOAD_URL} 2> /dev/null) + UPLOAD=$(${CURLBINARY}${CURL_OPTIONS} -s -S --data-urlencode "data@${REPORTFILE}" --data-urlencode "licensekey@${LICENSE_KEY_FILE}" --data-urlencode "hostid=${HOSTID}" --data-urlencode "hostid2=${HOSTID2}" ${UPLOAD_URL} 2> /dev/null) EXITCODE=$? LogText "Exit code: ${EXITCODE}" if [ ${EXITCODE} -gt 0 ]; then diff --git a/include/functions b/include/functions index de40a427..c88674ba 100644 --- a/include/functions +++ b/include/functions @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -38,7 +38,7 @@ # DigitsOnly Return only the digits from a string # DirectoryExists Check if a directory exists on the disk # DiscoverProfiles Determine available profiles on system -# Display Output text to screen with colors and identation +# Display Output text to screen with colors and indentation # DisplayError Show an error on screen # DisplayException Show an exception on screen # DisplayManual Output text to screen without any layout @@ -1089,12 +1089,13 @@ ;; "Solaris") - INTERFACES_TO_TEST="e1000g1 net0" + INTERFACES_TO_TEST="net0 e1000g1 e1000g0" FOUND=0 for I in ${INTERFACES_TO_TEST}; do FIND=$(${IFCONFIGBINARY} -a | grep "^${I}") if [ ! "${FIND}" = "" ]; then FOUND=1; LogText "Found interface ${I} on Solaris" + break fi done if [ ${FOUND} -eq 1 ]; then @@ -1107,7 +1108,7 @@ ReportException "GetHostID" "Can not find sha1/sha1sum or openssl" fi else - ReportException "GetHostID" "No interface found op Solaris to create HostID" + ReportException "GetHostID" "No interface found on Solaris to create HostID" fi ;; @@ -1286,11 +1287,12 @@ CHECK_PERMISSION=$(echo "${CHECK_PERMISSION}" | ${AWKBINARY} '{printf "%03d",$1}') # First try stat command - LogText "Test: checking if file ${CHECKFILE} is ${CHECK_PERMISSION}" + LogText "Test: checking if file ${CHECKFILE} has the permissions set to ${CHECK_PERMISSION} or more restrictive" if [ -n "${STATBINARY}" ]; then case ${OS} in - *BSD) + *BSD | "macOS") + # BSD and macOS have no --format, only short notation DATA=$(${STATBINARY} -f "%OLp" ${CHECKFILE}) ;; *) @@ -1344,7 +1346,7 @@ DATA=$(echo "${DATA}" | ${AWKBINARY} '{printf "%03d",$1}') if [ -n "${DATA}" ]; then - if [ "${DATA}" = "${CHECK_PERMISSION}" ]; then + if [ "${DATA}" -le "${CHECK_PERMISSION}" ]; then LogText "Outcome: correct permissions (${DATA})" return 0 fi @@ -1516,6 +1518,7 @@ # Returns : 0 (process is running), 1 (process not running) # RUNNING (1 = running, 0 = not running) - will be deprecated # Notes : PSOPTIONS are declared globally, to prevent testing each call + # Fallback is used on binaries as IsRunning is used for 'show' command ################################################################################ IsRunning() { @@ -1545,44 +1548,43 @@ if [ -z "${search}" ]; then ExitFatal "Missing process to search for when using IsRunning function"; fi RUNNING=0 - # AIX does not fully support pgrep options, so using ps instead - if [ -n "${PGREPBINARY}" ] && [ "${OS}" != "AIX" ]; then + if [ -x "${PGREPBINARY}" ] && [ "${OS}" != "AIX" ]; then # When --user is used, perform a search using the -u option - # Initialize users for strict mode + # Initialize users for strict mode if [ -n "${users:-}" ]; then for u in ${users}; do - user_uid=$(getent passwd "${u}" 2> /dev/null | ${AWKBINARY} -F: '{print $3}') + user_uid=$(getent passwd "${u}" 2> /dev/null | ${AWKBINARY:-awk} -F: '{print $3}') # Only perform search if user exists and we had no match yet if [ -n "${user_uid}" ]; then if [ -z "${FIND}" ]; then LogText "Performing pgrep scan using uid ${user_uid}" - FIND=$(${PGREPBINARY} ${pgrep_options} -u "${user_uid}" "${search}" | ${TRBINARY} '\n' ' ') + FIND=$(${PGREPBINARY:-pgrep} ${pgrep_options} -u "${user_uid}" "${search}" | ${TRBINARY:-tr} '\n' ' ') fi fi done else LogText "Performing pgrep scan without uid" - FIND=$(${PGREPBINARY} ${pgrep_options} "${search}" | ${TRBINARY} '\n' ' ') + FIND=$(${PGREPBINARY:-pgrep} ${pgrep_options} "${search}" | ${TRBINARY:-tr} '\n' ' ') fi else if [ "${SHELL_IS_BUSYBOX}" -eq 1 ]; then # This search is not foolproof LogText "Performing simple ps scan (busybox)" PSOPTIONS=" -o args=" - FIND=$(${PSBINARY} ${PSOPTIONS} | ${EGREPBINARY} "( |/)${search}" | ${GREPBINARY} -v "grep") + FIND=$(${PSBINARY:-ps} ${PSOPTIONS} | ${EGREPBINARY:-egrep} "( |/)${search}" | ${GREPBINARY:-grep} -v "grep") else if [ -n "${users}" ]; then for u in ${users}; do - user_uid=$(getent passwd "${u}" 2> /dev/null | ${AWKBINARY} -F: '{print $3}') + user_uid=$(getent passwd "${u}" 2> /dev/null | ${AWKBINARY:-awk} -F: '{print $3}') # Only perform search if user exists and we had no match yet if [ -n "${user_uid}" ]; then if [ -z "${FIND}" ]; then if [ ${PARTIAL_SEARCH} -eq 1 ]; then LogText "Performing ps scan using partial match and for uid ${user_uid}" - FIND=$(${PSBINARY} -u "${user_uid}" -o comm= "${search}" | ${AWKBINARY} -v pattern="${search}" '$0 ~ pattern {print}') + FIND=$(${PSBINARY:-ps} -u "${user_uid}" -o comm= "${search}" | ${AWKBINARY:-awk} -v pattern="${search}" '$0 ~ pattern {print}') else LogText "Performing ps scan using exact match and for uid ${user_uid}" - FIND=$(${PSBINARY} -u "${user_uid}" -o comm= "${search}" | ${AWKBINARY} -v pattern="^${search}$" '$0 ~ pattern {print}') + FIND=$(${PSBINARY:-ps} -u "${user_uid}" -o comm= "${search}" | ${AWKBINARY:-awk} -v pattern="^${search}$" '$0 ~ pattern {print}') fi fi fi @@ -1595,10 +1597,10 @@ esac if [ ${PARTIAL_SEARCH} -eq 1 ]; then LogText "Performing ps scan using partial match and without uid" - FIND=$(${PSBINARY} ${PSOPTIONS} | ${AWKBINARY} -v pattern="${search}" '$0 ~ pattern {print}') + FIND=$(${PSBINARY:-ps} ${PSOPTIONS} | ${AWKBINARY:-awk} -v pattern="${search}" '$0 ~ pattern {print}') else LogText "Performing ps scan using exact match and without uid" - FIND=$(${PSBINARY} ${PSOPTIONS} | ${AWKBINARY} -v pattern="^${search}$" '$0 ~ pattern {print}') + FIND=$(${PSBINARY:-ps} ${PSOPTIONS} | ${AWKBINARY:-awk} -v pattern="^${search}$" '$0 ~ pattern {print}') fi fi fi @@ -1774,14 +1776,11 @@ # dmidecode # Values: VMware Virtual Platform / VirtualBox if [ -z "${SHORT}" ]; then - if [ -x /usr/bin/dmidecode ]; then DMIDECODE_BINARY="/usr/bin/dmidecode" - elif [ -x /usr/sbin/dmidecode ]; then DMIDECODE_BINARY="/usr/sbin/dmidecode" - else - DMIDECODE_BINARY="" - fi - if [ ! "${DMIDECODE_BINARY}" = "" -a ${PRIVILEGED} -eq 1 ]; then + # Try to find dmidecode in case we did not check binaries (e.g. lynis show environment) + if [ ${CHECK_BINARIES} -eq 0 ]; then DMIDECODEBINARY=$(command -v dmidecode 2> /dev/null); fi + if [ -n "${DMIDECODEBINARY}" -a -x "${DMIDECODEBINARY}" -a ${PRIVILEGED} -eq 1 ]; then LogText "Test: trying to guess virtualization with dmidecode" - FIND=$(/usr/sbin/dmidecode -s system-product-name | awk '{ print $1 }') + FIND=$(${DMIDECODEBINARY} -s system-product-name | awk '{ print $1 }') if [ -n "${FIND}" ]; then LogText "Result: found ${FIND}" SHORT="${FIND}" @@ -1794,6 +1793,7 @@ else LogText "Result: skipped dmidecode test, as we already found machine type" fi + # Other options # SaltStack: salt-call grains.get virtual # < needs snippet > @@ -1864,7 +1864,7 @@ fi # Check if we caught some string along all tests - if [ ! "${SHORT}" = "" ]; then + if [ -n "${SHORT}" ]; then # Lowercase and see if we found a match SHORT=$(echo ${SHORT} | awk '{ print $1 }' | tr '[:upper:]' '[:lower:]') @@ -2020,6 +2020,7 @@ PackageIsInstalled() { exit_code=255 + # First parameter is package name (or __dummy__ for initial test to see if package manager is available and works as expected) if [ $# -eq 1 ]; then package="$1" else @@ -2041,6 +2042,9 @@ elif [ -n "${PKG_BINARY}" ]; then output=$(${PKG_BINARY} -N info ${package} >/dev/null 2>&1) exit_code=$? # 0=package installed, 70=invalid package + elif [ -n "${PKGINFOBINARY}" ]; then + output=$(${PKGINFOBINARY} -q -e ${package} >/dev/null 2>&1) + exit_code=$? # 0=package installed, 1=package not installed elif [ -n "${RPMBINARY}" ]; then output=$(${RPMBINARY} --quiet -q ${package} > /dev/null 2>&1) exit_code=$? @@ -2050,8 +2054,25 @@ elif [ -n "${ZYPPERBINARY}" ]; then output=$(${ZYPPERBINARY} --quiet --non-interactive search --installed -i ${package} 2> /dev/null | grep "^i") if [ -n "${output}" ]; then exit_code=0; else exit_code=1; fi + elif [ -n "${XBPSBINARY}" ]; then + output=$(${XBPSBINARY} ${package} 2> /dev/null | ${GREPBINARY} "^ii") + exit_code=$? else - ReportException "PackageIsInstalled:01" + if [ "${package}" != "__dummy__" ]; then + ReportException "PackageIsInstalled:01 (test=${TEST_NO:-unknown})" + fi + fi + + # Give thumbs up if dummy package is used during initial test for package manager availability + if [ "${package}" = "__dummy__" ]; then + # There should be no positive match on this dummy package + if [ ${exit_code} -eq 0 ]; then + exit_code=1 + elif [ ${exit_code} -eq 255 ]; then + exit_code=1 + else + exit_code=0 + fi fi return ${exit_code} @@ -2159,7 +2180,8 @@ for I in ${FIND}; do I=$(echo ${I} | sed 's/:space:/ /g' | sed 's/;$//' | sed 's/ #.*$//') OPTION=$(echo ${I} | awk '{ print $1 }') - VALUE=$(echo ${I}| cut -d' ' -f2-) + # Use quotes here to prevent wildcard expansion + VALUE=$(echo "${I}"| cut -d' ' -f2-) LogText "Result: found option ${OPTION} in ${CONFIG_FILE} with value '${VALUE}'" STORE_SETTING=1 case ${OPTION} in @@ -2282,9 +2304,25 @@ done if [ ${FOUND} -eq 0 ]; then NGINX_CONF_FILES_ADDITIONS="${NGINX_CONF_FILES_ADDITIONS} ${VALUE}"; fi # Check for additional config files included as follows - # "include sites-enabled/*.conf" - elif [ $(echo ${VALUE} | grep -F -c "*.conf") -gt 0 ]; then - for FOUND_CONF in $(ls ${CONFIG_FILE%nginx.conf}${VALUE%;*}); do + # "include sites-enabled/*.conf" (relative path) + # "include /etc/nginx/sites-enabled/*.conf" (absolute path) + elif [ $(echo "${VALUE}" | grep -F -c "*.conf") -gt 0 ]; then + # Check if path is absolute or relative + case $VALUE in + /*) + # Absolute path, so wildcard pattern is already correct + CONF_WILDCARD=${VALUE%;*} + ;; + *) + # Relative path, so construct absolute path for wildcard pattern + CONF_WILDCARD=${CONFIG_FILE%nginx.conf}${VALUE%;*} + ;; + esac + for FOUND_CONF in ${CONF_WILDCARD}; do + if [ "${FOUND_CONF}" = "${CONF_WILDCARD}" ]; then + LogText "Found no match for wildcard pattern: ${CONF_WILDCARD}" + break + fi FOUND=0 for CONF in ${NGINX_CONF_FILES}; do if [ "${CONF}" = "${FOUND_CONF}" ]; then FOUND=1; LogText "Found this file already in our configuration files array, not adding to queue"; fi @@ -2494,8 +2532,8 @@ Register() { # Do not insert a log break, if previous test was not logged if [ ${SKIPLOGTEST} -eq 0 ]; then LogTextBreak; fi - ROOT_ONLY=0; SKIPTEST=0; SKIPLOGTEST=0; SKIPREASON=""; TEST_NEED_OS=""; PREQS_MET="" - TEST_CATEGORY=""; TEST_NEED_NETWORK=""; TEST_NEED_PLATFORM="" + ROOT_ONLY=0; SKIPTEST=0; SKIPLOGTEST=0; SKIPREASON=""; PREQS_MET="" + TEST_CATEGORY=""; TEST_NEED_NETWORK=""; TEST_NEED_OS=""; TEST_NEED_PKG_MGR=0; TEST_NEED_PLATFORM="" TOTAL_TESTS=$((TOTAL_TESTS + 1)) while [ $# -ge 1 ]; do case $1 in @@ -2519,6 +2557,9 @@ shift TEST_NEED_OS=$1 ;; + --package-manager-required) + TEST_NEED_PKG_MGR=1 + ;; --preqs-met) shift PREQS_MET=$1 @@ -2562,7 +2603,7 @@ CURRENT_TS=$(GetTimestamp) if [ ${PREVIOUS_TS} -gt 0 ]; then SLOW_TEST=0 - TIME_THRESHOLD=10 # seconds + TIME_THRESHOLD=$SLOW_TEST_THRESHOLD # seconds # Calculate timing and determine if we use seconds or nanoseconds (more precise) TIME_DIFF=$((CURRENT_TS - PREVIOUS_TS)) @@ -2631,6 +2672,9 @@ # Check for correct hardware platform if [ ${SKIPTEST} -eq 0 -a -n "${TEST_NEED_PLATFORM}" -a ! "${HARDWARE}" = "${TEST_NEED_PLATFORM}" ]; then SKIPTEST=1; SKIPREASON="Incorrect hardware platform"; fi + # Check for required (and discovered) package manager + if [ ${SKIPTEST} -eq 0 -a ${TEST_NEED_PKG_MGR} -eq 1 -a ${HAS_PACKAGE_MANAGER} -eq 0 ]; then SKIPTEST=1; SKIPREASON="Requires a known package manager to test presence of a particular package"; fi + # Not all prerequisites met, like missing tool if [ ${SKIPTEST} -eq 0 -a "${PREQS_MET}" = "NO" ]; then SKIPTEST=1; if [ -z "${SKIPREASON}" ]; then SKIPREASON="Prerequisites not met (ie missing tool, other type of Linux distribution)"; fi; fi @@ -3641,4 +3685,4 @@ #================================================================================ # Lynis is part of Lynis Enterprise and released under GPLv3 license -# Copyright 2007-2019 - Michael Boelen, CISOfy - https://cisofy.com +# Copyright 2007-2020 - Michael Boelen, CISOfy - https://cisofy.com diff --git a/include/helper_audit_dockerfile b/include/helper_audit_dockerfile index a0efca38..a71326ee 100644 --- a/include/helper_audit_dockerfile +++ b/include/helper_audit_dockerfile @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -44,7 +44,7 @@ fi ################################################################################################## # - InsertSection "Image" + InsertSection "${SECTION_IMAGE}" PKGMGR="" FIND=$(grep "^FROM" ${AUDIT_FILE} | sed 's/ /:space:/g') @@ -93,7 +93,7 @@ fi # ################################################################################################## # - InsertSection "Basics" + InsertSection "${SECTION_BASICS}" MAINTAINER=$(grep -E -i "*MAINTAINER" ${AUDIT_FILE} | sed 's/=/ /g' | cut -d'"' -f 2) if [ -z "${MAINTAINER}" ]; then @@ -127,7 +127,7 @@ fi # ################################################################################################## # - InsertSection "Software" + InsertSection "${SECTION_SOFTWARE}" case $PKGMGR in "apt") @@ -166,7 +166,7 @@ fi # ################################################################################################## # - InsertSection "Downloads" + InsertSection "${SECTION_DOWNLOADS}" FILE_DOWNLOAD=0 @@ -217,7 +217,7 @@ fi # ################################################################################################## # - InsertSection "Permissions" + InsertSection "${SECTION_PERMISSIONS}" FIND=$(grep -i "chmod 777" ${AUDIT_FILE}) if HasData "${FIND}"; then diff --git a/include/helper_configure b/include/helper_configure index 4e0dd654..029ab4f7 100644 --- a/include/helper_configure +++ b/include/helper_configure @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -72,7 +72,7 @@ ExitFatal fi - FIND=$(echo ${HELPER_PARAMERS} | grep " ") + FIND=$(echo ${HELPER_PARAMS} | grep " ") if [ ! "${FIND}" = "" ]; then ${ECHOCMD} "Found invalid character (space) in configuration string"; ExitFatal; fi CONFIGURE_SETTINGS=$(echo $2 | sed 's/:/ /g') diff --git a/include/helper_generate b/include/helper_generate index 30044705..f3a8d909 100644 --- a/include/helper_generate +++ b/include/helper_generate @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -51,8 +51,10 @@ if [ $# -gt 0 ]; then ;; *) # xxd does not exist on FreeBSD - HOSTID=$(head -c20 < /dev/urandom | hexdump -ve '"%.2x"') - HOSTID2=$(head -c32 < /dev/urandom | hexdump -ve '"%.2x"') + # Note: hexdump may omit leading or trailing zeroes. + # Take 100 characters as input, turn to hex, then take first 40/64. + HOSTID=$(head -c100 < /dev/urandom | hexdump -ve '"%.2x"' | head -c40) + HOSTID2=$(head -c100 < /dev/urandom | hexdump -ve '"%.2x"' | head -c64) ;; esac diff --git a/include/helper_show b/include/helper_show index 923f4496..e251aad0 100644 --- a/include/helper_show +++ b/include/helper_show @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -30,7 +30,7 @@ COMMANDS="audit configure generate show update upload-only" HELPERS="audit configure show update" -OPTIONS="--auditor\n--cronjob (--cron)\n--debug\n--developer\n--devops\n--forensics\n--help (-h)\n--log-file\n--manpage (--man)\n--no-colors\n--no-log\n--pentest\n--profile\n--plugin-dir\n--quick (-Q)\n--quiet (-q)\n--report-file\n--reverse-colors\n--skip-plugins\n--tests\n--tests-from-category\n--tests-from-group\n--usecwd\n--upload\n--verbose\n--version (-V)\n--wait\n--warnings-only" +OPTIONS="--auditor\n--cronjob (--cron)\n--debug\n--developer\n--devops\n--forensics\n--help (-h)\n--log-file\n--manpage (--man)\n--no-colors\n--no-log\n--no-plugins\n--pentest\n--profile\n--plugin-dir\n--quick (-Q)\n--quiet (-q)\n--report-file\n--reverse-colors\n--tests\n--tests-from-category\n--tests-from-group\n--usecwd\n--upload\n--verbose\n--version (-V)\n--wait\n--warnings-only" SHOW_ARGS="categories changelog commands dbdir details environment eol groups help hostids includedir language license logfile man options os pidfile plugindir profiles release releasedate report settings tests version workdir" SHOW_HELP="lynis show ${BROWN}categories${NORMAL} (display test categories) @@ -245,7 +245,7 @@ if [ $# -gt 0 ]; then shift if [ $# -eq 1 ]; then TESTID="$1" - awk -v search="Performing test ID $TESTID" '$0 ~ search {++f;p=1}p&&f==1;/===---/{p=0}' ${LOGFILE} + awk -v search="Performing test ID $TESTID" '$0 ~ search {++f;p=1}p&&f==1;/====/{p=0}' ${LOGFILE} fi fi ;; @@ -265,14 +265,15 @@ if [ $# -gt 0 ]; then fi ;; "eol") + ${ECHOCMD} "Operating-system=${OS_FULLNAME}" if [ ${EOL} -eq 0 ]; then - ${ECHOCMD} "OS end-of-life: No" + ${ECHOCMD} "End-of-life=No" elif [ ${EOL} -eq 1 ]; then - ${ECHOCMD} "OS end-of-life: Yes" + ${ECHOCMD} "End-of-life=Yes" elif [ ${EOL} -eq 255 ]; then - ${ECHOCMD} "OS end-of-life: Not tested" + ${ECHOCMD} "End-of-life=Not tested" else - ${ECHOCMD} "OS end-of-life: Unknown" + ${ECHOCMD} "End-of-life=Unknown" fi ;; "groups") diff --git a/include/helper_system_remote_scan b/include/helper_system_remote_scan index 15aaf249..8f9df294 100644 --- a/include/helper_system_remote_scan +++ b/include/helper_system_remote_scan @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com diff --git a/include/helper_update b/include/helper_update index dedbed4d..cc5f672c 100644 --- a/include/helper_update +++ b/include/helper_update @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com diff --git a/include/osdetection b/include/osdetection index f06b23b6..1596ed10 100644 --- a/include/osdetection +++ b/include/osdetection @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -62,6 +62,7 @@ 10.13 | 10.13.[0-9]*) OS_FULLNAME="macOS High Sierra (${OS_VERSION})" ;; 10.14 | 10.14.[0-9]*) OS_FULLNAME="macOS Mojave (${OS_VERSION})" ;; 10.15 | 10.15.[0-9]*) OS_FULLNAME="macOS Catalina (${OS_VERSION})" ;; + 11.0 | 11.0[0-9]*) OS_FULLNAME="macOS Big Sur (${OS_VERSION})" ;; *) echo "Unknown macOS version. Do you know what version it is? Create an issue at ${PROGRAM_SOURCE}" ;; esac else @@ -139,12 +140,18 @@ # Generic if [ -e /etc/os-release ]; then + OS_FULLNAME=$(awk -F= '/^PRETTY_NAME=/ {print substr($2,2,length($2)-2)}' /etc/os-release) OS_ID=$(grep "^ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') if [ -n "${OS_ID}" ]; then case ${OS_ID} in + "alpine") + LINUX_VERSION="Alpine Linux" + OS_NAME=$(grep "^PRETTY_NAME=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + OS_VERSION_FULL=$(grep "^VERSION=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + ;; "amzn") LINUX_VERSION="Amazon Linux" - OS_FULLNAME=$(grep "^PRETTY_NAME=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') OS_NAME="Amazon Linux" OS_REDHAT_OR_CLONE=1 OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') @@ -156,30 +163,83 @@ ;; "centos") LINUX_VERSION="CentOS" - OS_FULLNAME=$(grep "^PRETTY_NAME=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') OS_NAME="CentOS Linux" OS_REDHAT_OR_CLONE=1 OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') ;; "clear-linux-os") LINUX_VERSION="Clear Linux OS" - OS_FULLNAME=$(grep "^PRETTY_NAME=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') OS_NAME="Clear Linux OS" OS_REDHAT_OR_CLONE=1 OS_VERSION="Rolling release" ;; + "cloudlinux") + LINUX_VERSION="CloudLinux" + OS_NAME="CloudLinux" + OS_REDHAT_OR_CLONE=1 + OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + ;; "coreos") LINUX_VERSION="CoreOS" - OS_FULLNAME=$(grep "^PRETTY_NAME=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') OS_NAME="CoreOS Linux" OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') ;; "debian") LINUX_VERSION="Debian" - OS_FULLNAME=$(grep "^PRETTY_NAME=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + OS_NAME="Debian" + OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + OS_VERSION_FULL=$(grep "^VERSION=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + ;; + "elementary") + LINUX_VERSION="elementary OS" + OS_NAME="elementary OS" + OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + OS_VERSION_FULL=$(grep "^VERSION=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + ;; + "endeavouros") + LINUX_VERSION="EndeavourOS" + OS_NAME="EndeavourOS" + OS_VERSION="Rolling release" + OS_VERSION_FULL="Rolling release" + ;; + "fedora") + LINUX_VERSION="Fedora" + OS_NAME="Fedora Linux" + OS_REDHAT_OR_CLONE=1 + OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + ;; + "flatcar") + LINUX_VERSION="Flatcar" + LINUX_VERSION_LIKE="CoreOS" + OS_NAME="Flatcar Linux" + OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + ;; + "gentoo") + LINUX_VERSION="Gentoo" + OS_NAME="Gentoo Linux" + OS_VERSION="Rolling release" + ;; + "ipfire") + LINUX_VERSION="IPFire" + OS_NAME="IPFire" + OS_VERSION=$(grep "^VERSION=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + ;; + "kali") + LINUX_VERSION="Kali" + OS_NAME="Kali Linux" + OS_VERSION="Rolling release" + ;; + "linuxmint") + LINUX_VERSION="Linux Mint" + OS_NAME="Linux Mint" + OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + OS_VERSION_FULL=$(grep "^VERSION=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + ;; + "mageia") + LINUX_VERSION="Mageia" + OS_NAME="Mageia" OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') OS_VERSION_FULL=$(grep "^VERSION=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') - OS_NAME="Debian" ;; "manjaro") LINUX_VERSION="Manjaro" @@ -187,55 +247,100 @@ OS_NAME="Manjaro" OS_VERSION="Rolling release" ;; + "nixos") + LINUX_VERSION="NixOS" + OS_NAME="NixOS" + OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + OS_VERSION_FULL=$(grep "^VERSION=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + ;; + "ol") + LINUX_VERSION="Oracle Linux" + OS_NAME="Oracle Linux" + OS_REDHAT_OR_CLONE=1 + OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + ;; "opensuse-tumbleweed") LINUX_VERSION="openSUSE Tumbleweed" - OS_FULLNAME=$(grep "^PRETTY_NAME=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') # It's rolling release but has a snapshot version (the date of the snapshot) OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') OS_NAME="openSUSE" ;; "opensuse-leap") LINUX_VERSION="openSUSE Leap" - OS_FULLNAME=$(grep "^PRETTY_NAME=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') OS_NAME="openSUSE" ;; - "ubuntu") - LINUX_VERSION="Ubuntu" - OS_FULLNAME=$(grep "^PRETTY_NAME=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + "pop") + LINUX_VERSION="Pop!_OS" OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') OS_VERSION_FULL=$(grep "^VERSION=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') - OS_NAME="Ubuntu" + OS_NAME="Pop!_OS" + ;; + "pureos") + LINUX_VERSION="PureOS" + OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + OS_VERSION_FULL=$(grep "^VERSION=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + OS_NAME="PureOS" ;; "raspbian") LINUX_VERSION="Raspbian" - OS_FULLNAME=$(grep "^PRETTY_NAME=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') OS_VERSION_FULL=$(grep "^VERSION=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') OS_NAME="Raspbian" ;; "rhel") LINUX_VERSION="RHEL" - OS_NAME=$(grep "^PRETTY_NAME=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + OS_NAME="RHEL" OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') OS_VERSION_FULL=$(grep "^VERSION=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') OS_FULLNAME="${OS_NAME} ${OS_VERSION_FULL}" OS_REDHAT_OR_CLONE=1 ;; + "rosa") + LINUX_VERSION="ROSA Linux" + OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + OS_VERSION_FULL=$(grep "^VERSION=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + OS_NAME="ROSA Linux" + ;; "slackware") LINUX_VERSION="Slackware" - OS_FULLNAME=$(grep "^PRETTY_NAME=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') OS_NAME="Slackware Linux" OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') OS_VERSION_FULL=$(grep "^VERSION=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') ;; + "sles") + LINUX_VERSION="SLES" + OS_NAME="openSUSE" + OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + OS_VERSION_FULL=$(grep "^PRETTY_NAME=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + ;; + "ubuntu") + LINUX_VERSION="Ubuntu" + OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + OS_VERSION_FULL=$(grep "^VERSION=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + OS_NAME="Ubuntu" + ;; + "void") + LINUX_VERSION="Void Linux" + OS_VERSION="Rolling release" + OS_NAME="Void Linux" + ;; + "zorin") + LINUX_VERSION="Zorin OS" + OS_NAME="Zorin OS" + OS_VERSION=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + OS_VERSION_FULL=$(grep "^VERSION=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + ;; *) - ReportException "OS Detection" "Unknown OS found in /etc/os-release" + ReportException "OS Detection" "Unknown OS found in /etc/os-release - Please create issue on GitHub project page: ${PROGRAM_SOURCE}" ;; esac fi fi + # Alpine + if [ -e "/etc/alpine-release" ]; then LINUX_VERSION="Alpine Linux"; OS_VERSION=$(cat /etc/alpine-release); fi + # Amazon if [ -z "${LINUX_VERSION}" -a -e "/etc/system-release" ]; then FIND=$(grep "^Amazon" /etc/system-release) @@ -337,13 +442,6 @@ LINUX_VERSION="Fedora" fi - # Mageia (has also /etc/megaia-release) - FIND=$(grep "Mageia" /etc/redhat-release) - if [ ! "${FIND}" = "" ]; then - OS_FULLNAME=$(grep "^Mageia" /etc/redhat-release) - OS_VERSION=$(grep "^Mageia" /etc/redhat-release | awk '{ if ($2=="release") { print $3 } }') - LINUX_VERSION="Mageia" - fi # Oracle Enterprise Linux FIND=$(grep "Enterprise Linux Enterprise Linux Server" /etc/redhat-release) @@ -481,12 +579,89 @@ SYSCTL_READKEY="" ;; - # Solaris / OpenSolaris + # Solaris / OpenSolaris / Ilumos ... SunOS) OS="Solaris" - OS_NAME="Sun Solaris" - OS_FULLNAME=$(uname -s -r) - OS_VERSION=$(uname -r) + OS_KERNELVERSION=$(uname -v) + OPENSOLARIS=0 + + if [ -f /etc/os-release ]; then + OS_ID=$(grep "^ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + OS_VERSION=$(grep "^VERSION=" /etc/os-release | awk -F= '{print $2}' | tr -d '"') + OS_FULLNAME=$(awk -F= '/^PRETTY_NAME=/ {print substr($2,2,length($2)-2)}' /etc/os-release) + case "${OS_ID}" in + "solaris") + OS_NAME="Oracle Solaris" + ;; + "omnios") + OS_NAME="OmniOS" + OPENSOLARIS=1 + ;; + "tribblix") + OS_NAME="Tribblix" + OS_FULLNAME="Tribblix ${OS_VERSION}" + OPENSOLARIS=1 + ;; + "*") + ReportException "OS Detection" "Unknown OS found in /etc/os-release - Please create issue on GitHub project page: ${PROGRAM_SOURCE}" + ;; + esac + elif [ "$(uname -o 2> /dev/null)" == "illumos" ]; then + OPENSOLARIS=1 + + # Solaris has a free form text file with release information + if grep "OpenIndiana" /etc/release > /dev/null; then + OS_NAME="OpenIndiana" + if grep "Hipster" /etc/release > /dev/null; then + OS_VERSION="$(tr ' ' '\n' < /etc/release | grep '[[:digit:]]\.[[:digit:]]')" + OS_FULLNAME="OpenIndiana Hipster $OS_VERSION" + else + OS_VERSION="Unknown" + OS_FULLNAME="OpenIndiana (unknown edition)" + fi + elif grep "OmniOS" /etc/release > /dev/null; then + OS_NAME="OmniOS" + OS_VERSION="$(tr ' ' '\n' < /etc/release | grep 'r[[:digit:]]')" + if grep "Community Edition" /etc/release > /dev/null; then + OS_FULLNAME="OmniOS Community Edition v11 $OS_VERSION" + fi + elif grep "SmartOS" /etc/release > /dev/null; then + OS_NAME="SmartOS" + OS_VERSION="-" + OS_FULLNAME="SmartOS" + else + OS_NAME="Unknown Illumos" + fi + elif grep "SchilliX" /etc/release > /dev/null; then + OS_NAME="SchilliX" + OS_FULLNAME="$(head -n 1 /etc/release | xargs)" + OS_VERSION="$(echo "$OS_FULLNAME" | cut -d '-' -f 2)" + + OPENSOLARIS=1 + elif head -n 1 < /etc/release | grep "Oracle Solaris" > /dev/null; then + OS_NAME="Oracle Solaris" + OS_FULLNAME="$(head -n 1 /etc/release | xargs)" + OS_VERSION="$(head -n 1 < /etc/release | xargs | cut -d ' ' -f 3)" + elif head -n 1 < /etc/release | xargs | grep "^Solaris " > /dev/null; then + OS_NAME="Sun Solaris" + # Example of /etc/release: + # Solaris 10 5/08 + # ... + # Solaris 10 10/09 (Update 8) + # The first line does not contain the "Update" number, + # only if present. + if tail -1 < /etc/release | xargs | grep "^Solaris " > /dev/null; then + OS_FULLNAME=$(tail -1 < /etc/release | xargs) + else + OS_FULLNAME=$(head -1 < /etc/release | xargs) + fi + OS_VERSION=$(echo "$OS_FULLNAME" | cut -d ' ' -f 2,3) + else # Old behaviour + OS_NAME="Sun Solaris" + OS_FULLNAME=$(uname -s -r) + OS_VERSION=$(uname -r) + fi + HARDWARE=$(uname -m) if [ -x /usr/bin/isainfo ]; then # Returns 32, 64 @@ -572,13 +747,17 @@ EOL_TIMESTAMP=$(awk -v value="${FIND}" -F: '{if ($1=="os" && value ~ $2){print $4}}' ${DBDIR}/software-eol.db | head -n 1) if [ -n "${EOL_TIMESTAMP}" ]; then EOL_DATE=$(awk -v value="${FIND}" -F: '{if ($1=="os" && value ~ $2){print $3}}' ${DBDIR}/software-eol.db | head -n 1) - NOW=$(date "+%s") - if [ -n "${NOW}" ]; then - if [ ${NOW} -gt ${EOL_TIMESTAMP} ]; then - EOL=1 - else - EOL=0 + if [ -n "${EOL_DATE}" ]; then + NOW=$(date "+%s") + if [ -n "${NOW}" ]; then + if [ ${NOW} -gt ${EOL_TIMESTAMP} ]; then + EOL=1 + else + EOL=0 + fi fi + else + EOL=0 fi fi fi diff --git a/include/parameters b/include/parameters index e682824f..242899e6 100644 --- a/include/parameters +++ b/include/parameters @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -270,7 +270,7 @@ ;; # Don't use colors - --no-colors | --nocolors | --no-colours | --nocolours) + --no-colors | --nocolors | --no-colour | --nocolour) COLORS=0 RemoveColors ;; @@ -280,6 +280,11 @@ LOGFILE="/dev/null" ;; + # Skip execution of plugins + --no-plugins | --noplugins | --skip-plugins) + SKIP_PLUGINS=1 + ;; + --pen-test | --pentest) PENTESTINGMODE=1 ;; @@ -332,7 +337,7 @@ ;; # Strip the colors which aren't clearly visible on light backgrounds - --reverse-colors| --reverse-colours) + --reverse-colors | --reverse-colour) BLUE="${NORMAL}"; SECTION="${NORMAL}"; NOTICE="${NORMAL}"; @@ -359,11 +364,6 @@ fi ;; - # Skip execution of plugins - --skip-plugins | --no-plugins | --noplugins) - SKIP_PLUGINS=1 - ;; - # Only scan these tests --tests) shift @@ -423,6 +423,23 @@ QUIET=1 ;; + # Warning when test is slow + --slow-warning) + if [ $# -gt 1 ]; then + shift + + if [ "$1" -gt 0 ] 2>/dev/null; then + SLOW_TEST_THRESHOLD="$1" + else + echo "Argument has to be number." + exit 1 + fi + else + echo "Specify threshold as number of seconds above which should Lynis warn about long test." + exit 1 + fi + ;; + --tests-category | --tests-categories | --view-categories | --list-categories | --show-categories) echo "Error: Deprecated option ($1)" exit 1 diff --git a/include/profiles b/include/profiles index f1bfb326..e7a25670 100644 --- a/include/profiles +++ b/include/profiles @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -35,23 +35,32 @@ # Show deprecation message for old config entries such as 'config:' and 'apache:' FOUND=0 - DATA=$(grep -E "^[a-z-]{1,}:" ${PROFILE} | od -An -ta | sed 's/ /!space!/g') # od -An (no file offset), -ta (named character, to be on safe side) + DATA=$(grep -E "^[a-z-]{1,}:" ${PROFILE}) if ! IsEmpty "${DATA}"; then FOUND=1; fi if [ ${FOUND} -eq 1 ]; then + Display --text " " + Display --text "==================================================================================================" DisplayWarning "Your profile contains old-style configuration entries. See log file for more details and how to convert these entries" - LogText "Your profile has one or more configuration items that are in an old format (lines starting with key:value). They need to be converted into the new format (key=value)." - LogText "Tip: Use grep to see the relevant matches (grep -E \"^[a-z-]{1,}:\" custom.prf)" - sleep 30 + Display --indent 2 --text "* ${RED}ISSUE${NORMAL}" + Display --indent 2 --text "Your profile has one or more lines that are in an old format (key:value). They need to be converted into the new format (key=value) or disabled." + Display --text " " + Display --indent 2 --text "* ${GREEN}HOW TO RESOLVE${NORMAL}" + Display --indent 2 --text "Use grep to see the relevant matches (grep -E \"^[a-z-]{1,}:\" custom.prf)" + Display --text " " + Display --text "==================================================================================================" + Display --text " " + LogText "Insight: Profile '${PROFILE}' contains one or more old-style configuration entries" + ReportWarning "GEN-0020" "Your profile contains one or more old-style configuration entries" + sleep 10 fi # Security check for unexpected and possibly harmful escape characters (hyphen should be listed as first or last character) - DATA=$(grep -Ev '^$|^ |^#|^config:' "${PROFILE}" | tr -d '[:alnum:]/\[\]\(\)_\|,\.:;= \n\r-' | od -An -ta | sed 's/ /!space!/g') + DATA=$(grep -Ev '^$|^ |^#|^config:' "${PROFILE}" | tr -d '[:alnum:]/\[\]\(\)_\|,\.:;= \n\r-') if ! IsEmpty "${DATA}"; then DisplayWarning "Your profile '${PROFILE}' contains unexpected characters. See the log file for more information." LogText "Found unexpected or possibly harmful characters in profile '${PROFILE}'. See which characters matched in the output below and compare them with your profile." - for I in ${DATA}; do - I=$(echo ${I} | sed 's/!space!/ /g') + for I in $(printf ${DATA} | od -An -ta); do LogText "Output: ${I}" done LogText "Suggestion: comment incorrect lines with a '#' and try again. Open a GitHub issue if valid characters are blocked" @@ -367,6 +376,13 @@ AddSetting "ssl-certificate-paths-to-ignore" "${SSL_CERTIFICATE_PATHS_TO_IGNORE}" "Paths that should be ignored for SSL certificates" ;; + # Check also certificates provided by packages? + ssl-certificate-include-packages) + FIND=$(echo "${VALUE}" | grep -E "^(1|true|yes)") && SSL_CERTIFICATE_INCLUDE_PACKAGES=1 + Debug "Check also certificates provided by packages set to ${SSL_CERTIFICATE_INCLUDE_PACKAGES}" + ;; + + # Set strict mode for development and quality purposes strict) FIND=$(echo "${VALUE}" | grep -E "^(1|true|yes)") && SET_STRICT=1 @@ -532,7 +548,7 @@ ################################################################################# # if [ -n "${DEPRECATED_OPTION}" ]; then - ReportWarning "LYNIS" "One or more deprecated options used" "${DEPRECATED_OPTION}" "Update your profile" + ReportWarning "GEN-0030" "One or more deprecated options used in profile" "${DEPRECATED_OPTION}" "Update your profile" fi # ################################################################################# @@ -540,7 +556,6 @@ Display --indent 2 --text "- Checking profiles..." --result "DONE" --color GREEN -LogTextBreak #================================================================================ # Lynis - Security Auditing and System Hardening for Linux and UNIX - https://cisofy.com diff --git a/include/report b/include/report index 815dfd03..3d0c7fdf 100644 --- a/include/report +++ b/include/report @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -151,14 +151,14 @@ fi # Show suggestions from logfile - SSUGGESTIONS=$(${GREPBINARY} 'Suggestion: ' ${LOGFILE} | sed 's/ /!space!/g') + SUGGESTIONS=$(${GREPBINARY} 'Suggestion: ' ${LOGFILE} | sed 's/ /!space!/g') - if [ -z "${SSUGGESTIONS}" ]; then + if [ -z "${SUGGESTIONS}" ]; then echo " ${OK}No suggestions${NORMAL}"; echo "" else echo " ${YELLOW}Suggestions${NORMAL} (${TOTAL_SUGGESTIONS}):" echo " ${WHITE}----------------------------${NORMAL}" - for SUGGESTION in ${SSUGGESTIONS}; do + for SUGGESTION in ${SUGGESTIONS}; do SOLUTION="" SHOWSUGGESTION=$(echo ${SUGGESTION} | sed 's/!space!/ /g' | sed 's/^.* Suggestion: //' | sed 's/\[details:\(.*\)\] \[solution:\(.*\)\]//' | sed 's/test://') ADDLINK=$(echo ${SUGGESTION} | sed 's/!space!/ /g' | sed 's/^.* Suggestion: \(.*\)\[test://' | sed 's/\]\(.*\)]//' | ${AWKBINARY} -F: '{print $1}') @@ -183,7 +183,7 @@ done fi # Show tip on how to continue (next steps) - if [ ! "${SWARNINGS}" = "" -o ! "${SSUGGESTIONS}" = "" ]; then + if [ ! "${SWARNINGS}" = "" -o ! "${SUGGESTIONS}" = "" ]; then echo " ${CYAN}Follow-up${NORMAL}:" echo " ${WHITE}----------------------------${NORMAL}" echo " ${WHITE}-${NORMAL} Show details of a test (lynis show details TEST-ID)" diff --git a/include/tests_accounting b/include/tests_accounting index 4d05f4d6..dd1ef2a8 100644 --- a/include/tests_accounting +++ b/include/tests_accounting @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -18,7 +18,7 @@ # ################################################################################# # - InsertSection "Accounting" + InsertSection "${SECTION_ACCOUNTING}" # ################################################################################# # @@ -123,8 +123,19 @@ Display --indent 2 --text "- Checking sysstat accounting data" --result "${STATUS_DISABLED}" --color WHITE ReportSuggestion "${TEST_NO}" "Enable sysstat to collect accounting (cron disabled)" fi + elif [ -f "${ROOTDIR}lib/systemd/system/sysstat.service" ] || [ -f "${ROOTDIR}etc/systemd/system/sysstat.service" ]; then + LogText "Result: sysstat systemd unit found" + if [ -L "${ROOTDIR}etc/systemd/system/multi-user.target.wants/sysstat.service" ]; then + # Assuming -collect.timer and -summary.timer are enabled as well, + # as they are usually in the install section. + LogText "Result: sysstat enabled via systemd" + Display --indent 2 --text "- Checking sysstat accounting data" --result "${STATUS_ENABLED}" --color GREEN + else + LogText "Result: sysstat disabled via systemd" + Display --indent 2 --text "- Checking sysstat accounting data" --result "${STATUS_DISABLED}" --color WHITE + fi else - LogText "Result: sysstat not found via ${ROOTDIR}etc/default/sysstat or ${ROOTDIR}etc/cron.d/sysstat" + LogText "Result: sysstat not found via ${ROOTDIR}etc/default/sysstat or ${ROOTDIR}etc/cron.d/sysstat or as a systemd unit" Display --indent 2 --text "- Checking sysstat accounting data" --result "${STATUS_NOT_FOUND}" --color YELLOW ReportSuggestion "${TEST_NO}" "Enable sysstat to collect accounting (no results)" fi @@ -413,4 +424,4 @@ WaitForKeyPress # #================================================================================ -# Lynis - Copyright 2007-2019, Michael Boelen / CISOfy - https://cisofy.com +# Lynis - Copyright 2007-2020, Michael Boelen / CISOfy - https://cisofy.com diff --git a/include/tests_authentication b/include/tests_authentication index 786bec64..ce2205ca 100644 --- a/include/tests_authentication +++ b/include/tests_authentication @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -31,7 +31,7 @@ # ################################################################################# # - InsertSection "Users, Groups and Authentication" + InsertSection "${SECTION_USERS_GROUPS_AND_AUTHENTICATION}" # Test : AUTH-9204 # Description : Check users with UID zero (0) @@ -157,51 +157,7 @@ # Test : AUTH-9218 # Description : Check login shells for passwordless accounts # Notes : Results should be checked - Register --test-no AUTH-9218 --os FreeBSD --weight L --network NO --category security --description "Check login shells for passwordless accounts" - if [ ${SKIPTEST} -eq 0 ]; then - FOUND=0 - LogText "Test: Checking login shells" - if [ -f ${ROOTDIR}etc/master.passwd ]; then - # Check for all shells, except: (/usr)/sbin/nologin /nonexistent - FIND=$(${GREPBINARY} "[a-z]:\*:" /etc/master.passwd | ${EGREPBINARY} -v '^#|/sbin/nologin|/usr/sbin/nologin|/nonexistent' | ${SEDBINARY} 's/ /!space!/g') - if [ "${FIND}" = "" ]; then - Display --indent 2 --text "- Login shells" --result "${STATUS_OK}" --color GREEN - else - Display --indent 2 --text "- Login shells" --result "${STATUS_WARNING}" --color RED - for LINE in ${FIND}; do - LINE=$(echo ${LINE} | ${SEDBINARY} 's/!space!/ /g') - SHELL=$(echo ${LINE} | ${AWKBINARY} -F: '{ print $10 }') - LogText "Output: ${LINE}" - if [ -z "${SHELL}" ]; then - LogText "Result: found no shell on line" - else - LogText "Result: found possible harmful shell ${SHELL}" - if [ -f ${SHELL} ]; then - LogText "Result: shell ${SHELL} does exist" - FOUND=1 - else - LogText "Result: shell ${SHELL} does not exist" - ReportSuggestion "${TEST_NO}" "Determine if account is needed, as shell ${SHELL} does not exist" - fi - fi - done - if [ ${FOUND} -eq 1 ]; then - ReportWarning "${TEST_NO}" "Possible harmful shell found (for passwordless account!)" - fi - fi - else - Display --indent 2 --text "- Login shells" --result "${STATUS_SKIPPED}" --color WHITE - LogText "Result: No /etc/master.passwd file found" - fi - unset LINE SHELL - fi -# -################################################################################# -# - # Test : AUTH-9489 - # Description : Check login shells for passwordless accounts - # Notes : Results should be checked - Register --test-no AUTH-9489 --os DragonFly --weight L --network NO --category security --description "Check login shells for passwordless accounts" + Register --test-no AUTH-9218 --os "DragonFly FreeBSD NetBSD OpenBSD" --root-only YES --weight L --network NO --category security --description "Check login shells for passwordless accounts" if [ ${SKIPTEST} -eq 0 ]; then FOUND=0 LogText "Test: Checking login shells" @@ -302,7 +258,7 @@ FIND=$(${ROOTDIR}usr/sbin/pwck -q -r 2> /dev/null; echo $?) TESTED=1 ;; - "Solaris") + "Solaris" | "HP-UX") FIND=$(${ROOTDIR}usr/sbin/pwck 2> /dev/null; echo $?) TESTED=1 ;; @@ -326,12 +282,131 @@ # ################################################################################# # + # Test : AUTH-9229 + # Description : Check password hashing methods vs. recommendations in crypt(5) + # Notes : Applicable to all Unix-like OS + # Requires read access to /etc/shadow (if it exists) + + ParsePasswordEntry() { + METHOD=$1 + case ${METHOD} in + 1:\* | 1:x | 0: | *:!* | *LOCK*) + # disabled | shadowed | no password | locked account (can be literal *LOCK* or something like LOCKED) + ;; + *:\$5\$*| *:\$6\$*) + # sha256crypt | sha512crypt: check number of rounds, should be >5000 + ROUNDS=$(echo "${METHOD}" | sed -n 's/.*rounds=\([0-9]*\)\$.*/\1/gp') + if [ -z "${ROUNDS}" ]; then + echo 'sha256crypt/sha512crypt(default<=5000rounds)' + elif [ "${ROUNDS}" -le 5000 ]; then + echo 'sha256crypt/sha512crypt(<=5000rounds)' + fi + ;; + *:\$y\$* | *:\$gy\$* | *:\$2b\$* | *:\$7\$*) + # yescrypt | gost-yescrypt | bcrypt | scrypt + ;; + *:_*) + echo bsdicrypt + ;; + *:\$1\$*) + echo md5crypt + ;; + *:\$3\$*) + echo NT + ;; + *:\$md5*) + echo SunMD5 + ;; + *:\$sha1*) + echo sha1crypt + ;; + 13:* | 178:*) + echo bigcrypt/descrypt + ;; + *) + echo "Unknown password hashing method ${METHOD}. Please report to lynis-dev@cisofy.com" + ;; + esac + } + + Register --test-no AUTH-9229 --root-only YES --weight L --network NO --category security --description "Check password hashing methods" + if [ ${SKIPTEST} -eq 0 ]; then + LogText "Test: Checking password hashing methods" + SHADOW=""; + if [ -e ${ROOTDIR}etc/shadow ]; then SHADOW="${ROOTDIR}etc/shadow"; fi + FIND=$(${CAT_BINARY} ${ROOTDIR}etc/passwd ${SHADOW} | ${AWKBINARY} -F : '{print length($2) ":" $2 }' | while read METHOD; do + ParsePasswordEntry ${METHOD} + done | ${SORTBINARY} -u | ${TRBINARY} '\n' ' ') + if [ -z "${FIND}" ]; then + Display --indent 2 --text "- Password hashing methods" --result "${STATUS_OK}" --color GREEN + LogText "Result: no poor password hashing methods found" + AddHP 2 2 + else + Display --indent 2 --text "- Password hashing methods" --result "${STATUS_SUGGESTION}" --color YELLOW + LogText "Result: poor password hashing methods found: ${FIND}" + ReportSuggestion "${TEST_NO}" "Check PAM configuration, add rounds if applicable and expire passwords to encrypt with new values" + AddHP 0 2 + fi + fi +# +################################################################################# +# + # Test : AUTH-9230 + # Description : Check group password hashing rounds in login.defs + # Notes : Applicable to all Unix-like OS + PREQS_MET="NO" + if [ -f ${ROOTDIR}etc/login.defs ]; then + PREQS_MET="YES" + fi + Register --test-no AUTH-9230 --preqs-met ${PREQS_MET} --root-only NO --weight L --network NO --category security --description "Check group password hashing rounds" + if [ ${SKIPTEST} -eq 0 ]; then + LogText "Test: Checking SHA_CRYPT_MIN_ROUNDS option in ${ROOTDIR}etc/login.defs" + FIND=$(${GREPBINARY} "^SHA_CRYPT_MIN_ROUNDS" ${ROOTDIR}etc/login.defs | ${AWKBINARY} '{ if ($1=="SHA_CRYPT_MIN_ROUNDS") { print $2 } }') + if [ -z "${FIND}" -o "${FIND}" = "0" ]; then + LogText "Result: number of minimum rounds used by the encryption algorithm is not configured" + Display --indent 2 --text "- Checking minimum group password hashing rounds" --result "${STATUS_DISABLED}" --color YELLOW + ReportSuggestion "${TEST_NO}" "Configure minimum encryption algorithm rounds in /etc/login.defs" + AddHP 0 2 + elif [ "${FIND}" -lt 5000 ]; then + LogText "Result: low number of minimum encryption algorithm rounds found: ${FIND}" + PASSWORD_MINIMUM_ROUNDS=${FIND} + Display --indent 2 --text "- Group password hashing rounds (minimum)" --result "${STATUS_SUGGESTION}" --color YELLOW + AddHP 1 2 + else + LogText "Result: number of encryption algorithm rounds is ${FIND}" + PASSWORD_MINIMUM_ROUNDS=${FIND} + Display --indent 2 --text "- Group password hashing rounds (minimum)" --result CONFIGURED --color GREEN + AddHP 2 2 + fi + + LogText "Test: Checking SHA_CRYPT_MAX_ROUNDS option in ${ROOTDIR}etc/login.defs" + FIND=$(${GREPBINARY} "^SHA_CRYPT_MAX_ROUNDS" ${ROOTDIR}etc/login.defs | ${AWKBINARY} '{ if ($1=="SHA_CRYPT_MAX_ROUNDS") { print $2 } }') + if [ -z "${FIND}" -o "${FIND}" = "0" ]; then + LogText "Result: number of maximum rounds used by the encryption algorithm is not configured" + Display --indent 2 --text "- Checking maximum group password hashing rounds" --result "${STATUS_DISABLED}" --color YELLOW + ReportSuggestion "${TEST_NO}" "Configure maximum encryption algorithm rounds in /etc/login.defs" + AddHP 0 2 + elif [ "${FIND}" -lt 10000 ]; then + LogText "Result: low number of maximum encryption algorithm rounds found: ${FIND}" + PASSWORD_MINIMUM_ROUNDS=${FIND} + Display --indent 2 --text "- Group password hashing rounds (maximum)" --result "${STATUS_SUGGESTION}" --color YELLOW + AddHP 1 2 + else + LogText "Result: number of encryption algorithm rounds is ${FIND}" + PASSWORD_MINIMUM_ROUNDS=${FIND} + Display --indent 2 --text "- Group password hashing rounds (maximum)" --result CONFIGURED --color GREEN + AddHP 2 2 + fi + fi +# +################################################################################# +# # Test : AUTH-9234 # Description : Query user accounts # Notes : AIX: 100+ # HPUX: 100+ # macOS doesn't have any user info in /etc/passwd, users are managed with opendirectoryd) - # OpenBSD/NetBSD: unknown + # OpenBSD/NetBSD: 1000-60000, excluding 32767 (default) # Arch Linux / CentOS / Ubuntu: 1000+ Register --test-no AUTH-9234 --weight L --network NO --category security --description "Query user accounts" if [ ${SKIPTEST} -eq 0 ]; then @@ -373,9 +448,21 @@ fi ;; - "OpenBSD") - LogText "OpenBSD real users output (ID = 0, or 1000-60000, but not 32767):" - FIND=$(${AWKBINARY} -F: '($3 >= 1000 && $3 <= 60000 && $3 != 32767) || ($3 == 0) { print $1","$3 }' /etc/passwd) + "NetBSD"|"OpenBSD") + if [ -f ${ROOTDIR}etc/usermgmt.conf ]; then + UID_RANGE=$(${GREPBINARY} "^range" ${ROOTDIR}etc/usermgmt.conf | ${AWKBINARY} '{ sub(/\.\./, "-", $2); print $2 }') + fi + if [ -n "${UID_RANGE}" ]; then + LogText "Result: found configured user id range specified: ${UID_RANGE}" + UID_MIN=$(echo $UID_RANGE | ${AWKBINARY} -F- '{ print $1 }') + UID_MAX=$(echo $UID_RANGE | ${AWKBINARY} -F- '{ print $2 }') + else + UID_MIN=1000 + UID_MAX=60000 + LogText "Result: no configured user id range specified; using default ${UID_MIN}-${UID_MAX}" + fi + LogText "${OS} real users output (ID = 0, or ${UID_MIN}-${UID_MAX}, but not 32767):" + FIND=$(${AWKBINARY} -v UID_MIN="${UID_MIN}" -v UID_MAX="${UID_MAX}" -F: '($3 >= UID_MIN && $3 <= UID_MAX && $3 != 32767) || ($3 == 0) { print $1","$3 }' /etc/passwd) ;; "Solaris") @@ -415,7 +502,7 @@ FIND=$(${EGREPBINARY} "^passwd" /etc/nsswitch.conf | ${EGREPBINARY} "compat|nisplus") if [ -z "${FIND}" ]; then LogText "Result: NIS+ authentication not enabled" - Display --indent 2 --text "- NIS+ authentication support" --result "NOT ENABLED" --color WHITE + Display --indent 2 --text "- NIS+ authentication support" --result "${STATUS_NOT_ENABLED}" --color WHITE else FIND2=$(${EGREPBINARY} "^passwd_compat" ${ROOTDIR}etc/nsswitch.conf | ${GREPBINARY} "nisplus") FIND3=$(${EGREPBINARY} "^passwd" ${ROOTDIR}etc/nsswitch.conf | ${GREPBINARY} "nisplus") @@ -424,7 +511,7 @@ Display --indent 2 --text "- NIS+ authentication support" --result "${STATUS_ENABLED}" --color GREEN else LogText "Result: NIS+ authentication not enabled" - Display --indent 2 --text "- NIS+ authentication support" --result "NOT ENABLED" --color WHITE + Display --indent 2 --text "- NIS+ authentication support" --result "${STATUS_NOT_ENABLED}" --color WHITE fi fi else @@ -442,7 +529,7 @@ FIND=$(${EGREPBINARY} "^passwd" /etc/nsswitch.conf | ${EGREPBINARY} "compat|nis" | ${GREPBINARY} -v "nisplus") if [ -z "${FIND}" ]; then LogText "Result: NIS authentication not enabled" - Display --indent 2 --text "- NIS authentication support" --result "NOT ENABLED" --color WHITE + Display --indent 2 --text "- NIS authentication support" --result "${STATUS_NOT_ENABLED}" --color WHITE else FIND2=$(${EGREPBINARY} "^passwd_compat" /etc/nsswitch.conf | ${GREPBINARY} "nis" | ${GREPBINARY} -v "nisplus") FIND3=$(${EGREPBINARY} "^passwd" /etc/nsswitch.conf | ${GREPBINARY} "nis" | ${GREPBINARY} -v "nisplus") @@ -451,7 +538,7 @@ Display --indent 2 --text "- NIS authentication support" --result "${STATUS_ENABLED}" --color GREEN else LogText "Result: NIS authentication not enabled" - Display --indent 2 --text "- NIS authentication support" --result "NOT ENABLED" --color WHITE + Display --indent 2 --text "- NIS authentication support" --result "${STATUS_NOT_ENABLED}" --color WHITE fi fi else @@ -497,7 +584,7 @@ if [ -d "${SUDOERS_D}" ]; then LogText "Test: checking drop-in directory (${SUDOERS_D})" FIND=$(${LSBINARY} -ld ${SUDOERS_D} | ${CUTBINARY} -c 2-10) - FIND2=$(${LSBINARY} -nd ${SUDOERS_D} | ${AWKBINARY} '{print $3$4}') + FIND2=$(${LSBINARY} -lnd ${SUDOERS_D} | ${AWKBINARY} '{print $3$4}') LogText "Result: Found directory permissions: ${FIND} and owner UID GID: ${FIND2}" case "${FIND}" in rwx[r-][w-][x-]--- ) @@ -525,7 +612,7 @@ for f in ${SUDO_CONFIG_FILES}; do LogText "Test: checking file (${f})" FIND=$(${LSBINARY} -l ${f} | ${CUTBINARY} -c 2-10) - FIND2=$(${LSBINARY} -n ${f} | ${AWKBINARY} '{print $3$4}') + FIND2=$(${LSBINARY} -ln ${f} | ${AWKBINARY} '{print $3$4}') LogText "Result: Found file permissions: ${FIND} and owner UID GID: ${FIND2}" case "${FIND}" in r[w-]-[r-][w-]---- ) @@ -677,7 +764,7 @@ LogText "Result: directory /etc/pam.d exists" Display --indent 2 --text "- PAM configuration files (pam.d)" --result "${STATUS_FOUND}" --color GREEN LogText "Test: searching PAM configuration files" - FIND=$(${FINDBINARY} ${ROOTDIR}etc/pam.d -not -name "*.pam-old" -type f -print | sort) + FIND=$(${FINDBINARY} ${ROOTDIR}etc/pam.d \! -name "*.pam-old" -type f -print | sort) for FILE in ${FIND}; do LogText "Found file: ${FILE}" done @@ -691,9 +778,9 @@ # # Test : AUTH-9268 # Description : Searching available PAM files - # Notes : PAM is used on AIX, FreeBSD, Linux, HPUX, Solaris - if [ ${OS} = "AIX" -o ${OS} = "Linux" -o ${OS} = "HPUX" -o ${OS} = "Solaris" ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi - Register --test-no AUTH-9268 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Checking presence pam.d files" + # Notes : PAM is used on AIX, FreeBSD, Linux, HPUX, NetBSD, Solaris + OS_USES_PAM="AIX DragonFly FreeBSD Linux HPUX NetBSD Solaris" + Register --test-no AUTH-9268 --os "${OS_USES_PAM}" --weight L --network NO --category security --description "Checking presence pam.d files" if [ ${SKIPTEST} -eq 0 ]; then FOUND=0 LogText "Test: Searching pam modules" @@ -762,7 +849,7 @@ # ################################################################################# # - # Test : AUTH-9282 and AUTH-9283 + # Test : AUTH-9282, AUTH-9283, and AUTH-9284 # Note : Every Linux based operating system seem to have different passwd # options, so we have to check the version first. if [ "${OS}" = "Linux" ]; then @@ -772,25 +859,29 @@ PREQS_MET="YES" FIND_P=$(passwd -a -S 2> /dev/null | ${AWKBINARY} '{ if ($2=="P" && $5=="99999") print $1 }') FIND2=$(passwd -a -S 2> /dev/null | ${AWKBINARY} '{ if ($2=="NP") print $1 }') + FIND3=$(passwd -a -S 2> /dev/null | ${AWKBINARY} '{ if ($2=="L") print $1 }' | sort | uniq) ;; *) PREQS_MET="YES" FIND_P=$(passwd --all --status 2> /dev/null | ${AWKBINARY} '{ if ($2=="P" && $5=="99999") print $1 }') FIND2=$(passwd --all --status 2> /dev/null | ${AWKBINARY} '{ if ($2=="NP") print $1 }') + FIND3=$(passwd --all --status 2> /dev/null | ${AWKBINARY} '{ if ($2=="L") print $1 }' | sort | uniq) ;; esac elif [ "${OS_REDHAT_OR_CLONE}" -eq 1 ]; then PREQS_MET="YES" FIND_P=$(for I in $(${AWKBINARY} -F: '{print $1}' "${ROOTDIR}etc/passwd") ; do passwd -S "$I" | ${AWKBINARY} '{ if ($2=="PS" && $5=="99999") print $1 }' ; done) FIND2=$(for I in $(${AWKBINARY} -F: '{print $1}' "${ROOTDIR}etc/passwd") ; do passwd -S "$I" | ${AWKBINARY} '{ if ($2=="NP") print $1 }' ; done) + FIND3=$(for I in $(${AWKBINARY} -F: '{print $1}' "${ROOTDIR}etc/passwd") ; do passwd -S "$I" | ${AWKBINARY} '{ if ($2=="L" || $2=="LK") print $1 }' | sort | uniq ; done) else LogText "Result: skipping test for this Linux version" ReportManual "AUTH-9282:01" PREQS_MET="NO" FIND_P="" FIND2="" + FIND3="" fi - else + else PREQS_MET="NO" fi @@ -811,11 +902,10 @@ ReportSuggestion "${TEST_NO}" "When possible set expire dates for all password protected accounts" fi fi -# -################################################################################# -# + # Test : AUTH-9283 # Description : Search passwordless accounts + # Notes : requires FIND2 variable Register --test-no AUTH-9283 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Checking accounts without password" if [ "${SKIPTEST}" -eq 0 ]; then LogText "Test: Checking passwordless accounts" @@ -832,6 +922,38 @@ ReportWarning "${TEST_NO}" "Found accounts without password" fi fi + + # Test : AUTH-9284 + # Description : Check locked user accounts in /etc/passwd + # Notes : requires FIND3 variable + Register --test-no AUTH-9284 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check locked user accounts in /etc/passwd" + if [ "${SKIPTEST}" -eq 0 ]; then + LogText "Test: Checking locked accounts" + NON_SYSTEM_ACCOUNTS=$(${AWKBINARY} -F : '$3 > 999 && $3 != 65534 {print $1}' ${ROOTDIR}etc/passwd | ${SORTBINARY} | ${UNIQBINARY}) + LOCKED_NON_SYSTEM_ACCOUNTS=0 + for account in ${FIND3}; do + if echo "${NON_SYSTEM_ACCOUNTS}" | ${GREPBINARY} -w "${account}" > /dev/null ; then + LOCKED_NON_SYSTEM_ACCOUNTS=$((LOCKED_NON_SYSTEM_ACCOUNTS + 1)) + fi + done + if [ ${LOCKED_NON_SYSTEM_ACCOUNTS} -eq 0 ]; then + LogText "Result: all accounts seem to be unlocked" + Display --indent 2 --text "- Locked accounts" --result "${STATUS_OK}" --color GREEN + else + LogText "Result: found one or more locked accounts" + for account in ${FIND3}; do + if echo "${NON_SYSTEM_ACCOUNTS}" | ${GREPBINARY} -w "${account}" > /dev/null ; then + LogText "Locked account: ${account}" + Report "locked_account[]=${account}" + fi + done + Display --indent 2 --text "- Locked accounts" --result "${STATUS_FOUND}" --color RED + ReportSuggestion "${TEST_NO}" "Look at the locked accounts and consider removing them" + fi + unset account LOCKED_NON_SYSTEM_ACCOUNTS NON_SYSTEM_ACCOUNTS + fi + + unset FIND1 FIND2 FIND3 # ################################################################################# # @@ -946,7 +1068,7 @@ # Test : AUTH-9306 # Description : Check if authentication is needed to boot the system # Notes : :d_boot_authenticate: is a good option for production machines to - # avoid unauthorized booting of systems. Option :d_boot_autentication@: + # avoid unauthorized booting of systems. Option :d_boot_authentication@: # disabled a required login. Register --test-no AUTH-9306 --os HP-UX --weight L --network NO --category security --description "Check single boot authentication" if [ ${SKIPTEST} -eq 0 ]; then @@ -1353,7 +1475,7 @@ if [ ${FOUND} -eq 1 ]; then Display --indent 2 --text "- Checking account locking" --result "${STATUS_ENABLED}" --color GREEN else - Display --indent 2 --text "- Checking account locking" --result "NOT ENABLED" --color YELLOW + Display --indent 2 --text "- Checking account locking" --result "${STATUS_NOT_ENABLED}" --color YELLOW fi fi # @@ -1367,7 +1489,7 @@ FIND=$(${EGREPBINARY} "^passwd" ${ROOTDIR}etc/nsswitch.conf | ${GREPBINARY} "ldap") if [ "${FIND}" = "" ]; then LogText "Result: LDAP authentication not enabled" - Display --indent 2 --text "- LDAP authentication support" --result "NOT ENABLED" --color WHITE + Display --indent 2 --text "- LDAP authentication support" --result "${STATUS_NOT_ENABLED}" --color WHITE else LogText "Result: LDAP authentication enabled" Display --indent 2 --text "- LDAP authentication support" --result "${STATUS_ENABLED}" --color GREEN diff --git a/include/tests_banners b/include/tests_banners index 7fa94da6..f7e4d7e9 100644 --- a/include/tests_banners +++ b/include/tests_banners @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -22,7 +22,7 @@ # ################################################################################# # - InsertSection "Banners and identification" + InsertSection "${SECTION_BANNERS_AND_IDENTIFICATION}" # ################################################################################# # diff --git a/include/tests_boot_services b/include/tests_boot_services index 2c239b64..7d6feeec 100644 --- a/include/tests_boot_services +++ b/include/tests_boot_services @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -22,7 +22,7 @@ # ################################################################################# # - InsertSection "Boot and services" + InsertSection "${SECTION_BOOT_AND_SERVICES}" # ################################################################################# # @@ -139,6 +139,13 @@ SERVICE_MANAGER="launchd" fi ;; + "Solaris") + if [ -n "${ROOTDIR}usr/bin/svcs" ]; then + SERVICE_MANAGER="SMF (svcs)" + elif [ -d "${ROOTDIR}etc/init.d" ]; then + SERVICE_MANAGER="SysV Init" + fi + ;; *) LogText "Result: unknown service manager" ;; @@ -183,6 +190,21 @@ # ################################################################################# # + # Test : BOOT-5109 + # Description : Check for rEFInd + Register --test-no BOOT-5109 --os "Linux" --weight L --network NO --root-only YES --category security --description "Check rEFInd as bootloader" + if [ ${SKIPTEST} -eq 0 ]; then + BOOT_LOADER_SEARCHED=1 + FileExists ${ROOTDIR}boot/refind_linux.conf + if [ ${FILE_FOUND} -eq 1 ]; then + LogText "Result: found rEFInd" + BOOT_LOADER="rEFInd" + BOOT_LOADER_FOUND=1 + fi + fi +# +################################################################################# +# # Test : BOOT-5116 # Description : Check if system is booted in UEFI mode Register --test-no BOOT-5116 --weight L --network NO --root-only YES --category security --description "Check if system is booted in UEFI mode" @@ -316,34 +338,50 @@ Register --test-no BOOT-5122 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check for GRUB boot password" if [ ${SKIPTEST} -eq 0 ]; then FOUND=0 - LogText "Found file ${GRUBCONFFILE}, proceeding with tests." - FileIsReadable ${GRUBCONFFILE} - if [ ${CANREAD} -eq 1 ]; then - FIND=$(${GREPBINARY} 'password --md5' ${GRUBCONFFILE} | ${GREPBINARY} -v '^#') - FIND2=$(${GREPBINARY} 'password --encrypted' ${GRUBCONFFILE} | ${GREPBINARY} -v '^#') - FIND3=$(${GREPBINARY} 'set superusers' ${GRUBCONFFILE} | ${GREPBINARY} -v '^#') - FIND4=$(${GREPBINARY} 'password_pbkdf2' ${GRUBCONFFILE} | ${GREPBINARY} -v '^#') - FIND5=$(${GREPBINARY} 'grub.pbkdf2' ${GRUBCONFFILE} | ${GREPBINARY} -v '^#') - # GRUB1: Password should be set (MD5 or SHA1) - if [ -n "${FIND}" -o -n "${FIND2}" ]; then - FOUND=1 - # GRUB2: Superusers AND password should be defined - elif [ -n "${FIND3}" ]; then - if [ -n "${FIND4}" -o -n "${FIND5}" ]; then FOUND=1; fi + + if [ -d "${ROOTDIR}etc/grub.d" ]; then + CONF_FILES=$(${FINDBINARY} "${ROOTDIR}etc/grub.d" -type f -name "[0-9][0-9]*" -print0 | ${TRBINARY} '\0' ' ' | ${TRBINARY} -d '[:cntrl:]') + CONF_FILES="${GRUBCONFFILE} ${ROOTDIR}boot/grub/custom.cfg ${CONF_FILES}" + else + CONF_FILES="${GRUBCONFFILE} ${ROOTDIR}boot/grub/custom.cfg" + fi + + for FILE in ${CONF_FILES}; do + if [ -f "${FILE}" ]; then + LogText "Found file ${FILE}, proceeding with tests." + if FileIsReadable "${FILE}"; then + FIND=$(${GREPBINARY} 'password --md5' ${FILE} | ${GREPBINARY} -v '^#') + FIND2=$(${GREPBINARY} 'password --encrypted' ${FILE} | ${GREPBINARY} -v '^#') + FIND3=$(${GREPBINARY} 'set superusers' ${FILE} | ${GREPBINARY} -v '^#') + FIND4=$(${GREPBINARY} 'password_pbkdf2' ${FILE} | ${GREPBINARY} -v '^#') + FIND5=$(${GREPBINARY} 'grub.pbkdf2' ${FILE} | ${GREPBINARY} -v '^#') + # GRUB1: Password should be set (MD5 or SHA1) + if [ -n "${FIND}" -o -n "${FIND2}" ]; then + FOUND=1 + # GRUB2: Superusers AND password should be defined + elif [ -n "${FIND3}" ]; then + if [ -n "${FIND4}" -o -n "${FIND5}" ]; then FOUND=1; fi + else + LogText "Result: did not find hashed password line in this file" + fi + else + LogText "Result: Can not read '${FILE}' (no permission?)" + fi + else + LogText "Result: File '${FILE}' does not exist" fi - if [ ${FOUND} -eq 1 ]; then + done + if [ ${FOUND} -eq 1 ]; then Display --indent 4 --text "- Checking for password protection" --result "${STATUS_OK}" --color GREEN LogText "Result: GRUB has password protection." AddHP 4 4 - else + else Display --indent 4 --text "- Checking for password protection" --result "${STATUS_NONE}" --color RED - LogText "Result: Didn't find hashed password line in GRUB boot file!" - ReportSuggestion "${TEST_NO}" "Set a password on GRUB bootloader to prevent altering boot configuration (e.g. boot in single user mode without password)" + LogText "Result: Didn't find hashed password line in GRUB configuration" + ReportSuggestion "${TEST_NO}" "Set a password on GRUB boot loader to prevent altering boot configuration (e.g. boot in single user mode without password)" AddHP 0 2 - fi - else - LogText "Result: Can not read ${GRUBCONFFILE} (no permission)" fi + unset CONF_FILES FILE FIND FIND2 FIND3 FIND4 FIND5 FOUND fi # ################################################################################# @@ -556,6 +594,55 @@ # ################################################################################# # + # Test : BOOT-5170 + # Description : Check for Solaris boot daemons + Register --test-no BOOT-5170 --os Solaris --weight L --network NO --category security --description "Check for Solaris boot daemons" + if [ ${SKIPTEST} -eq 0 ]; then + if [ -n "${SVCSBINARY}" ]; then + LogText "Result: Using svcs binary to check for daemons" + LogText "SysV style services may be incorrectly counted as running." + + Report "running_service_tool=svcs" + + # For the documentation of the states (field $1) see + # "Managing System Services in Oracle Solaris 11.4" pp. 24, available + # at https://docs.oracle.com/cd/E37838_01/pdf/E60998.pdf + + FIND=$("${SVCSBINARY}" -Ha | ${AWKBINARY} '{ if ($1 == "online" || $1 == "legacy_run") print $3 }') + COUNT=0 + for ITEM in ${FIND}; do + LogText "Found running daemon: ${ITEM}" + Report "running_service[]=${ITEM}" + COUNT=$((COUNT + 1 )) + done + Display --indent 2 --text "- Check running daemons (svcs)" --result "${STATUS_DONE}" --color GREEN + Display --indent 8 --text "Result: found ${COUNT} running daemons" + LogText "Result: Found ${COUNT} running daemons" + + LogText "Searching for enabled daemons (svcs)" + Report "boot_service_tool=svcs" + + FIND=$("${SVCSBINARY}" -Ha | ${AWKBINARY} '{ if ($1 != "disabled" && $1 != "uninitialized") print $3 }') + COUNT=0 + for ITEM in ${FIND}; do + LogText "Found enabled daemon at boot: ${ITEM}" + Report "boot_service[]=${ITEM}" + COUNT=$((COUNT + 1 )) + done + LogText "Note: Run svcs -a see all services" + Display --indent 2 --text "- Check enabled daemons at boot (svcs)" --result "${STATUS_DONE}" --color GREEN + Display --indent 8 --text "Result: found ${COUNT} enabled daemons at boot" + LogText "Result: Found ${COUNT} enabled daemons at boot" + fi + fi +# +################################################################################# +# + # Test : BOOT-5171 + # Description : Check for services with errors on solaris +# +################################################################################# +# # Test : BOOT-5177 # Description : Check for Linux boot services (systemd and chkconfig) # Notes : We skip using chkconfig if systemd is being used. @@ -579,7 +666,7 @@ LogText "Hint: Run systemctl --full --type=service to see all services" Display --indent 2 --text "- Check running services (systemctl)" --result "${STATUS_DONE}" --color GREEN Display --indent 8 --text "Result: found ${COUNT} running services" - LogText "Result: Found ${COUNT} enabled services" + LogText "Result: Found ${COUNT} running services" # Services at boot LogText "Searching for enabled services (systemctl services only)" @@ -594,7 +681,7 @@ LogText "Hint: Run systemctl list-unit-files --type=service to see all services" Display --indent 2 --text "- Check enabled services at boot (systemctl)" --result "${STATUS_DONE}" --color GREEN Display --indent 8 --text "Result: found ${COUNT} enabled services" - LogText "Result: Found ${COUNT} running services" + LogText "Result: Found ${COUNT} enabled services" else @@ -655,7 +742,7 @@ # # Test : BOOT-5184 # Description : Check world writable startup scripts - Register --test-no BOOT-5184 --os Linux --weight L --network NO --category security --description "Check permissions for boot files/scripts" + Register --test-no BOOT-5184 --os "Linux Solaris" --weight L --network NO --category security --description "Check permissions for boot files/scripts" if [ ${SKIPTEST} -eq 0 ]; then FOUND=0 CHECKDIRS="${ROOTDIR}etc/init.d ${ROOTDIR}etc/rc.d ${ROOTDIR}etc/rcS.d" @@ -822,7 +909,7 @@ # # Test : BOOT-5260 # Description : Check single user mode for systemd - Register --test-no BOOT-5260 --weight L --network NO --category security --description "Check single user mode for systemd" + Register --test-no BOOT-5260 --os Linux --weight L --network NO --category security --description "Check single user mode for systemd" if [ ${SKIPTEST} -eq 0 ]; then LogText "Test: Searching /usr/lib/systemd/system/rescue.service" if [ -f ${ROOTDIR}usr/lib/systemd/system/rescue.service ]; then @@ -960,6 +1047,44 @@ # ################################################################################# # + # Test : BOOT-5264 + # Description : Run systemd-analyze security + if [ -z "${SYSTEMDANALYZEBINARY}" ]; then SKIPREASON="systemd-analyze not available"; PREQS_MET="NO"; + else + SYSTEMD_VERSION=$("${SYSTEMDANALYZEBINARY}" --version | ${AWKBINARY} '/^systemd / {print $2}') + if [ "${SYSTEMD_VERSION}" -ge 240 ]; then PREQS_MET="YES"; else SKIPREASON="systemd-analyze too old (v${SYSTEMD_VERSION}), need at least v240"; PREQS_MET="NO"; fi + fi + Register --test-no BOOT-5264 --preqs-met ${PREQS_MET} --skip-reason "${SKIPREASON}" --os Linux --weight L --network NO --category security --description "Run systemd-analyze security" + if [ ${SKIPTEST} -eq 0 ]; then + LogText "Test: Run systemd-analyze security" + Display --indent 2 --text "- Running 'systemd-analyze security'" + ${SYSTEMDANALYZEBINARY} security | while read UNIT EXPOSURE PREDICATE HAPPY; do + if [ "${UNIT}" = "UNIT" ]; then + continue + fi + COLOR="BLACK" + case ${PREDICATE} in + PERFECT | SAFE | OK) + COLOR=GREEN + ;; + MEDIUM) + COLOR=WHITE + ;; + EXPOSED) + COLOR=YELLOW + ;; + UNSAFE | DANGEROUS) + COLOR=RED + ;; + esac + Display --indent 8 --text "- ${UNIT}:" --result "${PREDICATE}" --color "${COLOR}" + LogText "Result: ${UNIT}: ${EXPOSURE} ${PREDICATE}" + done + ReportSuggestion "${TEST_NO}" "Consider hardening system services" "Run '${SYSTEMDANALYZEBINARY} security SERVICE' for each service" + fi +# +################################################################################# +# Report "boot_loader=${BOOT_LOADER}" Report "boot_uefi_booted=${UEFI_BOOTED}" diff --git a/include/tests_containers b/include/tests_containers index cda52da7..78c12c50 100644 --- a/include/tests_containers +++ b/include/tests_containers @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -22,7 +22,7 @@ # ################################################################################# # - InsertSection "Containers" + InsertSection "${SECTION_CONTAINERS}" # ################################################################################# # @@ -226,4 +226,4 @@ WaitForKeyPress # #================================================================================ -# Lynis - Copyright 2007-2019, CISOfy - https://cisofy.com +# Lynis - Copyright 2007-2020, CISOfy - https://cisofy.com diff --git a/include/tests_crypto b/include/tests_crypto index 44f19cdc..af63d21a 100644 --- a/include/tests_crypto +++ b/include/tests_crypto @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -22,7 +22,11 @@ # ################################################################################# # - InsertSection "Cryptography" + RNG_FOUND=0 +# +################################################################################# +# + InsertSection "${SECTION_CRYPTOGRAPHY}" # ################################################################################# # @@ -50,7 +54,7 @@ LASTSUBDIR="" LogText "Result: found directory ${DIR}" # Search for certificate files - FILES=$(${FINDBINARY} ${DIR} -type f 2> /dev/null | ${EGREPBINARY} ".crt$|.pem$|^cert" | ${SORTBINARY} | ${SEDBINARY} 's/ /__space__/g') + FILES=$(${FINDBINARY} ${DIR} -type f 2> /dev/null | ${EGREPBINARY} ".cer$|.crt$|.der$|.pem$|^cert" | ${SORTBINARY} | ${SEDBINARY} 's/ /__space__/g') for FILE in ${FILES}; do FILE=$(echo ${FILE} | ${SEDBINARY} 's/__space__/ /g') # See if we need to skip this path @@ -63,7 +67,7 @@ SKIP=0 # Now check if this path is on the to-be-ignored list for D in ${SSL_CERTIFICATE_PATHS_TO_IGNORE}; do - if Equals "${D}" "${SUBDIR}"; then + if ContainsString "${D}" "${SUBDIR}"; then SKIP=1 LogText "Result: skipping directory (${SUBDIR}) as it is on ignore list" fi @@ -74,18 +78,25 @@ COUNT_DIR=$((COUNT_DIR + 1)) FileIsReadable "${FILE}" if [ ${CANREAD} -eq 1 ]; then - # Only check the files that are not installed by a package - if ! FileInstalledByPackage "${FILE}"; then + # Only check the files that are not installed by a package, unless enabled by profile + if [ ${SSL_CERTIFICATE_INCLUDE_PACKAGES} -eq 1 ] || ! FileInstalledByPackage "${FILE}"; then + echo ${FILE} | ${EGREPBINARY} --quiet ".cer$|.der$" + CER_DER=$? OUTPUT=$(${GREPBINARY} -q 'BEGIN CERT' "${FILE}") - if [ $? -eq 0 ]; then + if [ $? -eq 0 -o ${CER_DER} -eq 0 ]; then LogText "Result: file is a certificate file" - FIND=$(${OPENSSLBINARY} x509 -noout -in "${FILE}" -enddate 2> /dev/null | ${GREPBINARY} "^notAfter") + if [ ${CER_DER} -eq 0 ]; then + SSL_DER_OPT="-inform der" + else + SSL_DER_OPT= + fi + FIND=$(${OPENSSLBINARY} x509 -noout ${SSL_DER_OPT} -in "${FILE}" -enddate 2> /dev/null | ${GREPBINARY} "^notAfter") if [ $? -eq 0 ]; then # Check certificate where 'end date' has been expired - FIND=$(${OPENSSLBINARY} x509 -noout -checkend 0 -in "${FILE}" -enddate 2> /dev/null) + FIND=$(${OPENSSLBINARY} x509 -noout ${SSL_DER_OPT} -checkend 0 -in "${FILE}" -enddate 2> /dev/null) EXIT_CODE=$? - CERT_CN=$(${OPENSSLBINARY} x509 -noout -subject -in "${FILE}" 2> /dev/null | ${SEDBINARY} -e 's/^subject.*CN=\([a-zA-Z0-9\.\-\*]*\).*$/\1/') - CERT_NOTAFTER=$(${OPENSSLBINARY} x509 -noout -enddate -in "${FILE}" 2> /dev/null | ${AWKBINARY} -F= '{if ($1=="notAfter") { print $2 }}') + CERT_CN=$(${OPENSSLBINARY} x509 -noout ${SSL_DER_OPT} -subject -in "${FILE}" 2> /dev/null | ${SEDBINARY} -e 's/^subject.*CN=\([a-zA-Z0-9\.\-\*]*\).*$/\1/') + CERT_NOTAFTER=$(${OPENSSLBINARY} x509 -noout ${SSL_DER_OPT} -enddate -in "${FILE}" 2> /dev/null | ${AWKBINARY} -F= '{if ($1=="notAfter") { print $2 }}') Report "certificate[]=${FILE}|${EXIT_CODE}|cn:${CERT_CN};notafter:${CERT_NOTAFTER};|" if [ ${EXIT_CODE} -eq 0 ]; then LogText "Result: certificate ${FILE} seems to be correct and still valid" @@ -174,6 +185,39 @@ # ################################################################################# # + # Test : CRYP-7931 + # Description : Determine if system uses encrypted swap + if [ -e "${SWAPONBINARY}" -a -e "${CRYPTSETUPBINARY}" ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi + Register --test-no CRYP-7931 --preqs-met ${PREQS_MET} --os Linux --weight L --network NO --root-only YES --category security --description "Determine if system uses encrypted swap" + if [ ${SKIPTEST} -eq 0 ]; then + ENCRYPTED_SWAPS=0 + UNENCRYPTED_SWAPS=0 + # Redirect errors, as RHEL 5/6 and others don't have the --show option + SWAPS=$(${SWAPONBINARY} --show=NAME --noheadings 2> /dev/null) + if [ $? -eq 0 ]; then + for BLOCK_DEV in ${SWAPS}; do + if ${CRYPTSETUPBINARY} isLuks "${BLOCK_DEV}" 2> /dev/null; then + LogText "Result: Found LUKS encrypted swap device: ${BLOCK_DEV}" + ENCRYPTED_SWAPS=$((ENCRYPTED_SWAPS + 1)) + Report "encrypted_swap[]=${BLOCK_DEV},LUKS" + elif ${CRYPTSETUPBINARY} status "${BLOCK_DEV}" 2> /dev/null | ${GREPBINARY} --quiet "cipher:"; then + LogText "Result: Found non-LUKS encrypted swap device: ${BLOCK_DEV}" + ENCRYPTED_SWAPS=$((ENCRYPTED_SWAPS + 1)) + Report "encrypted_swap[]=${BLOCK_DEV},other" + else + LogText "Result: Found unencrypted swap device: ${BLOCK_DEV}" + UNENCRYPTED_SWAPS=$((UNENCRYPTED_SWAPS +1)) + Report "non_encrypted_swap[]=${BLOCK_DEV}" + fi + done + Display --indent 2 --text "- Found ${ENCRYPTED_SWAPS} encrypted and ${UNENCRYPTED_SWAPS} unencrypted swap devices in use." --result OK --color WHITE + else + LogText "Result: skipping testing as swapon returned an error." + fi + fi +# +################################################################################# +# # Test : CRYP-8002 # Description : Gather available kernel entropy Register --test-no CRYP-8002 --os Linux --weight L --network NO --root-only NO --category security --description "Gather available kernel entropy" @@ -195,6 +239,64 @@ # ################################################################################# # + # Test : CRYP-8004 + # Description : Test for presence of hardware random number generators + Register --test-no CRYP-8004 --os Linux --weight L --network NO --root-only NO --category security --description "Presence of hardware random number generators" + if [ ${SKIPTEST} -eq 0 ]; then + LogText "Test: looking for ${ROOTDIR}sys/class/misc/hw_random/rng_current" + if [ -f "${ROOTDIR}sys/class/misc/hw_random/rng_current" ]; then + DATA=$(${HEADBINARY} -n 1 ${ROOTDIR}sys/class/misc/hw_random/rng_current | ${TRBINARY} -d '[[:cntrl:]]') + if [ "${DATA}" != "none" ]; then + LogText "Result: positive match, found RNG: ${DATA}" + if IsRunning "rngd"; then + Display --indent 2 --text "- HW RNG & rngd" --result "${STATUS_YES}" --color GREEN + LogText "Result: rngd is running" + RNG_FOUND=1 + else + Display --indent 2 --text "- HW RNG & rngd" --result "${STATUS_NO}" --color YELLOW + # TODO - enable suggestion when website has listing for this control + # ReportSuggestion "${TEST_NO}" "Utilize hardware random number generation by running rngd" + fi + else + Display --indent 2 --text "- HW RNG & rngd" --result "${STATUS_NO}" --color YELLOW + LogText "Result: no HW RNG available" + fi + else + Display --indent 2 --text "- HW RNG & rngd" --result "${STATUS_NO}" --color RED + LogText "Result: could not find ${ROOTDIR}sys/class/misc/hw_random/rng_current" + fi + fi +# +################################################################################# +# + # Test : CRYP-8005 + # Description : Test for presence of software pseudo random number generators + Register --test-no CRYP-8005 --os Linux --weight L --network NO --root-only NO --category security --description "Presence of software pseudo random number generators" + if [ ${SKIPTEST} -eq 0 ]; then + LogText "Test: looking for software pseudo random number generators" + FOUND="" + for SERVICE in audio-entropyd haveged jitterentropy-rngd; do + # Using --full as jitterentropy-rngd would otherwise not match + if IsRunning --full "${SERVICE}"; then + FOUND="${FOUND} ${SERVICE}" + fi + done + if [ -z "${FOUND}" ]; then + Display --indent 2 --text "- SW prng" --result "${STATUS_NO}" --color YELLOW + # ReportSuggestion "${TEST_NO}" "Utilize software pseudo random number generators" + else + RNG_FOUND=1 + Display --indent 2 --text "- SW prng" --result "${STATUS_YES}" --color GREEN + LogText "Result: found ${FOUND} running" + fi + fi +# +################################################################################# +# + Report "rng_found=${RNG_FOUND}" +# +################################################################################# +# WaitForKeyPress diff --git a/include/tests_databases b/include/tests_databases index f950fa9c..9c8e1de0 100644 --- a/include/tests_databases +++ b/include/tests_databases @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -39,7 +39,7 @@ # ################################################################################# # - InsertSection "Databases" + InsertSection "${SECTION_DATABASES}" # Test : DBS-1804 # Description : Check if MySQL is being used @@ -86,7 +86,7 @@ # "-u root --password=" avoids ~/.my.cnf authentication settings # "plugin = 'mysql_native_password' AND authentication_string = ''" avoids false positives when secure plugins are used - FIND=$(${MYSQLCLIENTBINARY} --no-defaults -u root --password= --silent --batch --execute="SELECT count(*) FROM mysql.user WHERE user = 'root' AND plugin = 'mysql_native_password' AND authentication_string = ''" mysql 2>/dev/null; echo $?) + FIND=$(${MYSQLCLIENTBINARY} --no-defaults -u root --password= --silent --batch --execute="SELECT count(*) FROM mysql.user WHERE user = 'root' AND plugin = 'mysql_native_password' AND authentication_string = ''" mysql > /dev/null 2>&1; echo $?) if [ "${FIND}" = "0" ]; then LogText "Result: Login succeeded, no MySQL root password set!" ReportWarning "${TEST_NO}" "No MySQL root password set" diff --git a/include/tests_dns b/include/tests_dns index 7e6109f5..085168d4 100644 --- a/include/tests_dns +++ b/include/tests_dns @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -45,11 +45,11 @@ # # if [ "${GOOD}" = "${TIMEOUT}" -a "${BAD}" = "${TIMEOUT}" ]; then # LogText "Result: received timeout, can't determine DNSSEC validation" -# Display --indent 4 --text "- Checking DNSSEC validation" --result "${STATUS_UNKOWN}" --color YELLOW +# Display --indent 4 --text "- Checking DNSSEC validation" --result "${STATUS_UNKNOWN}" --color YELLOW # #ReportException "${TEST_NO}" "Exception found, both query failed, due to connection timeout" # elif [ -z "${GOOD}" -a -n "${BAD}" ]; then # LogText "Result: good signature failed, yet bad signature was accepted" -# Display --indent 4 --text "- Checking DNSSEC validation" --result "${STATUS_UNKOWN}" --color YELLOW +# Display --indent 4 --text "- Checking DNSSEC validation" --result "${STATUS_UNKNOWN}" --color YELLOW # #ReportException "${TEST_NO}" "Exception found, OK failed, bad signature was accepted" # elif [ -n "${GOOD}" -a -n "${BAD}" ]; then # Display --indent 4 --text "- Checking DNSSEC validation" --result "${STATUS_SUGGESTION}" --color YELLOW diff --git a/include/tests_file_integrity b/include/tests_file_integrity index 36201fcf..c06b1703 100644 --- a/include/tests_file_integrity +++ b/include/tests_file_integrity @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -25,7 +25,7 @@ # ################################################################################# # - InsertSection "Software: file integrity" + InsertSection "${SECTION_FILE_INTEGRITY}" Display --indent 2 --text "- Checking file integrity tools" # ################################################################################# @@ -298,6 +298,107 @@ # ################################################################################# # + # Test : FINT-4339 + # Description : Check IMA/EVM status + if [ ! -z "${EVMCTLBINARY}" ]; then PREQS_MET="YES"; else PREQS_MET="NO"; SKIPREASON="No evmctl binary found"; fi + Register --test-no FINT-4339 --os Linux --preqs-met ${PREQS_MET} --skip-reason "${SKIPREASON}" --weight L --network NO --category security --description "Check IMA/EVM status" + if [ ${SKIPTEST} -eq 0 ]; then + FOUND=0 + if [ -e /sys/kernel/security/ima ]; then + FOUND=$(${CAT_BINARY} /sys/kernel/security/ima/runtime_measurements_count) + fi + if [ "${FOUND}" -ne 1 ]; then + LogText "Result: EVM tools found but IMA/EVM disabled" + Display --indent 2 --text "- IMA/EVM (status)" --result "${STATUS_DISABLED}" --color YELLOW + else + LogText "Result: EVM tools found, IMA/EVM enabled" + FILE_INT_TOOL="evmctl" + FILE_INT_TOOL_FOUND=1 + Display --indent 2 --text "- IMA/EVM (status)" --result "${STATUS_ENABLED}" --color GREEN + fi + fi +# +################################################################################# +# + # Test : FINT-4340 + # Description : Check dm-integrity status + if [ ! -z "${INTEGRITYSETUPBINARY}" ]; then PREQS_MET="YES"; else PREQS_MET="NO"; SKIPREASON="No integritysetup binary found"; fi + Register --test-no FINT-4340 --os Linux --preqs-met ${PREQS_MET} --skip-reason "${SKIPREASON}" --weight L --network NO --category security --description "Check dm-integrity status" + if [ ${SKIPTEST} -eq 0 ]; then + FOUND=0 + ROOTPROTECTED=0 + ROOTDEVICE=$(${MOUNTBINARY} | ${AWKBINARY} '/ on \/ type / { print $1 }') + for DEVICE in /dev/mapper/*; do + if [ -e "${DEVICE}" ]; then + FIND=$(${INTEGRITYSETUPBINARY} status "${DEVICE}" | ${EGREPBINARY} 'type:.*INTEGRITY') + if [ ! -z "${FIND}" ]; then + FOUND=1 + LogText "Result: found dm-integrity device ${DEVICE}" + if [ "${DEVICE}" = "${ROOTDEVICE}" ]; then + ROOTPROTECTED=1 + fi + fi + fi + done + if [ "${FOUND}" -ne 1 ]; then + LogText "Result: dm-integrity tools found but no active devices" + Display --indent 2 --text "- dm-integrity (status)" --result "${STATUS_DISABLED}" --color WHITE + else + LogText "Result: dm-integrity tools found, active devices" + if [ ${ROOTPROTECTED} -eq 1 ]; then + LogText "Result: root filesystem is protected by dm-integrity" + Display --indent 2 --text "- dm-integrity (status)" --result "${STATUS_ENABLED}" --color GREEN + else + LogText "Result: root filesystem is not protected by dm-integrity but active devices found" + Display --indent 2 --text "- dm-integrity (status)" --result "${STATUS_FOUND}" --color YELLOW + fi + FILE_INT_TOOL="dm-integrity" + FILE_INT_TOOL_FOUND=1 + Display --indent 2 --text "- dm-integrity (status)" --result "${STATUS_ENABLED}" --color GREEN + fi + fi +# +################################################################################# +# + # Test : FINT-4341 + # Description : Check dm-verity status + if [ ! -z "${VERITYSETUPBINARY}" ]; then PREQS_MET="YES"; else PREQS_MET="NO"; SKIPREASON="No veritysetup binary found"; fi + Register --test-no FINT-4341 --os Linux --preqs-met ${PREQS_MET} --skip-reason "${SKIPREASON}" --weight L --network NO --category security --description "Check dm-verity status" + if [ ${SKIPTEST} -eq 0 ]; then + FOUND=0 + ROOTPROTECTED=0 + ROOTDEVICE=$(${MOUNTBINARY} | ${AWKBINARY} '/ on \/ type / { print $1 }') + for DEVICE in /dev/mapper/*; do + if [ -e "${DEVICE}" ]; then + FIND=$(${VERITYSETUPBINARY} status "${DEVICE}" | ${EGREPBINARY} 'type:.*VERITY') + if [ ! -z "${FIND}" ]; then + FOUND=1 + LogText "Result: found dm-verity device ${DEVICE}" + if [ "${DEVICE}" = "${ROOTDEVICE}" ]; then + ROOTPROTECTED=1 + fi + fi + fi + done + if [ "${FOUND}" -ne 1 ]; then + LogText "Result: dm-verity tools found but no active devices" + Display --indent 2 --text "- dm-verity (status)" --result "${STATUS_DISABLED}" --color WHITE + else + LogText "Result: dm-verity tools found, active devices" + if [ ${ROOTPROTECTED} -eq 1 ]; then + LogText "Result: root filesystem is protected by dm-verity" + Display --indent 2 --text "- dm-verity (status)" --result "${STATUS_ENABLED}" --color GREEN + else + LogText "Result: root filesystem is not protected by dm-verity but active devices found" + Display --indent 2 --text "- dm-verity (status)" --result "${STATUS_FOUND}" --color YELLOW + fi + FILE_INT_TOOL="dm-verity" + FILE_INT_TOOL_FOUND=1 + fi + fi +# +################################################################################# +# # Test : FINT-4402 (was FINT-4316) # Description : Check if AIDE is configured to use SHA256 or SHA512 checksums if [ ! "${AIDEBINARY}" = "" -a -n "${AIDECONFIG}" ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi @@ -340,4 +441,4 @@ WaitForKeyPress # #================================================================================ -# Lynis - Copyright 2007-2019 Michael Boelen, CISOfy - https://cisofy.com +# Lynis - Copyright 2007-2020 Michael Boelen, CISOfy - https://cisofy.com diff --git a/include/tests_file_permissions b/include/tests_file_permissions index 35e28753..50ccdeee 100644 --- a/include/tests_file_permissions +++ b/include/tests_file_permissions @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -22,7 +22,7 @@ # ################################################################################# # - InsertSection "File Permissions" + InsertSection "${SECTION_FILE_PERMISSIONS}" # ################################################################################# # @@ -72,4 +72,4 @@ WaitForKeyPress # #================================================================================ -# Lynis - Copyright 2007-2019, CISOfy - https://cisofy.com +# Lynis - Copyright 2007-2020, CISOfy - https://cisofy.com diff --git a/include/tests_filesystems b/include/tests_filesystems index 798978e7..0de387f7 100644 --- a/include/tests_filesystems +++ b/include/tests_filesystems @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -28,7 +28,7 @@ # ################################################################################# # - InsertSection "File systems" + InsertSection "${SECTION_FILE_SYSTEMS}" # ################################################################################# # @@ -50,6 +50,7 @@ LogText "Result: directory ${I} exists" case "${OS}" in "AIX") FIND=$(${MOUNTBINARY} | ${AWKBINARY} -v MP=${I} '{ if ($2==MP) { print $2 }}') ;; + "HP-UX") FIND=$(${MOUNTBINARY} | ${AWKBINARY} -v MP=${I} '{ if ($1==MP) { print $1 }}') ;; *) FIND=$(${MOUNTBINARY} | ${AWKBINARY} -v MP=${I} '{ if ($3==MP) { print $3 }}') ;; esac @@ -211,10 +212,11 @@ ################################################################################# # # Test : FILE-6330 - # Description : Query all ZFS mounts from /etc/fstab + # Description : Query ZFS mounts + # Note : mount -p does not work under Linux Register --test-no FILE-6330 --os FreeBSD --weight L --network NO --category security --description "Checking ZFS file systems" if [ ${SKIPTEST} -eq 0 ]; then - LogText "Test: Query /etc/fstab for available ZFS mount points" + LogText "Test: Discover for available ZFS mount points" FIND=$(${MOUNTBINARY} -p | ${AWKBINARY} '{ if ($3 == "zfs") { print $1":"$2":"$3":"$4":" }}') if [ -z "${FIND}" ]; then Display --indent 2 --text "- Querying ZFS mount points (mount -p)" --result "${STATUS_NONE}" --color WHITE @@ -235,7 +237,7 @@ # Description : Query all HAMMER PFS mounts from /etc/fstab Register --test-no FILE-6439 --os DragonFly --weight L --network NO --category security --description "Checking HAMMER PFS mounts" if [ ${SKIPTEST} -eq 0 ]; then - LogText "Test: Query /etc/fstab for available HAMMER PFS mount points" + LogText "Test: Query /etc/fstab for available HAMMER PFS mount points" FIND=$(${MOUNTBINARY} -p | ${AWKBINARY} '{ if ($3 == "null") { print $1":"$2":"$3":"$4":" }}') if [ -z "${FIND}" ]; then Display --indent 2 --text "- Querying HAMMER PFS mount points (mount -p)" --result "${STATUS_NONE}" --color WHITE @@ -554,16 +556,18 @@ # --------------------------------------------------------- # Mount point nodev noexec nosuid # /boot v v v + # /dev v v # /dev/shm v v v # /home v v + # /run v v # /tmp v v v - # /var v + # /var v v # /var/log v v v # /var/log/audit v v v # /var/tmp v v v # --------------------------------------------------------- - FILESYSTEMS_TO_CHECK="/boot:nodev,noexec,nosuid /dev/shm:nosuid,nodev,noexec /home:nodev,nosuid /tmp:nodev,noexec,nosuid /var:nosuid /var/log:nodev,noexec,nosuid /var/log/audit:nodev,noexec,nosuid /var/tmp:nodev,noexec,nosuid" + FILESYSTEMS_TO_CHECK="/boot:nodev,noexec,nosuid /dev:noexec,nosuid /dev/shm:nosuid,nodev,noexec /home:nodev,nosuid /run:nodev,nosuid /tmp:nodev,noexec,nosuid /var:nodev,nosuid /var/log:nodev,noexec,nosuid /var/log/audit:nodev,noexec,nosuid /var/tmp:nodev,noexec,nosuid" Register --test-no FILE-6374 --os Linux --weight L --network NO --category security --description "Linux mount options" if [ ${SKIPTEST} -eq 0 ]; then if [ -f ${ROOTDIR}etc/fstab ]; then @@ -577,9 +581,14 @@ FS_FSTAB="" fi fi + if [ -z "${FS_FSTAB}" ]; then # not found in fstab, check if mounted otherwise + FS_FSTAB=$(mount | ${AWKBINARY} -v fs=${FILESYSTEM} '{ if ($3==fs) { print $6 } }') + FOUND_FLAGS=$(mount | ${AWKBINARY} -v fs=${FILESYSTEM} '{ if ($1~"[^#]" && $3==fs) { print $6 } }' | ${SEDBINARY} 's/,/ /g' | ${TRBINARY} '\n' ' ') + else + FOUND_FLAGS=$(${AWKBINARY} -v fs=${FILESYSTEM} '{ if ($1~"[^#]" && $2==fs) { print $4 } }' ${ROOTDIR}etc/fstab | ${SEDBINARY} 's/,/ /g' | ${TRBINARY} '\n' ' ') + fi if [ -n "${FS_FSTAB}" ]; then # In awk using caret/circumflex as first character between brackets, means 'not' (instead of beginning of line) - FOUND_FLAGS=$(${AWKBINARY} -v fs=${FILESYSTEM} '{ if ($1~"[^#]" && $2==fs) { print $4 } }' ${ROOTDIR}etc/fstab | ${SEDBINARY} 's/,/ /g' | ${TRBINARY} '\n' ' ') LogText "File system: ${FILESYSTEM}" LogText "Expected flags: ${EXPECTED_FLAGS}" LogText "Found flags: ${FOUND_FLAGS}" @@ -620,6 +629,13 @@ fi done fi + NMOUNTS=$(mount | ${WCBINARY} -l) + NDEVMOUNTS=$(mount | ${AWKBINARY} '{print $6}' | ${GREPBINARY} -v nodev | ${WCBINARY} -l) + NEXECMOUNTS=$(mount | ${AWKBINARY} '{print $6}' | ${GREPBINARY} -v noexec | ${WCBINARY} -l) + NSUIDMOUNTS=$(mount | ${AWKBINARY} '{print $6}' | ${GREPBINARY} -v nosuid | ${WCBINARY} -l) + NWRITEANDEXECMOUNTS=$(mount | ${AWKBINARY} '{print $6}' | ${GREPBINARY} -v noexec | ${EGREPBINARY} -v '^\(ro[,)]' | ${WCBINARY} -l) + LogText "Result: Total without nodev:${NDEVMOUNTS} noexec:${NEXECMOUNTS} nosuid:${NSUIDMOUNTS} ro or noexec (W^X): ${NWRITEANDEXECMOUNTS}, of total ${NMOUNTS}" + Display --indent 2 --text "- Total without nodev:${NDEVMOUNTS} noexec:${NEXECMOUNTS} nosuid:${NSUIDMOUNTS} ro or noexec (W^X): ${NWRITEANDEXECMOUNTS} of total ${NMOUNTS}" fi # ################################################################################# @@ -653,7 +669,6 @@ # Description : Check for nodirtime option # Want to contribute to Lynis? Create this test - # ################################################################################# # @@ -661,7 +676,6 @@ # Description : Check for relatime # Want to contribute to Lynis? Create this test - # ################################################################################# # @@ -674,11 +688,36 @@ # ################################################################################# # - # Test : FILE-6394 TODO + # Test : FILE-6394 # Description : Check vm.swappiness (Linux) - - # Want to contribute to Lynis? Create this test - + Register --test-no FILE-6394 --os Linux --weight L --network NO --category security --description "Determine level of swappiness." + if [ ${SKIPTEST} -eq 0 ]; then + SWAPLEVEL=$(${CAT_BINARY} /proc/sys/vm/swappiness) + LogText "Test: checking level of vm.swappiness: ${SWAPLEVEL}" + PHYSDISK=$(${LSBLKBINARY} | ${GREPBINARY} -E 'disk|SWAP' | ${GREPBINARY} -B1 SWAP | ${HEADBINARY} -n1 | ${AWKBINARY} '{print $1}') + if [ ${SWAPLEVEL} -gt 60 ]; then + LogText "Result: vm.swappiness=${SWAPLEVEL} meaning that swapping is more frequent than default." + # Check if swap is on a HDD or SDD for frequent swapping + if [ -d "/sys/block/${PHYSDISK}" ]; then + HDDORSDD=$(${CAT_BINARY} "/sys/block/${PHYSDISK}/queue/rotational") + if [ ${HDDORSDD} -eq 1 ]; then + ReportSuggestion "${TEST_NO}" "vm.swappiness set to: ${SWAPLEVEL} > 60 (default) - consider installing an SSD for swap partition for better performance." + fi + fi + elif [ ${SWAPLEVEL} -eq 0 ]; then + LogText "Result: vm.swappiness=${SWAPLEVEL} meaning swapping is disabled." + ReportSuggestion "${TEST_NO}" "vm.swappiness set to: ${SWAPLEVEL}. Consider setting value to minimum of 1 for minimizing swappiness, but not quite disabling it. Will prevent OOM killer from killing processes when running out of physical memory." + elif [ ${SWAPLEVEL} -eq 1 ]; then + LogText "Result: vm.swappiness=${SWAPLEVEL} meaning that swapping can still occur but at very minimum." + elif [ ${SWAPLEVEL} -eq 10 ]; then + LogText "Result: vm.swappiness=${SWAPLEVEL} which is the preferred setting for database servers." + elif [ ${SWAPLEVEL} -lt 60 ]; then + LogText "Result: vm.swappiness=${SWAPLEVEL} meaning that swapping is less frequent than default. This is only recommended for servers." + else + LogText "Result: vm.swappiness=${SWAPLEVEL} which is the standard level of swappiness and works well for desktop systems." + fi + if IsVerbose; then Display --indent 2 --text "- Swappiness: ${SWAPLEVEL}" --result "INFO" --color WHITE; fi + fi # ################################################################################# # @@ -791,6 +830,15 @@ AddHP 3 3 if IsDebug; then Display --indent 6 --text "- Module ${FS} not present in the kernel" --result OK --color GREEN; fi fi + FIND=$(${LSBINARY} ${ROOTDIR}etc/modprobe.d/* 2> /dev/null) + if [ -n "${FIND}" ]; then + FIND1=$(${EGREPBINARY} "blacklist ${FS}" ${ROOTDIR}etc/modprobe.d/* | ${GREPBINARY} -v "#") + FIND2=$(${EGREPBINARY} "install ${FS} /bin/true" ${ROOTDIR}etc/modprobe.d/* | ${GREPBINARY} -v "#") + if [ -n "${FIND1}" ] || [ -n "${FIND2}" ]; then + Display --indent 4 --text "- Module $FS is blacklisted" --result "OK" --color GREEN + LogText "Result: module ${FS} is blacklisted" + fi + fi done if [ ${FOUND} -eq 1 ]; then Display --indent 4 --text "- Discovered kernel modules: ${AVAILABLE_MODPROBE_FS}" diff --git a/include/tests_firewalls b/include/tests_firewalls index 67f21020..685f2452 100644 --- a/include/tests_firewalls +++ b/include/tests_firewalls @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -22,7 +22,7 @@ # ################################################################################# # - InsertSection "Software: firewalls" + InsertSection "${SECTION_FIREWALLS}" # ################################################################################# # @@ -407,6 +407,8 @@ Register --test-no FIRE-4534 --weight L --os "macOS" --network NO --category security --description "Check for presence of outbound firewalls on macOS" if [ ${SKIPTEST} -eq 0 ]; then + FOUND=0 + # Little Snitch Daemon (macOS) LogText "Test: checking process Little Snitch Daemon" if IsRunning --full "Little Snitch Daemon"; then @@ -537,7 +539,7 @@ Register --test-no FIRE-4590 --weight L --network NO --category security --description "Check firewall status" if [ ${SKIPTEST} -eq 0 ]; then if [ ${FIREWALL_ACTIVE} -eq 1 ]; then - Display --indent 2 --text "- Checking host based firewall" --result "ACTIVE" --color GREEN + Display --indent 2 --text "- Checking host based firewall" --result "${STATUS_ACTIVE}" --color GREEN LogText "Result: host based firewall or packet filter is active" Report "manual[]=Verify if there is a formal process for testing and applying firewall rules" Report "manual[]=Verify all traffic is filtered the right way between the different security zones" @@ -546,7 +548,7 @@ Report "manual[]=Make sure an explicit deny all is the default policy for all unmatched traffic" AddHP 5 5 else - Display --indent 2 --text "- Checking host based firewall" --result "NOT ACTIVE" --color YELLOW + Display --indent 2 --text "- Checking host based firewall" --result "${STATUS_NOT_ACTIVE}" --color YELLOW LogText "Result: no host based firewall/packet filter found or configured" ReportSuggestion "${TEST_NO}" "Configure a firewall/packet filter to filter incoming and outgoing traffic" AddHP 0 5 diff --git a/include/tests_hardening b/include/tests_hardening index 8b8ae452..4feff7c6 100644 --- a/include/tests_hardening +++ b/include/tests_hardening @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -18,7 +18,7 @@ # ################################################################################# # - InsertSection "Hardening" + InsertSection "${SECTION_HARDENING}" # COMPILER_INSTALLED is initialized before HARDEN_COMPILERS_NEEDED=0 diff --git a/include/tests_homedirs b/include/tests_homedirs index 13a91d86..c896bf86 100644 --- a/include/tests_homedirs +++ b/include/tests_homedirs @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -22,7 +22,7 @@ # ################################################################################# # - InsertSection "Home directories" + InsertSection "${SECTION_HOME_DIRECTORIES}" # ################################################################################# # diff --git a/include/tests_insecure_services b/include/tests_insecure_services index 61a66066..2ba308b3 100644 --- a/include/tests_insecure_services +++ b/include/tests_insecure_services @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -22,7 +22,7 @@ # ################################################################################# # - InsertSection "Insecure services" + InsertSection "${SECTION_INSECURE_SERVICES}" # ################################################################################# # @@ -37,7 +37,7 @@ # # Test : INSE-8000 # Description : Check for installed inetd package - Register --test-no INSE-8000 --weight L --network NO --category security --description "Installed inetd package" + Register --test-no INSE-8000 --package-manager-required --weight L --network NO --category security --description "Installed inetd package" if [ ${SKIPTEST} -eq 0 ]; then # Check for installed inetd daemon LogText "Test: Checking if inetd is installed" @@ -63,11 +63,11 @@ LogText "Test: Searching for active inet daemon" if IsRunning "inetd"; then LogText "Result: inetd is running" - Display --indent 4 --text "- inetd status" --result "ACTIVE" --color GREEN + Display --indent 4 --text "- inetd status" --result "${STATUS_ACTIVE}" --color GREEN INETD_ACTIVE=1 else LogText "Result: inetd is NOT running" - Display --indent 4 --text "- inetd status" --result "NOT ACTIVE" --color GREEN + Display --indent 4 --text "- inetd status" --result "${STATUS_NOT_ACTIVE}" --color GREEN fi fi # @@ -134,7 +134,7 @@ # # Test : INSE-8100 # Description : Check for installed xinetd daemon - Register --test-no INSE-8100 --weight L --network NO --category security --description "Check for installed xinetd daemon" + Register --test-no INSE-8100 --package-manager-required --weight L --network NO --category security --description "Check for installed xinetd daemon" if [ ${SKIPTEST} -eq 0 ]; then # Check for installed xinetd daemon LogText "Test: Checking for installed xinetd daemon" @@ -158,11 +158,11 @@ LogText "Test: Searching for active extended internet services daemon (xinetd)" if IsRunning "xinetd"; then LogText "Result: xinetd is running" - Display --indent 4 --text "- xinetd status" --result "ACTIVE" --color GREEN + Display --indent 4 --text "- xinetd status" --result "${STATUS_ACTIVE}" --color GREEN XINETD_ACTIVE=1 else LogText "Result: xinetd is NOT running" - Display --indent 4 --text "- xinetd status" --result "NOT ACTIVE" --color GREEN + Display --indent 4 --text "- xinetd status" --result "${STATUS_NOT_ACTIVE}" --color GREEN fi fi # @@ -250,7 +250,7 @@ # Test : INSE-8200 # Description : Check if tcp_wrappers is installed when inetd/xinetd is active if [ ${INETD_ACTIVE} -eq 1 -o ${XINETD_ACTIVE} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi - Register --test-no INSE-8200 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check if tcp_wrappers is installed when inetd/xinetd is active" + Register --test-no INSE-8200 --package-manager-required --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check if tcp_wrappers is installed when inetd/xinetd is active" if [ ${SKIPTEST} -eq 0 ]; then LogText "Test: Checking if tcp_wrappers is installed" FOUND=0 @@ -272,7 +272,7 @@ # # Test : INSE-8300 # Description : Check if rsh client is installed - Register --test-no INSE-8300 --weight L --network NO --category security --description "Check if rsh client is installed" + Register --test-no INSE-8300 --package-manager-required --weight L --network NO --category security --description "Check if rsh client is installed" if [ ${SKIPTEST} -eq 0 ]; then LogText "Test: Checking if rsh client is installed" FOUND=0 @@ -328,7 +328,7 @@ # # Test : INSE-8304 # Description : Check if rsh server is installed - Register --test-no INSE-8304 --weight L --network NO --category security --description "Check if rsh server is installed" + Register --test-no INSE-8304 --package-manager-required --weight L --network NO --category security --description "Check if rsh server is installed" if [ ${SKIPTEST} -eq 0 ]; then # Check if rsh server is installed LogText "Test: Checking if rsh server is installed" @@ -352,7 +352,7 @@ # # Test : INSE-8310 # Description : Check if telnet client is installed - Register --test-no INSE-8310 --weight L --network NO --category security --description "Check if telnet client is installed" + Register --test-no INSE-8310 --package-manager-required --weight L --network NO --category security --description "Check if telnet client is installed" if [ ${SKIPTEST} -eq 0 ]; then # Check if telnet client is installed LogText "Test: Checking if telnet client is installed" @@ -373,7 +373,7 @@ # # Test : INSE-8312 # Description : Check if telnet server is installed - Register --test-no INSE-8322 --weight L --network NO --category security --description "Check if telnet server is installed" + Register --test-no INSE-8322 --package-manager-required --weight L --network NO --category security --description "Check if telnet server is installed" if [ ${SKIPTEST} -eq 0 ]; then # Check if TFTP server is installed LogText "Test: Checking if telnet server is installed" @@ -385,7 +385,7 @@ if [ ${FOUND} -eq 1 ]; then LogText "Result: telnet server is installed" Display --indent 2 --text "- Installed telnet server package" --result "${STATUS_FOUND}" --color YELLOW - ReportSuggestion "${TEST_NO}" "Removing the ${FOUND} package and replace with SSH when possible" + ReportSuggestion "${TEST_NO}" "Removing the telnet server package and replace with SSH when possible" Report "insecure_service[]=telnet-server" else LogText "Result: telnet server is NOT installed" @@ -398,7 +398,7 @@ # # Test : INSE-8314 # Description : Check if NIS client is installed - Register --test-no INSE-8314 --weight L --network NO --category security --description "Check if NIS client is installed" + Register --test-no INSE-8314 --package-manager-required --weight L --network NO --category security --description "Check if NIS client is installed" if [ ${SKIPTEST} -eq 0 ]; then FOUND="" LogText "Test: Checking if NIS client is installed" @@ -422,7 +422,7 @@ # # Test : INSE-8316 # Description : Check if NIS server is installed - Register --test-no INSE-8316 --weight L --network NO --category security --description "Check if NIS server is installed" + Register --test-no INSE-8316 --package-manager-required --weight L --network NO --category security --description "Check if NIS server is installed" if [ ${SKIPTEST} -eq 0 ]; then FOUND="" LogText "Test: Checking if NIS server is installed" @@ -446,7 +446,7 @@ # # Test : INSE-8318 # Description : Check if TFTP client is installed - Register --test-no INSE-8318 --weight L --network NO --category security --description "Check if TFTP client is installed" + Register --test-no INSE-8318 --package-manager-required --weight L --network NO --category security --description "Check if TFTP client is installed" if [ ${SKIPTEST} -eq 0 ]; then LogText "Test: Checking if TFTP client is installed" FOUND="" @@ -470,7 +470,7 @@ # # Test : INSE-8320 # Description : Check if TFTP server is installed - Register --test-no INSE-8320 --weight L --network NO --category security --description "Check if TFTP server is installed" + Register --test-no INSE-8320 --package-manager-required --weight L --network NO --category security --description "Check if TFTP server is installed" if [ ${SKIPTEST} -eq 0 ]; then LogText "Test: Checking if TFTP server is installed" FOUND="" diff --git a/include/tests_kernel b/include/tests_kernel index 0f72525e..119b276e 100644 --- a/include/tests_kernel +++ b/include/tests_kernel @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -22,7 +22,7 @@ # ################################################################################# # - InsertSection "Kernel" + InsertSection "${SECTION_KERNEL}" # ################################################################################# # @@ -31,6 +31,7 @@ LINUXCONFIGFILE="" LINUXCONFIGFILE_ZIPPED=0 LIMITS_DIRECTORY="${ROOTDIR}etc/security/limits.d" + APT_ARCHIVE_DIRECTORY="${ROOTDIR}var/cache/apt/archives" # ################################################################################# # @@ -102,8 +103,7 @@ # Description : Check CPU options and support (PAE, No eXecute, eXecute Disable) # More info : pae and nx bit are both visible on AMD and Intel CPU's if supported - if [ "${HARDWARE}" = "x86_64" ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi - Register --test-no KRNL-5677 --preqs-met "${PREQS_MET}" --os Linux --weight L --network NO --category security --description "Check CPU options and support" + Register --test-no KRNL-5677 --platform x86_64 --os Linux --weight L --network NO --category security --description "Check CPU options and support" if [ ${SKIPTEST} -eq 0 ]; then Display --indent 2 --text "- Checking CPU support (NX/PAE)" LogText "Test: Checking /proc/cpuinfo" @@ -235,12 +235,13 @@ Register --test-no KRNL-5728 --os Linux --weight L --network NO --category security --description "Checking Linux kernel config" if [ ${SKIPTEST} -eq 0 ]; then CHECKFILE="${ROOTDIR}boot/config-$(uname -r)" + CHECKFILE_ZIPPED="${ROOTDIR}proc/config.gz" if [ -f ${CHECKFILE} ]; then LINUXCONFIGFILE="${CHECKFILE}" LogText "Result: found config (${LINUXCONFIGFILE})" Display --indent 2 --text "- Checking Linux kernel configuration file" --result "${STATUS_FOUND}" --color GREEN - elif [ -f ${ROOTDIR}proc/config.gz ]; then - LINUXCONFIGFILE="${CHECKFILE}" + elif [ -f ${CHECKFILE_ZIPPED} ]; then + LINUXCONFIGFILE="${CHECKFILE_ZIPPED}" LINUXCONFIGFILE_ZIPPED=1 LogText "Result: found config: ${ROOTDIR}proc/config.gz (compressed)" Display --indent 2 --text "- Checking Linux kernel configuration file" --result "${STATUS_FOUND}" --color GREEN @@ -392,6 +393,12 @@ elif [ -e ${ROOTDIR}dev/grsec ]; then FINDKERNEL=linux-image-$(uname -r) LogText "Result: ${ROOTDIR}vmlinuz missing due to grsecurity; assuming ${FINDKERNEL}" + elif [ -e ${ROOTDIR}etc/rpi-issue ]; then + FINDKERNEL=raspberrypi-kernel + LogText "Result: ${ROOTDIR}vmlinuz missing due to Raspbian" + elif `${EGREPBINARY} -q 'do_symlinks.*=.*No' ${ROOTDIR}etc/kernel-img.conf`; then + FINDKERNEL=linux-image-$(uname -r) + LogText "Result: ${ROOTDIR}vmlinuz missing due to /etc/kernel-img.conf item do_symlinks = No" else LogText "This system is missing ${ROOTDIR}vmlinuz or ${ROOTDIR}boot/vmlinuz. Unable to check whether kernel is up-to-date." ReportSuggestion "${TEST_NO}" "Determine why ${ROOTDIR}vmlinuz or ${ROOTDIR}boot/vmlinuz is missing on this Debian/Ubuntu system." "/vmlinuz or /boot/vmlinuz" @@ -478,13 +485,13 @@ ( [ ${SYSD_CORED_BASE_PROCSIZEMAX_NR_ENABLED} -ge 1 ] && [ ${SYSD_CORED_SUB_STORAGE_NR_ENABLED} -ge 1 ] ) || \ ( [ ${SYSD_CORED_BASE_STORAGE_NR_ENABLED} -ge 1 ] && [ ${SYSD_CORED_SUB_PROCSIZEMAX_NR_ENABLED} -ge 1 ] ) || \ ( [ ${SYSD_CORED_SUB_PROCSIZEMAX_NR_ENABLED} -ge 1 ] && [ ${SYSD_CORED_SUB_STORAGE_NR_ENABLED} -ge 1 ] ); then - LogText "Result: core dumps are explicitely enabled in systemd configuration files" + LogText "Result: core dumps are explicitly enabled in systemd configuration files" ReportSuggestion "${TEST_NO}" "If not required, consider explicit disabling of core dump in ${ROOTDIR}etc/systemd/coredump.conf ('ProcessSizeMax=0', 'Storage=none')" Display --indent 4 --text "- configuration in systemd conf files" --result "${STATUS_ENABLED}" --color RED AddHP 0 1 else LogText "Result: core dumps are not disabled in systemd configuration. Didn't find settings 'ProcessSizeMax=0' and 'Storage=none'" - Display --indent 4 --text "- configuration in systemd conf files" --result "DEFAULT" --color WHITE + Display --indent 4 --text "- configuration in systemd conf files" --result "${STATUS_DEFAULT}" --color WHITE AddHP 0 1 fi fi @@ -501,7 +508,7 @@ AddHP 1 1 elif [ -z "${ULIMIT_C_VALUE_SUB}" ] && [ -z "${ULIMIT_C_VALUE}" ]; then LogText "Result: core dumps are not disabled in ${ROOTDIR}etc/profile or ${ROOTDIR}etc/profile.d/*.sh config files. Didn't find setting 'ulimit -c 0'" - Display --indent 4 --text "- configuration in etc/profile" --result "DEFAULT" --color WHITE + Display --indent 4 --text "- configuration in etc/profile" --result "${STATUS_DEFAULT}" --color WHITE AddHP 0 1 elif ( [ -n "${ULIMIT_C_VALUE_SUB}" ] && ( [ "${ULIMIT_C_VALUE_SUB}" = "unlimited" ] || [ "${ULIMIT_C_VALUE_SUB}" != "0" ] ) ) || ( [ -n "${ULIMIT_C_VALUE}" ] && [ -z "${ULIMIT_C_VALUE_SUB}" ] && ( [ "${ULIMIT_C_VALUE}" = "unlimited" ] || [ "${ULIMIT_C_VALUE}" != "0" ] ) ); then LogText "Result: core dumps are enabled in ${ROOTDIR}etc/profile or ${ROOTDIR}etc/profile.d/*.sh config files. A value higher than 0 is configured for 'ulimit -c'" @@ -509,7 +516,7 @@ AddHP 0 1 else LogText "Result: ERROR - something went wrong. Unexpected result during check of ${ROOTDIR}etc/profile and ${ROOTDIR}etc/profile.d/*.sh config files. Please report on Github!" - Display --indent 4 --text "- configuration in etc/profile" --result "ERROR" --color YELLOW + Display --indent 4 --text "- configuration in etc/profile" --result "${STATUS_ERROR}" --color YELLOW fi fi # Limits option @@ -531,8 +538,8 @@ FIND2="hard core enabled" fi - IS_SOFTCORE_DISABLED="$(if [ "${FIND1}" = "soft core disabled" ]; then ${ECHOCMD} DISABLED; elif [ "${FIND1}" = "soft core enabled" ]; then ${ECHOCMD} ENABLED; else ${ECHOCMD} DEFAULT; fi)" - IS_HARDCORE_DISABLED="$(if [ "${FIND2}" = "hard core disabled" ]; then ${ECHOCMD} DISABLED; elif [ "${FIND2}" = "hard core enabled" ]; then ${ECHOCMD} ENABLED; else ${ECHOCMD} DEFAULT; fi)" + IS_SOFTCORE_DISABLED="$(if [ "${FIND1}" = "soft core disabled" ]; then ${ECHOCMD} DISABLED; elif [ "${FIND1}" = "soft core enabled" ]; then ${ECHOCMD} ENABLED; else ${ECHOCMD} ${STATUS_DEFAULT}; fi)" + IS_HARDCORE_DISABLED="$(if [ "${FIND2}" = "hard core disabled" ]; then ${ECHOCMD} DISABLED; elif [ "${FIND2}" = "hard core enabled" ]; then ${ECHOCMD} ENABLED; else ${ECHOCMD} ${STATUS_DEFAULT}; fi)" if [ "${FIND2}" = "hard core disabled" ]; then LogText "Result: core dumps are hard disabled" @@ -580,18 +587,18 @@ fi if [ "${FIND}" = "2" ]; then LogText "Result: programs can dump core dump, but only readable by root (value 2, for debugging with file protection)" - Display --indent 4 --text "- Checking setuid core dumps configuration" --result PROTECTED --color WHITE + Display --indent 4 --text "- Checking setuid core dumps configuration" --result "${STATUS_PROTECTED}" --color WHITE AddHP 1 1 elif [ "${FIND}" = "1" ]; then LogText "Result: all programs can perform core dumps (value 1, for debugging)" - Display --indent 2 --text "- Checking setuid core dumps configuration" --result DEBUG --color YELLOW + Display --indent 2 --text "- Checking setuid core dumps configuration" --result "${STATUS_DEBUG}" --color YELLOW ReportSuggestion "${TEST_NO}" "Determine if all binaries need to be able to core dump" AddHP 0 1 else # 0 - (default) - traditional behaviour. Any process which has changed privilege levels or is execute only will not be dumped # https://www.kernel.org/doc/Documentation/sysctl/fs.txt LogText "Result: found default option (0), no execute only program or program with changed privilege levels can dump" - Display --indent 4 --text "- Checking setuid core dumps configuration" --result DISABLED --color GREEN + Display --indent 4 --text "- Checking setuid core dumps configuration" --result "${STATUS_DISABLED}" --color GREEN AddHP 1 1 fi fi @@ -624,7 +631,7 @@ fi # Check if /boot exists - if [ ${PRIVILEGED} -eq 1 -a -d "${ROOTDIR}boot" ]; then + if [ -d "${ROOTDIR}boot" ]; then LogText "Result: /boot exists, performing more tests from here" FIND=$(${LSBINARY} ${ROOTDIR}boot/* 2> /dev/null) if [ -n "${FIND}" ]; then @@ -650,30 +657,47 @@ else ReportException "${TEST_NO}:1" "Can't determine kernel version on disk, need debug data" fi - elif [ -f ${ROOTDIR}boot/vmlinuz-linux -o -f ${ROOTDIR}boot/vmlinuz-linux-lts -o -f $(ls -t ${ROOTDIR}boot/vm[l-]* 2> /dev/null | head -1) ]; then - if [ -L ${ROOTDIR}boot/vmlinuz-linux ]; then - LogText "Result: found symlink ${ROOTDIR}boot/vmlinuz-linux" - FOUND_VMLINUZ=$(readlink ${ROOTDIR}boot/vmlinuz-linux) - LogText "Result: symlinked target is ${FOUND_VMLINUZ}" - VERSION_ON_DISK=$(echo ${FOUND_VMLINUZ} | ${SEDBINARY} 's/^vmlinuz-//') + elif [ -f ${ROOTDIR}boot/vmlinuz-linux ] || [ -f ${ROOTDIR}boot/vmlinuz-linux-lts ] || [ -f "$(${LSBINARY} -t ${ROOTDIR}boot/vm[l0-9]* 2> /dev/null | ${HEADBINARY} -1)" ]; then + if [ -f ${ROOTDIR}boot/vmlinuz-linux ]; then + LogText "Result: found ${ROOTDIR}boot/vmlinuz-linux" + FOUND_VMLINUZ=${ROOTDIR}boot/vmlinuz-linux elif [ -f ${ROOTDIR}boot/vmlinuz-linux-lts ]; then - LogText "Result: found boot/vmlinuz-linux-lts" + LogText "Result: found ${ROOTDIR}boot/vmlinuz-linux-lts" FOUND_VMLINUZ=${ROOTDIR}boot/vmlinuz-linux-lts + elif [ -f ${ROOTDIR}boot/vmlinuz-lts ]; then + LogText "Result: found ${ROOTDIR}boot/vmlinuz-lts" + FOUND_VMLINUZ=${ROOTDIR}boot/vmlinuz-lts else - # Match on /boot/vm5.3.7 or /boot/vmlinuz-5.3.7-1-default - FOUND_VMLINUZ=$(ls -t ${ROOTDIR}boot/vm[l-]* 2> /dev/null | head -1) + # Match on items like /boot/vm5.3.7 or /boot/vmlinuz-5.3.7-1-default. Get newest file (ls -t and pipe into head) + # Note: ignore a rescue kernel (e.g. CentOS) + FOUND_VMLINUZ=$(${LSBINARY} -t ${ROOTDIR}boot/vm[l0-9]* 2> /dev/null | ${GREPBINARY} -v '\-rescue\-' | ${HEADBINARY} -1) + LogText "Result: found ${FOUND_VMLINUZ}" fi + VERSION_ON_DISK="" if [ -L "${FOUND_VMLINUZ}" ]; then LogText "Result: found a symlink, retrieving destination" FOUND_VMLINUZ=$(readlink "${FOUND_VMLINUZ}") LogText "Result: destination file is ${FOUND_VMLINUZ}" - VERSION_ON_DISK=$(echo ${FOUND_VMLINUZ} | ${SEDBINARY} 's/^vmlinuz-//') + VERSION_ON_DISK=$(echo ${FOUND_VMLINUZ} | ${SEDBINARY} 's#^/boot/##' | ${SEDBINARY} 's/^vmlinuz-//') + LogText "Result: version derived from file name is '${VERSION_ON_DISK}'" + elif [ -f "${FOUND_VMLINUZ}" ]; then + VERSION_ON_DISK=$(echo ${FOUND_VMLINUZ} | ${SEDBINARY} 's#^/boot/##' | ${SEDBINARY} 's/^vmlinuz-//' | ${SEDBINARY} '$s/-\?\(linux\)\?-\?\(lts\)\?//') LogText "Result: version derived from file name is '${VERSION_ON_DISK}'" + fi + # Data check: perform reset if we found a version but looks incomplete + # Example: Arch Linux will return only 'linux' as its version after it discovered /boot/vmlinuz-linux + case ${VERSION_ON_DISK} in + "linux" | "linux-lts") + LogText "Result: reset of version (${VERSION_ON_DISK}) as it looks incomplete" + VERSION_ON_DISK="" + ;; + esac + + # If we did not find the version yet, see if we can extract it from the magic data that 'file' returns if [ -z "${VERSION_ON_DISK}" ]; then - LogText "Result: found ${FOUND_VMLINUZ}" LogText "Test: checking kernel version on disk" NEXTLINE=0 VERSION_ON_DISK="" @@ -686,6 +710,12 @@ if [ "${I}" = "version" ]; then NEXTLINE=1; fi fi done + fi + + # Last check if we finally got a version or not + if [ -z "${VERSION_ON_DISK}" ]; then + LogText "Result: could not find the version on disk" + ReportException "${TEST_NO}:4" "Could not find the kernel version" else LogText "Result: found version ${VERSION_ON_DISK}" ACTIVE_KERNEL=$(uname -r) @@ -698,10 +728,6 @@ LogText "Result: reboot needed, as there is a difference between active kernel and the one on disk" fi fi - if [ -z "${VERSION_ON_DISK}" ]; then - LogText "Result: could not find the version on disk" - ReportException "${TEST_NO}:4" "Could not find the kernel version" - fi else if [ -L ${ROOTDIR}boot/vmlinuz ]; then LogText "Result: found symlink of ${ROOTDIR}boot/vmlinuz, skipping file" @@ -767,6 +793,107 @@ LogText "Result: /boot does not exist or not privileged to read files" fi + # Attempt to check for Raspbian if reboot is needed + # This check searches for apt package "raspberrypi-kernel-[package-date]", trys to extract the date of packaging from the filename + # and compares that date with the currently running kernel's build date (uname -v). + # Of course there can be a time difference between kernel build and kernel packaging, therefore a time difference of + # 3 days is accepted and it is assumed with only 3 days apart, this must be the same kernel version. + if [ ${REBOOT_NEEDED} -eq 2 ] && [ -d "${APT_ARCHIVE_DIRECTORY}" ]; then + LogText "Result: found folder ${APT_ARCHIVE_DIRECTORY}; assuming this is a debian based distribution" + LogText "Check: try to find raspberrypi-kernel file in ${APT_ARCHIVE_DIRECTORY} and extract package date from file name" + + FOUND_KERNEL_DATE=$(${FINDBINARY} ${APT_ARCHIVE_DIRECTORY} -name "raspberrypi-kernel*" -printf "%T@ %Tc %p\n" 2> /dev/null \ + | ${SORTBINARY} -nr | ${HEADBINARY} -1 | ${GREPBINARY} -o "raspberrypi-kernel.*deb" | ${EGREPBINARY} -o "\.[0-9]+" | ${SEDBINARY} 's/\.//g') + + if [ -n "${FOUND_KERNEL_DATE}" ]; then + FOUND_KERNEL_IN_SECONDS=$(date -d "${FOUND_KERNEL_DATE}" "+%s" 2> /dev/null) + else + LogText "Result: Skipping this test, as there was no package date to extract" + fi + + if [ -n "${FOUND_KERNEL_IN_SECONDS}" ] && [ ${FOUND_KERNEL_IN_SECONDS} -gt 1 ]; then + LogText "Result: Got package date: ${FOUND_KERNEL_DATE} (= ${FOUND_KERNEL_IN_SECONDS} seconds)" + UNAME_OUTPUT="$(${UNAMEBINARY} -v 2> /dev/null)" + else + LogText "Result: Skipping this test, as extracting the seconds of package date failed" + fi + + if [ -n "${UNAME_OUTPUT}" ]; then + LogText "Result: Got an output from 'uname -v'" + LogText "Check: Trying to extract kernel build date from 'uname -v' output" + next="" + for part in ${UNAME_OUTPUT}; do + if [ -z "$next" ]; then + if [ "${part}" = "Mon" ] || [ "${part}" = "Tue" ] || [ "${part}" = "Wed" ] || [ "${part}" = "Thu" ] || [ "${part}" = "Fri" ] || [ "${part}" = "Sat" ] || [ "${part}" = "Sun" ]; then + next="month" + fi + elif [ "$next" = "month" ]; then + if [ $(${ECHOCMD} "${part}" | ${EGREPBINARY} -c "[A-Z][a-z]") -ge 1 ]; then + UNAME_DATE_MONTH="${part}" + next="day" + fi + elif [ "${next}" = "day" ]; then + if [ $(${ECHOCMD} ${part} | ${EGREPBINARY} -c "[0-9][0-9]") -ge 1 ]; then + UNAME_DATE_DAY="${part}" + next="time" + fi + elif [ "${next}" = "time" ]; then + if [ $(${ECHOCMD} ${part} | ${EGREPBINARY} -c ":[0-9][0-9]:") -ge 1 ]; then + next="year" + fi + elif [ "${next}" = "year" ]; then + if [ $(${ECHOCMD} ${part} | ${EGREPBINARY} -c "[0-9][0-9]") -ge 1 ]; then + UNAME_DATE_YEAR="${part}" + break + fi + fi + done + if [ -n "${UNAME_DATE_MONTH}" ] && [ -n "${UNAME_DATE_DAY}" ] && [ -n "${UNAME_DATE_YEAR}" ]; then + LogText "Result: Extracted kernel build date is: ${UNAME_DATE_DAY} ${UNAME_DATE_MONTH} ${UNAME_DATE_YEAR}" + UNAME_DATE_IN_SECONDS=$(date -d "${UNAME_DATE_DAY} ${UNAME_DATE_MONTH} ${UNAME_DATE_YEAR}" "+%s" 2> /dev/null) + LogText "Check: Comparing kernel build date in seconds (${UNAME_DATE_IN_SECONDS}s) with package date in seconds (${FOUND_KERNEL_IN_SECONDS}s)" + if [ -n "${UNAME_DATE_IN_SECONDS}" ] && [ ${FOUND_KERNEL_IN_SECONDS} -ge ${UNAME_DATE_IN_SECONDS} ]; then + LogText "Result: package creation date is older than running kernel. Hence, this check should be valid." + LogText "Check if package create date and kernel build date are not more than 3 days apart." + + SECONDS_APART=$(( ${FOUND_KERNEL_IN_SECONDS} - ${UNAME_DATE_IN_SECONDS} )) + if [ ${SECONDS_APART} -ge 60 ]; then + MINUTES_APART=$(( ${SECONDS_APART} / 60 )) + if [ ${MINUTES_APART} -ge 60 ]; then + DAYS_APART=$(( ${MINUTES_APART} / 60 )) + if [ ${DAYS_APART} -ge 24 ]; then DAYS_APART=$(( ${DAYS_APART} / 24 )); else DAYS_APART=0; fi + else + DAYS_APART=0 + fi + else + DAYS_APART=0 + fi + # assuming kernels are packaged definitely within 3 days. ACCEPTED_TIME_DIFF needs a value in seconds + ACCEPTED_TIME_DIFF=$((3 * 24 * 60 * 60)) + if [ ${FOUND_KERNEL_IN_SECONDS} -le $((${UNAME_DATE_IN_SECONDS} + ${ACCEPTED_TIME_DIFF})) ]; then + LogText "Result: package create date and kernel build date are only ${DAYS_APART} day(s) apart." + LogText "Result: Assuming no reboot needed." + REBOOT_NEEDED=0 + else + LogText "Result: package create date and kernel build date are ${DAYS_APART} day(s) apart." + LogText "Result: Assuming reboot is needed." + REBOOT_NEEDED=1 + fi + else + LogText "Result: Package's create date is older than running kernel, which is unexpected. Might not be a valid test. Skipping..." + fi + else + LogText "Result: Could not extract Day, Month and Year from 'uname -v' output" + fi + else + LogText "Result: Did not get output from 'uname -v'. Skipping test." + fi + + + else + LogText "Result: /var/cache/apt/archives/ does not exist" + fi + # Display discovered status if [ ${REBOOT_NEEDED} -eq 0 ]; then Display --indent 2 --text "- Check if reboot is needed" --result "${STATUS_NO}" --color GREEN @@ -787,4 +914,4 @@ WaitForKeyPress # #================================================================================ -# Lynis - Copyright 2007-2019, CISOfy - https://cisofy.com +# Lynis - Copyright 2007-2020, CISOfy - https://cisofy.com diff --git a/include/tests_kernel_hardening b/include/tests_kernel_hardening index 9599a708..c0887078 100644 --- a/include/tests_kernel_hardening +++ b/include/tests_kernel_hardening @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -22,13 +22,13 @@ # ################################################################################# # - InsertSection "Kernel Hardening" + InsertSection "${SECTION_KERNEL_HARDENING}" # ################################################################################# # # Test : KRNL-6000 # Description : Check sysctl parameters - # Sysctl : net.ipv4.icmp_ingore_bogus_error_responses (=1) + # Sysctl : net.ipv4.icmp_ignore_bogus_error_responses (=1) if [ ! "${SYSCTL_READKEY}" = "" ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi Register --test-no KRNL-6000 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check sysctl key pairs in scan profile" if [ ${SKIPTEST} -eq 0 ]; then @@ -89,7 +89,7 @@ AddHP ${tFINDhp} ${tFINDhp} else LogText "Result: sysctl key ${tFINDkey} has a different value than expected in scan profile. Expected=${tFINDexpvalue}, Real=${tFINDcurvalue}" - Display --indent 4 --text "- ${tFINDkey} (exp: ${tFINDexpvalue})" --result DIFFERENT --color RED + Display --indent 4 --text "- ${tFINDkey} (exp: ${tFINDexpvalue})" --result "${STATUS_DIFFERENT}" --color RED AddHP 0 ${tFINDhp} FOUND=1 N=$((N + 1)) diff --git a/include/tests_ldap b/include/tests_ldap index 63e26e58..7558d491 100644 --- a/include/tests_ldap +++ b/include/tests_ldap @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -22,7 +22,7 @@ # ################################################################################# # - InsertSection "LDAP Services" + InsertSection "${SECTION_LDAP_SERVICES}" # ################################################################################# # diff --git a/include/tests_logging b/include/tests_logging index 9c2ae9a6..acbbcf5b 100644 --- a/include/tests_logging +++ b/include/tests_logging @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -28,7 +28,9 @@ METALOG_RUNNING=0 RFC3195D_RUNNING=0 RSYSLOG_RUNNING=0 + SOLARIS_LOGHOST="" SOLARIS_LOGHOST_FOUND=0 + SOLARIS_LOGHOST_LOCALHOST=0 SYSLOG_DAEMON_PRESENT=0 SYSLOG_DAEMON_RUNNING=0 SYSLOG_NG_RUNNING=0 @@ -36,7 +38,7 @@ # ################################################################################# # - InsertSection "Logging and files" + InsertSection "${SECTION_LOGGING_AND_FILES}" # Test : LOGG-2130 # Description : Check for a running syslog daemon @@ -305,6 +307,7 @@ LogText "Result: Checking for loghost in /etc/inet/hosts" FIND=$(${GREPBINARY} loghost /etc/inet/hosts | ${GREPBINARY} -v "^#") if [ -n "${FIND}" ]; then + SOLARIS_LOGHOST="${FIND}" SOLARIS_LOGHOST_FOUND=1 LogText "Result: Found loghost entry in /etc/inet/hosts" else @@ -314,6 +317,7 @@ LogText "Result: Checking for loghost via name resolving" FIND=$(getent hosts loghost | ${GREPBINARY} loghost) if [ -n "${FIND}" ]; then + SOLARIS_LOGHOST="${FIND}" SOLARIS_LOGHOST_FOUND=1 LogText "Result: name resolving was successful" LogText "Output: ${FIND}" @@ -335,6 +339,26 @@ # ################################################################################# # + # Test : LOGG-2153 + # Description : Check Solaris 'loghost' entry is not localhost, meaning + # remote logging is not configured. + if [ ${SOLARIS_LOGHOST_FOUND} -eq 1 ] && [ -n "${SOLARIS_LOGHOST}" ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi + Register --test-no LOGG-2153 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Checking loghost is localhost" + if [ ${SKIPTEST} -eq 0 ]; then + FIND=$(echo "${SOLARIS_LOGHOST}" | ${AWKBINARY} '{ print $1 }' | ${EGREPBINARY} "::1|127.0.0.1|127.1") + if [ -n "${FIND}" ]; then + SOLARIS_LOGHOST_LOCALHOST=1 + LogText "Result: loghost entry is localhost (default)" + Display --indent 4 --text "- Checking loghost entry is localhost" --result "${STATUS_YES}" --color YELLOW + ReportSuggestion "${TEST_NO}" "Set loghost entry to a remote location to enable remote logging." + else + Display --indent 4 --text "- Checking loghost entry is localhost" --result "${STATUS_NO}" --color GREEN + fi + fi + +# +################################################################################# +# # Test : LOGG-2154 # Description : Check to see if remote logging is enabled # Notes : prevent lines showing up with commands in it (like |mail) @@ -402,8 +426,13 @@ LogText "Test: check if logs are also logged to a remote logging host" FIND=$(${EGREPBINARY} "@[a-zA-Z0-9]|destination\s.+(udp|tcp).+\sport" ${SYSLOGD_CONF} | ${GREPBINARY} -v "^#" | ${GREPBINARY} -v "[a-zA-Z0-9]@") if [ -n "${FIND}" ]; then - LogText "Result: remote logging enabled" - REMOTE_LOGGING_ENABLED=1 + FIND2=$(echo "${FIND}" | ${GREPBINARY} -v "@loghost") + if [ SOLARIS_LOGHOST_LOCALHOST -eq 1 ] && [ -z "${FIND2}" ]; then + LogText "Result: remote logging enabled to loghost, but loghost is localhost" + else + LogText "Result: remote logging enabled" + REMOTE_LOGGING_ENABLED=1 + fi else # Search for configured destinations with an IP address or hostname, then determine which ones are used as a log destination DESTINATIONS=$(${GREPBINARY} "^destination" ${SYSLOGD_CONF} | ${EGREPBINARY} "(udp|tcp)" | ${GREPBINARY} "port" | ${AWKBINARY} '{print $2}') @@ -423,7 +452,7 @@ LogText "Result: no remote logging found" ReportSuggestion "${TEST_NO}" "Enable logging to an external logging host for archiving purposes and additional protection" AddHP 1 3 - Display --indent 2 --text "- Checking remote logging" --result "NOT ENABLED" --color YELLOW + Display --indent 2 --text "- Checking remote logging" --result "${STATUS_NOT_ENABLED}" --color YELLOW else Report "remote_syslog_configured=1" AddHP 5 5 @@ -534,12 +563,7 @@ LSOF_GREP="WARNING|Output information" # MySQL versions prior to 5.6 leave lots of deleted in-use files in /tmp, ignoring those - if [ -n "${DPKGBINARY}" ]; then - EARLY_MYSQL=$(${DPKGBINARY} -l | ${EGREPBINARY} mysql-server-5.[0-5]) - elif [ -n "${RPMBINARY}" ]; then - EARLY_MYSQL=$(${RPMBINARY} -qa mariadb | ${EGREPBINARY} mariadb-5.[0-5]) - fi - if [ -n "${EARLY_MYSQL}" ]; then LSOF_GREP="${LSOF_GREP}|mysqld"; fi + LSOF_GREP="${LSOF_GREP}|mysqld" # grsecurity causes Fail2Ban to hold onto deleted in-use files in /var/tmp if [ ${GRSEC_FOUND} -eq 1 ]; then LSOF_GREP="${LSOF_GREP}|fail2ban"; fi @@ -555,7 +579,7 @@ LogText "Found deleted file: ${I}" Report "deleted_file[]=${I}" done - Display --indent 2 --text "- Checking deleted files in use" --result "FILES FOUND" --color YELLOW + Display --indent 2 --text "- Checking deleted files in use" --result "${STATUS_FILES_FOUND}" --color YELLOW ReportSuggestion "${TEST_NO}" "Check what deleted files are still in use and why." else LogText "Result: no deleted files found" diff --git a/include/tests_mac_frameworks b/include/tests_mac_frameworks index 972bbb8a..5c55e8f5 100644 --- a/include/tests_mac_frameworks +++ b/include/tests_mac_frameworks @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -24,7 +24,7 @@ SELINUXFOUND=0 TOMOYOFOUND=0 - InsertSection "Security frameworks" + InsertSection "${SECTION_SECURITY_FRAMEWORKS}" # ################################################################################# # @@ -75,6 +75,12 @@ Report "apparmor_enabled=1" Report "apparmor_policy_loaded=1" AddHP 3 3 + # ignore kernel threads (Parent PID = 2 [kthreadd]) + NUNCONFINED=$(${PSBINARY} -N --ppid 2 -o label | ${GREPBINARY} '^unconfined' | ${WCBINARY} -l) + Display --indent 8 --text "Found ${NUNCONFINED} unconfined processes" + for PROCESS in $(${PSBINARY} -N --ppid 2 -o label:1,pid,comm | ${GREPBINARY} '^unconfined' | ${TRBINARY} ' ' ':'); do + LogText "Result: Unconfined process: ${PROCESS}" + done elif [ $? -eq 4 ]; then LogText "Result: Can not determine status, most likely due to lacking permissions" Display --indent 4 --text "- Checking AppArmor status" --result "${STATUS_UNKNOWN}" --color RED @@ -152,6 +158,17 @@ Display --indent 6 --text "- Checking current mode and config file" --result "${STATUS_WARNING}" --color RED fi Display --indent 8 --text "Current SELinux mode: ${FIND}" + PERMISSIVE=$(${SEMANAGEBINARY} permissive --list --noheading | ${TRBINARY} '\n' ' ') + NPERMISSIVE=$(${SEMANAGEBINARY} permissive --list --noheading | ${WCBINARY} -l) + Display --indent 8 --text "Found ${NPERMISSIVE} permissive SELinux object types" + LogText "Permissive SELinux object types: ${PERMISSIVE}" + UNCONFINED=$(${PSBINARY} -eo label,pid,command | ${GREPBINARY} '[u]nconfined_t' | ${TRBINARY} '\n' ' ') + INITRC=$(${PSBINARY} -eo label,pid,command | ${GREPBINARY} '[i]nitrc_t' | ${TRBINARY} '\n' ' ') + NUNCONFINED=$(${PSBINARY} -eo label | ${GREPBINARY} '[u]nconfined_t' | ${WCBINARY} -l) + NINITRC=$(${PSBINARY} -eo label | ${GREPBINARY} '[i]nitrc_t' | ${WCBINARY} -l) + Display --indent 8 --text "Found ${NUNCONFINED} unconfined and ${NINITRC} initrc_t processes" + LogText "Unconfined processes: ${UNCONFINED}" + LogText "Processes with initrc_t type: ${INITRC}" else LogText "Result: SELinux framework is disabled" Display --indent 4 --text "- Checking SELinux status" --result "${STATUS_DISABLED}" --color YELLOW @@ -189,6 +206,13 @@ LogText "Result: TOMOYO Linux is enabled" Display --indent 4 --text "- Checking TOMOYO Linux status" --result "${STATUS_ENABLED}" --color GREEN Report "tomoyo_enabled=1" + if [ ! -z ${TOMOYOPSTREEBINARY} ]; then + NUNCONFINED=$(${TOMOYOPSTREEBINARY} | ${GREPBINARY} -v '^ 3 ' | ${WCBINARY} -l) + Display --indent 8 --text "Found ${NUNCONFINED} unconfined (not profile 3) processes" + for PROCESS in $(${TOMOYOPSTREEBINARY} | ${GREPBINARY} -v '^ 3 ' | ${SEDBINARY} -e 's/+-//g' -e 's/^ *//g' -e 's/ \+/:/g' | ${SORTBINARY}); do + LogText "Result: Unconfined process: ${PROCESS}" + done + fi AddHP 3 3 else LogText "Result: TOMOYO Linux is disabled" diff --git a/include/tests_mail_messaging b/include/tests_mail_messaging index 63b43804..cbbde8a0 100644 --- a/include/tests_mail_messaging +++ b/include/tests_mail_messaging @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -22,7 +22,7 @@ # ################################################################################# # - InsertSection "Software: e-mail and messaging" + InsertSection "${SECTION_EMAIL_AND_MESSAGING}" # ################################################################################# # @@ -61,7 +61,7 @@ # Test : MAIL-8804 # Description : Exim configuration options if [ ${EXIM_RUNNING} -eq 1 -a ! "${EXIMBINARY}" = "" ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi - Register --test-no MAIL-8803 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Exim configuration options" + Register --test-no MAIL-8804 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Exim configuration options" if [ ${SKIPTEST} -eq 0 -a ${EXIM_RUNNING} -eq 1 ]; then LogText "Test: Exim configuration options" diff --git a/include/tests_malware b/include/tests_malware index d983b17f..3c2cd72d 100644 --- a/include/tests_malware +++ b/include/tests_malware @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -22,7 +22,7 @@ # ################################################################################# # - InsertSection "Software: ${SECTION_MALWARE}" + InsertSection "${SECTION_MALWARE}" # ################################################################################# # @@ -39,6 +39,7 @@ MALWARE_SCANNER_INSTALLED=0 SOPHOS_SCANNER_RUNNING=0 SYMANTEC_SCANNER_RUNNING=0 + SYNOLOGY_DAEMON_RUNNING=0 # ################################################################################# # @@ -102,28 +103,6 @@ if [ ${SKIPTEST} -eq 0 ]; then FOUND=0 - # ESET security products - LogText "Test: checking process esets_daemon" - if IsRunning "esets_daemon"; then - FOUND=1 - ESET_DAEMON_RUNNING=1 - MALWARE_SCANNER_INSTALLED=1 - if IsVerbose; then Display --indent 2 --text "- ${GEN_CHECKING} ESET daemon" --result "${STATUS_FOUND}" --color GREEN; fi - LogText "Result: found ESET security product" - Report "malware_scanner[]=eset" - fi - - # Bitdefender (macOS) - LogText "Test: checking process epagd" - if IsRunning "epagd"; then - FOUND=1 - BITDEFENDER_DAEMON_RUNNING=1 - MALWARE_SCANNER_INSTALLED=1 - if IsVerbose; then Display --indent 2 --text "- ${GEN_CHECKING} Bitdefender agent" --result "${STATUS_FOUND}" --color GREEN; fi - LogText "Result: found Bitdefender security product" - Report "malware_scanner[]=bitdefender" - fi - # Avast (macOS) LogText "Test: checking process com.avast.daemon" if IsRunning "com.avast.daemon"; then @@ -146,6 +125,17 @@ Report "malware_scanner[]=avira" fi + # Bitdefender (macOS) + LogText "Test: checking process epagd" + if IsRunning "bdagentd" || IsRunning "epagd"; then + FOUND=1 + BITDEFENDER_DAEMON_RUNNING=1 + MALWARE_SCANNER_INSTALLED=1 + if IsVerbose; then Display --indent 2 --text "- ${GEN_CHECKING} Bitdefender agent" --result "${STATUS_FOUND}" --color GREEN; fi + LogText "Result: found Bitdefender security product" + Report "malware_scanner[]=bitdefender" + fi + # CrowdStrike falcon-sensor LogText "Test: checking process falcon-sensor (CrowdStrike)" if IsRunning "falcon-sensor"; then @@ -168,6 +158,17 @@ Report "malware_scanner[]=cylance-protect" fi + # ESET security products + LogText "Test: checking process esets_daemon" + if IsRunning "esets_daemon"; then + FOUND=1 + ESET_DAEMON_RUNNING=1 + MALWARE_SCANNER_INSTALLED=1 + if IsVerbose; then Display --indent 2 --text "- ${GEN_CHECKING} ESET daemon" --result "${STATUS_FOUND}" --color GREEN; fi + LogText "Result: found ESET security product" + Report "malware_scanner[]=eset" + fi + # Kaspersky products LogText "Test: checking process wdserver or klnagent (Kaspersky)" # wdserver is too generic to match on, so we want to ensure that it is related to Kaspersky first @@ -239,6 +240,17 @@ Report "malware_scanner[]=symantec" fi + # Synology Antivirus Essential + LogText "Test: checking process synoavd" + if IsRunning "synoavd"; then + FOUND=1 + SYNOLOGY_DAEMON_RUNNING=1 + MALWARE_SCANNER_INSTALLED=1 + if IsVerbose; then Display --indent 2 --text "- ${GEN_CHECKING} Synology Antivirus Essential" --result "${STATUS_FOUND}" --color GREEN; fi + LogText "Result: found Synology Antivirus Essential" + Report "malware_scanner[]=synoavd" + fi + # TrendMicro (macOS) LogText "Test: checking process TmccMac to test for Trend Micro anti-virus (macOS)" if IsRunning "TmccMac"; then diff --git a/include/tests_memory_processes b/include/tests_memory_processes index 6c1bf558..2454f320 100644 --- a/include/tests_memory_processes +++ b/include/tests_memory_processes @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -118,7 +118,7 @@ # # Test : PROC-3802 # Description : Check presence of prelink tooling - Register --test-no PROC-3802 --weight L --network NO --category security --description "Check presence of prelink tooling" + Register --test-no PROC-3802 --package-manager-required --os Linux --weight L --network NO --category security --description "Check presence of prelink tooling" if [ ${SKIPTEST} -eq 0 ]; then if PackageIsInstalled "prelink"; then LogText "Result: prelink packages is installed" diff --git a/include/tests_nameservices b/include/tests_nameservices index 59983cac..46f4f1fb 100644 --- a/include/tests_nameservices +++ b/include/tests_nameservices @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -22,7 +22,7 @@ # ################################################################################# # - InsertSection "Name services" + InsertSection "${SECTION_NAME_SERVICES}" # ################################################################################# # diff --git a/include/tests_networking b/include/tests_networking index 51bed912..7a04305f 100644 --- a/include/tests_networking +++ b/include/tests_networking @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -31,7 +31,56 @@ # ################################################################################# # - InsertSection "Networking" + InsertSection "${SECTION_NETWORKING}" +# +################################################################################# +# + # Test : NETW-2400 + # Description : Test hostname for valid characters and length + # Notes : FQDN: max 253 characters + # : component: a-z, 0-9, hyphen, not start with hyphen, max 63 characters + # dots allowed as separator + Register --test-no NETW-2400 --weight L --network YES --category basics --description "Hostname length and value check" + if [ ${SKIPTEST} -eq 0 ]; then + # Test first the fully qualified domain name + if [ ${#FQDN} -gt 253 ]; then + # Too long + LogText "Result: FQDN is more than 253 characters" + Display --indent 2 --text "- Hostname (FQDN length)" --result "${STATUS_WARNING}" --color RED + ReportWarning "${TEST_NO}" "Hostname is too long (more than 253 characters)" + elif [ ${#FQDN} -eq 0 ]; then + # FQDN not defined + LogText "Result: FQDN is not defined" + if IsVerbose; then Display --indent 2 --text "- Hostname (FQDN length)" --result "${STATUS_UNKNOWN}" --color YELLOW; fi + else + # Fine + LogText "Result: FQDN is defined and not longer than 253 characters (${#FQDN} characters)" + if IsVerbose; then Display --indent 2 --text "- Hostname (FQDN length)" --result "${STATUS_OK}" --color GREEN; fi + fi + # Now test short hostname + if [ ${#HOSTNAME} -eq 0 ]; then + if IsVerbose; then Display --indent 2 --text "- Hostname (FQDN length)" --result "${STATUS_NONE}" --color RED; fi + LogText "Result: hostname is not defined" + else + # Test length + if [ ${#HOSTNAME} -gt 63 ]; then + LogText "Result: hostname is more than 63 characters" + Display --indent 2 --text "- Hostname (length)" --result "${STATUS_WARNING}" --color RED + else + LogText "Result: hostnamed is defined and not longer than 63 characters" + fi + # Test valid characters (normally a dot should not be in the name, but we can't be 100% sure we have short name) + FIND=$(echo "${HOSTNAME}" | ${TRBINARY} -d '[:alnum:]\.\-') + if [ -z "${FIND}" ]; then + LogText "Result: good, no unexpected characters discovered in hostname" + if IsVerbose; then Display --indent 2 --text "- Hostname (allowed characters)" --result "${STATUS_OK}" --color GREEN; fi + else + LogText "Result: unexpected characters discovered in hostname (characters: ${FIND}), which may impact network connectivity" + Display --indent 2 --text "- Hostname (allowed characters)" --result "${STATUS_WARNING}" --color RED + ReportWarning "${TEST_NO}" "Hostname contains invalid characters" "hostname" "text:See log file for invalid characters" + fi + fi + fi # ################################################################################# # @@ -91,7 +140,7 @@ Display --indent 2 --text "- Checking IPv6 configuration" --result "${STATUS_ENABLED}" --color WHITE STATUS=$(echo ${IPV6_MODE} | ${TRBINARY} '[:lower:]' '[:upper:]') Display --indent 6 --text "Configuration method" --result "${STATUS}" --color WHITE - if [ ${IPV6_ONLY} -eq 1 ]; then STATUS="YES"; else STATUS="NO"; fi + if [ ${IPV6_ONLY} -eq 1 ]; then STATUS="${STATUS_YES}"; else STATUS="${STATUS_NO}"; fi LogText "Result: IPv6 only configuration: ${STATUS}" Display --indent 6 --text "IPv6 only" --result "${STATUS}" --color WHITE else @@ -190,6 +239,40 @@ # ################################################################################# # + # Test : NETW-2706 + # Description : Check systemd-resolve output and upstream DNSSEC status + # Notes : Ubuntu 16.04 uses systemd-resolve, newer ones most likely resolvectl + if [ -n "${RESOLVECTLBINARY}" ]; then + PREQS_MET="YES" + RESOLVE_CMD="${RESOLVECTLBINARY}" + RESOLVE_CMD_PARAM="statistics" + elif [ -n "$(command -v systemd-resolve 2> /dev/null)" ]; then + PREQS_MET="YES" + RESOLVE_CMD="$(command -v systemd-resolve 2> /dev/null)" + RESOLVE_CMD_PARAM="--statistics" + else + PREQS_MET="NO" + fi + Register --test-no NETW-2706 --preqs-met "${PREQS_MET}" --weight L --network YES --category security --description "Check systemd-resolved and upstream DNSSEC status" + if [ ${SKIPTEST} -eq 0 ]; then + SKIP=0 + DNSSEC_STATUS=$(${RESOLVE_CMD} ${RESOLVE_CMD_PARAM} 2> /dev/null | ${AWKBINARY} -F ":" '/DNSSEC supported/ { print $2 }' | ${TRBINARY} -d ' ') + if [ "${DNSSEC_STATUS}" = "yes" ]; then + Display --indent 4 --text "- DNSSEC supported (systemd-resolved)" --result "${STATUS_YES}" --color GREEN + LogText "Result: DNSSEC supported by systemd-resolved and upstream DNS servers" + elif [ "${DNSSEC_STATUS}" = "no" ]; then + Display --indent 4 --text "- DNSSEC supported (systemd-resolved)" --result "${STATUS_NO}" --color YELLOW + LogText "Result: DNSSEC not supported by systemd-resolved or upstream DNS servers" + else + Display --indent 4 --text "- DNSSEC supported (systemd-resolved)" --result "${STATUS_UNKNOWN}" --color RED + LogText "Result: command '${RESOLVE_CMD} ${RESOLVE_CMD_PARAM}' returned an error. Please run command manually to check for details." + fi + else + LogText "Result: Test most likely skipped due to not having resolvectl" + fi +# +################################################################################# +# # Test : NETW-3001 # Description : Find default gateway (route) # More info : BSD: ^default Linux: 0.0.0.0 @@ -429,6 +512,15 @@ ReportException "${TEST_NO}:3" "netstat missing to gather listening ports" fi ;; + Solaris) + if [ -n "${NETSTATBINARY}" ]; then + LogText "Test: Retrieving netstat information to find listening ports" + FIND=$(${NETSTATBINARY} -an -P udp | ${AWKBINARY} '{ if($7=="LISTEN") { print $1"|udp|LISTEN|" }}') + FIND2=$(${NETSTATBINARY} -an -P tcp | ${AWKBINARY} '{ if($7=="LISTEN") { print $1"|tcp|LISTEN|" }}') + else + ReportException "${TEST_NO}:4" "netstat missing to gather listening ports" + fi + ;; *) # Got this exception? Provide your details and output of netstat or any other tool to determine this information. ReportException "${TEST_NO}:2" "Unclear what method to use, to determine listening port information" @@ -600,7 +692,7 @@ Display --indent 2 --text "- Checking status DHCP client" --result "${STATUS_RUNNING}" --color WHITE DHCP_CLIENT_RUNNING=1 else - Display --indent 2 --text "- Checking status DHCP client" --result "NOT ACTIVE" --color WHITE + Display --indent 2 --text "- Checking status DHCP client" --result "${STATUS_NOT_ACTIVE}" --color WHITE fi fi # @@ -641,40 +733,44 @@ # # Test : NETW-3200 # Description : Determine available network protocols + # Notes : See all available supported modules: ls -d /lib/modules/$(uname -r )/kernel/net + # To see active/enabled protocols: ls -d /proc/sys/net Register --test-no NETW-3200 --weight L --network YES --category security --description "Determine available network protocols" if [ ${SKIPTEST} -eq 0 ]; then TESTED=0 + FOUND_UNCOMMON_PROTOCOL_ENABLED=0 case ${OS} in Linux) TESTED=1 LogText "Test: checking the status of some network protocols that typically are not used" UNCOMMON_PROTOCOLS="dccp sctp rds tipc" for P in ${UNCOMMON_PROTOCOLS}; do + LogText "Test: now checking module '${P}'" if ! SkipAtomicTest "${TEST_NO}:${P}"; then - FOUND_UNCOMMON_PROTOCOL=0 + UNCOMMON_PROTOCOL_DISABLED=0 + # First check modprobe.conf if [ -f ${ROOTDIR}etc/modprobe.conf ]; then DATA=$(${GREPBINARY} "^install ${P} /bin/true" ${ROOTDIR}etc/modprobe.conf) if [ -n "${DATA}" ]; then - LogText "Result: found ${P} module loaded via modprobe.conf" - FOUND_UNCOMMON_PROTOCOL=1 + LogText "Result: found ${P} module disabled via modprobe.conf" + UNCOMMON_PROTOCOL_DISABLED=1 fi fi + # Then additional modprobe configuration files if [ -d ${ROOTDIR}etc/modprobe.d ]; then DATA=$(${GREPBINARY} --files-with-matches --no-messages "^install ${P} /bin/true" ${ROOTDIR}etc/modprobe.d/*) if [ -n "${DATA}" ]; then - FOUND_UNCOMMON_PROTOCOL=1 + UNCOMMON_PROTOCOL_DISABLED=1 for F in ${DATA}; do - LogText "Result: found ${P} module loaded via ${F}" + LogText "Result: found ${P} module disabled via ${F}" done fi fi - # Although a protocol may not been enabled using install, it can be loaded. This may be revealed using /proc - #/proc/sys/net/ - - if [ ${FOUND_UNCOMMON_PROTOCOL} -eq 1 ]; then - ReportSuggestion "${TEST_NO}" "Determine if network protocol ${P} needs to be used on this system" + if [ ${UNCOMMON_PROTOCOL_DISABLED} -eq 0 ]; then + ReportSuggestion "${TEST_NO}" "Determine if protocol '${P}' is really needed on this system" Report "uncommon_network_protocol_enabled=${P}" + FOUND_UNCOMMON_PROTOCOL_ENABLED=1 fi fi done @@ -686,7 +782,7 @@ ;; esac if [ ${TESTED} -eq 1 ]; then - if [ ${FOUND_UNCOMMON_PROTOCOL} -eq 1 ]; then + if [ ${FOUND_UNCOMMON_PROTOCOL_ENABLED} -eq 1 ]; then Display --indent 2 --text "- Uncommon network protocols" --result "${FOUND}" --color YELLOW else Display --indent 2 --text "- Uncommon network protocols" --result "${STATUS_NOT_FOUND}" --color GREEN @@ -698,7 +794,6 @@ ################################################################################# # - WaitForKeyPress # diff --git a/include/tests_php b/include/tests_php index d84b181a..32211f1a 100644 --- a/include/tests_php +++ b/include/tests_php @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -36,6 +36,7 @@ ${ROOTDIR}etc/php7.1/php.ini \ ${ROOTDIR}etc/php7.2/php.ini \ ${ROOTDIR}etc/php7.3/php.ini \ + ${ROOTDIR}etc/php7.4/php.ini \ ${ROOTDIR}etc/php/cgi-php5/php.ini \ ${ROOTDIR}etc/php/cli-php5/php.ini \ ${ROOTDIR}etc/php/apache2-php5/php.ini \ @@ -45,24 +46,29 @@ ${ROOTDIR}etc/php/apache2-php7.1/php.ini \ ${ROOTDIR}etc/php/apache2-php7.2/php.ini \ ${ROOTDIR}etc/php/apache2-php7.3/php.ini \ + ${ROOTDIR}etc/php/apache2-php7.4/php.ini \ ${ROOTDIR}etc/php/cgi-php5.5/php.ini \ ${ROOTDIR}etc/php/cgi-php5.6/php.ini \ ${ROOTDIR}etc/php/cgi-php7.0/php.ini \ ${ROOTDIR}etc/php/cgi-php7.1/php.ini \ ${ROOTDIR}etc/php/cgi-php7.2/php.ini \ ${ROOTDIR}etc/php/cgi-php7.3/php.ini \ + ${ROOTDIR}etc/php/cgi-php7.4/php.ini \ ${ROOTDIR}etc/php/cli-php5.5/php.ini \ ${ROOTDIR}etc/php/cli-php5.6/php.ini \ ${ROOTDIR}etc/php/cli-php7.0/php.ini \ ${ROOTDIR}etc/php/cli-php7.1/php.ini \ ${ROOTDIR}etc/php/cli-php7.2/php.ini \ ${ROOTDIR}etc/php/cli-php7.3/php.ini \ + ${ROOTDIR}etc/php/cli-php7.4/php.ini \ ${ROOTDIR}etc/php/embed-php5.5/php.ini \ ${ROOTDIR}etc/php/embed-php5.6/php.ini \ ${ROOTDIR}etc/php/embed-php7.0/php.ini \ ${ROOTDIR}etc/php/embed-php7.1/php.ini \ ${ROOTDIR}etc/php/embed-php7.2/php.ini \ ${ROOTDIR}etc/php/embed-php7.3/php.ini \ + ${ROOTDIR}etc/php/embed-php7.4/php.ini \ + ${ROOTDIR}etc/php/fpm-php7.4/php.ini \ ${ROOTDIR}etc/php/fpm-php7.3/php.ini \ ${ROOTDIR}etc/php/fpm-php7.2/php.ini \ ${ROOTDIR}etc/php/fpm-php7.1/php.ini \ @@ -71,7 +77,9 @@ ${ROOTDIR}etc/php/fpm-php5.6/php.ini \ ${ROOTDIR}etc/php5/cgi/php.ini \ ${ROOTDIR}etc/php5/cli/php.ini \ - ${ROOTDIR}etc/php5/cli-php5.4/php.ini ${ROOTDIR}etc/php5/cli-php5.5/php.ini ${ROOTDIR}etc/php5/cli-php5.6/php.ini \ + ${ROOTDIR}etc/php5/cli-php5.4/php.ini \ + ${ROOTDIR}etc/php5/cli-php5.5/php.ini \ + ${ROOTDIR}etc/php5/cli-php5.6/php.ini \ ${ROOTDIR}etc/php5/apache2/php.ini \ ${ROOTDIR}etc/php5/fpm/php.ini \ ${ROOTDIR}private/etc/php.ini \ @@ -79,12 +87,20 @@ ${ROOTDIR}etc/php/7.1/apache2/php.ini \ ${ROOTDIR}etc/php/7.2/apache2/php.ini \ ${ROOTDIR}etc/php/7.3/apache2/php.ini \ - ${ROOTDIR}etc/php/7.0/cli/php.ini ${ROOTDIR}etc/php/7.0/fpm/php.ini \ - ${ROOTDIR}etc/php/7.1/cli/php.ini ${ROOTDIR}etc/php/7.1/fpm/php.ini \ - ${ROOTDIR}etc/php/7.2/cli/php.ini ${ROOTDIR}etc/php/7.2/fpm/php.ini \ - ${ROOTDIR}etc/php/7.3/cli/php.ini ${ROOTDIR}etc/php/7.3/fpm/php.ini \ + ${ROOTDIR}etc/php/7.4/apache2/php.ini \ + ${ROOTDIR}etc/php/7.0/cli/php.ini \ + ${ROOTDIR}etc/php/7.0/fpm/php.ini \ + ${ROOTDIR}etc/php/7.1/cli/php.ini \ + ${ROOTDIR}etc/php/7.1/fpm/php.ini \ + ${ROOTDIR}etc/php/7.2/cli/php.ini \ + ${ROOTDIR}etc/php/7.2/fpm/php.ini \ + ${ROOTDIR}etc/php/7.3/cli/php.ini \ + ${ROOTDIR}etc/php/7.3/fpm/php.ini \ + ${ROOTDIR}etc/php/7.4/cli/php.ini \ + ${ROOTDIR}etc/php/7.4/fpm/php.ini \ ${ROOTDIR}var/www/conf/php.ini \ - ${ROOTDIR}usr/local/etc/php.ini ${ROOTDIR}usr/local/lib/php.ini \ + ${ROOTDIR}usr/local/etc/php.ini \ + ${ROOTDIR}usr/local/lib/php.ini \ ${ROOTDIR}usr/local/etc/php5/cgi/php.ini \ ${ROOTDIR}usr/local/php54/lib/php.ini \ ${ROOTDIR}usr/local/php56/lib/php.ini \ @@ -92,6 +108,7 @@ ${ROOTDIR}usr/local/php71/lib/php.ini \ ${ROOTDIR}usr/local/php72/lib/php.ini \ ${ROOTDIR}usr/local/php73/lib/php.ini \ + ${ROOTDIR}usr/local/php74/lib/php.ini \ ${ROOTDIR}usr/local/zend/etc/php.ini \ ${ROOTDIR}usr/pkg/etc/php.ini \ ${ROOTDIR}opt/cpanel/ea-php54/root/etc/php.ini \ @@ -101,6 +118,7 @@ ${ROOTDIR}opt/cpanel/ea-php71/root/etc/php.ini \ ${ROOTDIR}opt/cpanel/ea-php72/root/etc/php.ini \ ${ROOTDIR}opt/cpanel/ea-php73/root/etc/php.ini \ + ${ROOTDIR}opt/cpanel/ea-php74/root/etc/php.ini \ ${ROOTDIR}opt/alt/php44/etc/php.ini \ ${ROOTDIR}opt/alt/php51/etc/php.ini \ ${ROOTDIR}opt/alt/php52/etc/php.ini \ @@ -112,27 +130,42 @@ ${ROOTDIR}opt/alt/php71/etc/php.ini \ ${ROOTDIR}opt/alt/php72/etc/php.ini \ ${ROOTDIR}opt/alt/php73/etc/php.ini \ + ${ROOTDIR}opt/alt/php74/etc/php.ini \ ${ROOTDIR}etc/opt/remi/php56/php.ini \ ${ROOTDIR}etc/opt/remi/php70/php.ini \ ${ROOTDIR}etc/opt/remi/php71/php.ini \ ${ROOTDIR}etc/opt/remi/php72/php.ini \ - ${ROOTDIR}etc/opt/remi/php73/php.ini" + ${ROOTDIR}etc/opt/remi/php73/php.ini \ + ${ROOTDIR}etc/opt/remi/php74/php.ini" # HEADS-UP: OpenBSD, last two releases are supported, and snapshots of -current PHPINILOCS="${PHPINILOCS} \ - ${ROOTDIR}etc/php-5.6.ini ${ROOTDIR}etc/php-7.0.ini ${ROOTDIR}etc/php-7.1.ini ${ROOTDIR}etc/php-7.2.ini ${ROOTDIR}etc/php-7.3.ini" + ${ROOTDIR}etc/php-5.6.ini \ + ${ROOTDIR}etc/php-7.0.ini \ + ${ROOTDIR}etc/php-7.1.ini \ + ${ROOTDIR}etc/php-7.2.ini \ + ${ROOTDIR}etc/php-7.3.ini \ + ${ROOTDIR}etc/php-7.4.ini" PHPINIDIRS="${ROOTDIR}etc/php5/conf.d \ ${ROOTDIR}etc/php/7.0/cli/conf.d \ ${ROOTDIR}etc/php/7.1/cli/conf.d \ ${ROOTDIR}etc/php/7.2/cli/conf.d \ ${ROOTDIR}etc/php/7.3/cli/conf.d \ + ${ROOTDIR}etc/php/7.4/cli/conf.d \ ${ROOTDIR}etc/php/7.0/fpm/conf.d \ ${ROOTDIR}etc/php/7.1/fpm/conf.d \ ${ROOTDIR}etc/php/7.2/fpm/conf.d \ ${ROOTDIR}etc/php/7.3/fpm/conf.d \ + ${ROOTDIR}etc/php/7.4/fpm/conf.d \ ${ROOTDIR}etc/php.d \ - ${ROOTDIR}opt/cpanel/ea-php54/root/etc/php.d ${ROOTDIR}opt/cpanel/ea-php55/root/etc/php.d ${ROOTDIR}opt/cpanel/ea-php56/root/etc/php.d ${ROOTDIR}opt/cpanel/ea-php70/root/etc/php.d \ - ${ROOTDIR}opt/cpanel/ea-php71/root/etc/php.d ${ROOTDIR}opt/cpanel/ea-php72/root/etc/php.d ${ROOTDIR}opt/cpanel/ea-php73/root/etc/php.d \ + ${ROOTDIR}opt/cpanel/ea-php54/root/etc/php.d \ + ${ROOTDIR}opt/cpanel/ea-php55/root/etc/php.d \ + ${ROOTDIR}opt/cpanel/ea-php56/root/etc/php.d \ + ${ROOTDIR}opt/cpanel/ea-php70/root/etc/php.d \ + ${ROOTDIR}opt/cpanel/ea-php71/root/etc/php.d \ + ${ROOTDIR}opt/cpanel/ea-php72/root/etc/php.d \ + ${ROOTDIR}opt/cpanel/ea-php73/root/etc/php.d \ + ${ROOTDIR}opt/cpanel/ea-php74/root/etc/php.d \ ${ROOTDIR}opt/alt/php44/etc/php.d.all \ ${ROOTDIR}opt/alt/php51/etc/php.d.all \ ${ROOTDIR}opt/alt/php52/etc/php.d.all \ @@ -144,14 +177,21 @@ ${ROOTDIR}opt/alt/php71/etc/php.d.all \ ${ROOTDIR}opt/alt/php72/etc/php.d.all \ ${ROOTDIR}opt/alt/php73/etc/php.d.all \ + ${ROOTDIR}opt/alt/php74/etc/php.d.all \ ${ROOTDIR}usr/local/lib/php.conf.d \ ${ROOTDIR}usr/local/php70/lib/php.conf.d \ ${ROOTDIR}usr/local/php71/lib/php.conf.d \ ${ROOTDIR}usr/local/php72/lib/php.conf.d \ - ${ROOTDIR}usr/local/php73/lib/php.conf.d" + ${ROOTDIR}usr/local/php73/lib/php.conf.d \ + ${ROOTDIR}usr/local/php74/lib/php.conf.d" # HEADS-UP: OpenBSD, last two releases are supported, and snapshots of -current PHPINIDIRS="${PHPINIDIRS} \ - ${ROOTDIR}etc/php-5.6 ${ROOTDIR}etc/php-7.0 ${ROOTDIR}etc/php-7.1 ${ROOTDIR}etc/php-7.2 ${ROOTDIR}etc/php-7.3" + ${ROOTDIR}etc/php-5.6 \ + ${ROOTDIR}etc/php-7.0 \ + ${ROOTDIR}etc/php-7.1 \ + ${ROOTDIR}etc/php-7.2 \ + ${ROOTDIR}etc/php-7.3 \ + ${ROOTDIR}etc/php-7.4" # ################################################################################# # @@ -291,6 +331,12 @@ if [ ${SKIPTEST} -eq 0 ]; then FOUND=0 for FILE in ${PHPINI_ALLFILES}; do + # Don't look at this setting in cli configuration + case "${FILE}" in + */cli/*) + continue + ;; + esac LogText "Test: Checking file ${FILE}" FIND=$(${EGREPBINARY} -i 'expose_php.*(on|yes|1)' ${FILE} | ${GREPBINARY} -v '^;') if HasData "${FIND}"; then @@ -458,6 +504,42 @@ # ################################################################################# # + # Test : PHP-2382 + # Description : Check listen option + # Background : https://github.com/CISOfy/lynis/issues/837 + if [ -n "${PHPINI_ALLFILES}" ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi + Register --test-no PHP-2382 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check PHP expose_php option" + if [ ${SKIPTEST} -eq 0 ]; then + FOUND=0 + for FILE in ${PHPINI_ALLFILES}; do + # Don't look at this setting in cli configuration + case "${FILE}" in + */cli/*) + continue + ;; + esac + LogText "Test: Checking file ${FILE}" + FIND=$(${EGREPBINARY} -i "^listen = [0-9]{1,5}$" ${FILE}) + if HasData "${FIND}"; then + LogText "Result: found listen on just a port number" + LogText "Data: ${FIND}" + LogText "Note: when possible, limit access to just localhost, so it can't be accessed from outside" + FOUND=1 + fi + done + + if [ ${FOUND} -eq 1 ]; then + Display --indent 4 --text "- Checking listen option" --result "${STATUS_SUGGESTION}" --color YELLOW + #ReportSuggestion "${TEST_NO}" "Limit the listening of FastCGI to just localhost or a local socket" "listen = 127.0.0.1:9000" "-" + AddHP 1 3 + else + Display --indent 4 --text "- Checking listen option" --result "${STATUS_OK}" --color GREEN + AddHP 2 2 + fi + fi +# +################################################################################# +# WaitForKeyPress diff --git a/include/tests_ports_packages b/include/tests_ports_packages index 4d037bf7..2e827813 100644 --- a/include/tests_ports_packages +++ b/include/tests_ports_packages @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -22,7 +22,7 @@ # ################################################################################# # - InsertSection "Ports and packages" + InsertSection "${SECTION_PORTS_AND_PACKAGES}" PACKAGE_MGR_PKG=0 PACKAGE_AUDIT_TOOL="" PACKAGE_AUDIT_TOOL_FOUND=0 @@ -38,7 +38,7 @@ # Test : PKGS-7301 # Description : Query FreeBSD pkg if [ -x ${ROOTDIR}usr/sbin/pkg ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi - Register --test-no PKGS-7301 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Query NetBSD pkg" + Register --test-no PKGS-7301 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Query FreeBSD pkg" if [ ${SKIPTEST} -eq 0 ]; then FIND=$(pkg -N 2>&1; echo $?) if [ "${FIND}" = "0" ]; then @@ -982,9 +982,19 @@ ################################################################################# # # Test : PKGS-7388 - # Description : Check security repository in Debian/ubuntu apt sources.list file - if [ -f ${ROOTDIR}etc/apt/sources.list -a -d ${ROOTDIR}etc/apt/sources.list.d ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi - Register --test-no PKGS-7388 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check security repository in Debian/ubuntu apt sources.list file" + # Description : Check security repository in Debian/Ubuntu apt sources.list file + PREQS_MET="NO" + if [ -f ${ROOTDIR}etc/apt/sources.list -a -d ${ROOTDIR}etc/apt/sources.list.d ]; then + case "${LINUX_VERSION}" in + "Debian" | "Linux Mint" | "Ubuntu") + PREQS_MET="YES" + ;; + *) + LogText "Skipping test, although sources.list or sources.list.d exists. This specific OS version most likely has no security repository" + ;; + esac + fi + Register --test-no PKGS-7388 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check security repository in apt sources.list file" if [ $SKIPTEST -eq 0 ]; then FOUND=0 if [ ${OPTION_DEBIAN_SKIP_SECURITY_REPOSITORY} -eq 0 ]; then @@ -1222,7 +1232,7 @@ ReportSuggestion "${TEST_NO}" "Install a package audit tool to determine vulnerable packages" LogText "Result: no package audit tool found" else - Display --indent 2 --text "- Checking package audit tool" --result INSTALLED --color GREEN + Display --indent 2 --text "- Checking package audit tool" --result "${STATUS_INSTALLED}" --color GREEN Display --indent 4 --text "Found: ${PACKAGE_AUDIT_TOOL}" LogText "Result: found package audit tool: ${PACKAGE_AUDIT_TOOL}" fi @@ -1279,7 +1289,7 @@ KERNELS=$(${ZYPPERBINARY} --non-interactive -n se --type package --match-exact --installed-only "kernel-default" 2> /dev/null | ${GREPBINARY} "kernel-default" | ${WCBINARY} -l) if [ ${KERNELS} -eq 0 ]; then LogText "Result: found no kernels from zypper output, which is unexpected." - ReportException "KRNL-5840:3" "Could not find any kernel packages via package manager. Maybe using a different kernel package?" + ReportException "${TEST_NO}" "Could not find any kernel packages via package manager. Maybe using a different kernel package?" elif [ ${KERNELS} -gt 3 ]; then LogText "Result: found more than 5 kernel packages on the system, which might indicate lack of regular cleanups" ReportSuggestion "${TEST_NO}" "Remove any unneeded kernel packages" @@ -1289,7 +1299,19 @@ fi if [ ${KERNELS} -eq 0 -a ${TESTED} -eq 1 ]; then - ReportException "KRNL-5840:1" "Could not find any kernel packages via package manager" + # Only report exception if there are kernels actually there. For example, LXC use the kernel of host system + case "${OS}" in + "Linux") + if [ -d "${ROOTDIR}boot" ]; then + if [ -z "$(${FINDBINARY} /boot -maxdepth 1 -type f -name 'vmlinuz*' -print -quit)" ]; then + ReportException "${TEST_NO}" "Could not find any kernel packages via package manager" + fi + fi + ;; + *) + ReportException "${TEST_NO}" "Could not find any kernel packages via package manager" + ;; + esac fi Report "installed_kernel_packages=${KERNELS}" @@ -1347,7 +1369,7 @@ Display --indent 2 --text "- Toolkit for automatic upgrades (${UNATTENDED_UPGRADES_TOOL})" --result "${STATUS_FOUND}" --color GREEN else AddHP 1 5 - Display --indent 2 --text "- Toolkit for automatic upgrades" --result "${STATUS_NOTFOUND}" --color YELLOW + Display --indent 2 --text "- Toolkit for automatic upgrades" --result "${STATUS_NOT_FOUND}" --color YELLOW LogText "Result: no toolkit for automatic updates discovered" ReportSuggestion "${TEST_NO}" "Consider using a tool to automatically apply upgrades" fi diff --git a/include/tests_printers_spools b/include/tests_printers_spoolers index 148bc007..61304f87 100644 --- a/include/tests_printers_spools +++ b/include/tests_printers_spoolers @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -34,7 +34,7 @@ # ################################################################################# # - InsertSection "Printers and Spools" + InsertSection "${SECTION_PRINTERS_AND_SPOOLS}" # ################################################################################# # @@ -134,23 +134,31 @@ # # Test : PRNT-2308 # Description : Check CUPS daemon network configuration + # Notes : Listen and SSLListen can be used if [ ${CUPSD_FOUND} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi Register --test-no PRNT-2308 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check CUPSd network configuration" if [ ${SKIPTEST} -eq 0 ]; then FOUND=0 # Checking network addresses LogText "Test: Checking CUPS daemon listening network addresses" - FIND=$(${GREPBINARY} "^Listen" ${CUPSD_CONFIG_FILE} | ${GREPBINARY} -v "/" | ${AWKBINARY} '{ print $2 }') + FIND=$(${EGREPBINARY} "^(SSL)?Listen" ${CUPSD_CONFIG_FILE} | ${GREPBINARY} -v "/" | ${AWKBINARY} '{ print $2 }') COUNT=0 for ITEM in ${FIND}; do - LogText "Found network address: ${ITEM}" + LogText "Result: found network address: ${ITEM}" COUNT=$((COUNT + 1)) FOUND=1 done - # Check if daemon is only running on localhost + # Search for Port statement + FIND=$(${EGREPBINARY} "^Port 631" ${CUPSD_CONFIG_FILE}) + if [ -n "${FIND}" ]; then + LogText "Result: found CUPS listening on port 631 (most likely all interfaces)" + FOUND=1 + fi + + # Check if daemon might be running on localhost if [ ${FOUND} -eq 0 ]; then - LogText "Result: no listen statement found in CUPS configuration file" + LogText "Result: CUPS does not look to be listening on a network port" elif [ ${COUNT} -eq 1 ]; then if [ "${FIND}" = "localhost:631" -o "${FIND}" = "127.0.0.1:631" ]; then LogText "Result: CUPS daemon only running on localhost" diff --git a/include/tests_scheduling b/include/tests_scheduling index 98b29932..b461ba95 100644 --- a/include/tests_scheduling +++ b/include/tests_scheduling @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -22,7 +22,7 @@ # ################################################################################# # - InsertSection "Scheduled tasks" + InsertSection "${SECTION_SCHEDULED_TASKS}" # ################################################################################# # diff --git a/include/tests_shells b/include/tests_shells index f440da5a..89be9979 100644 --- a/include/tests_shells +++ b/include/tests_shells @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -23,7 +23,7 @@ ################################################################################# # IDLE_TIMEOUT=0 - InsertSection "Shells" + InsertSection "${SECTION_SHELLS}" # ################################################################################# # @@ -115,7 +115,7 @@ if IsRunning "autolog"; then IDLE_TIMEOUT=1 LogText "Result: found autolog process to kill idle sessions" - Report="session_timeout_method[]=autolog" + Report "session_timeout_method[]=autolog" IDLE_TIMEOUT_METHOD="autolog" fi @@ -282,4 +282,4 @@ WaitForKeyPress # #================================================================================ -# Lynis - Copyright 2007-2019, CISOfy - http://cisofy.com +# Lynis - Copyright 2007-2020, CISOfy - http://cisofy.com diff --git a/include/tests_snmp b/include/tests_snmp index 6253f542..0bf785f0 100644 --- a/include/tests_snmp +++ b/include/tests_snmp @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -28,7 +28,7 @@ # ################################################################################# # - InsertSection "SNMP Support" + InsertSection "${SECTION_SNMP_SUPPORT}" # Test : SNMP-3302 # Description : Check for a running SNMP daemon @@ -104,4 +104,4 @@ WaitForKeyPress # #================================================================================ -# Lynis - Copyright 2007-2019 Michael Boelen, CISOfy - https://cisofy.com +# Lynis - Copyright 2007-2020 Michael Boelen, CISOfy - https://cisofy.com diff --git a/include/tests_squid b/include/tests_squid index 075ecbb4..d62310a3 100644 --- a/include/tests_squid +++ b/include/tests_squid @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -29,7 +29,7 @@ # ################################################################################# # - InsertSection "Squid Support" + InsertSection "${SECTION_SQUID_SUPPORT}" # ################################################################################# # @@ -325,4 +325,4 @@ WaitForKeyPress # #================================================================================ -# Lynis - Copyright 2007-2019 Michael Boelen, CISOfy - https://cisofy.com +# Lynis - Copyright 2007-2020 Michael Boelen, CISOfy - https://cisofy.com diff --git a/include/tests_ssh b/include/tests_ssh index 5c8b3775..43c678b9 100644 --- a/include/tests_ssh +++ b/include/tests_ssh @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -34,7 +34,7 @@ # ################################################################################# # - InsertSection "SSH Support" + InsertSection "${SECTION_SSH_SUPPORT}" # ################################################################################# # @@ -117,7 +117,7 @@ # Test : SSH-7408 # Description : Check SSH specific defined options # Notes : Instead of parsing the configuration file, we query the SSH daemon itself - if [ ${OPENSSHD_RUNNING} -eq 1 -a -n "${SSH_DAEMON_OPTIONS_FILE}" -a ${OPENSSHD_VERSION_MAJOR} -ge 5 -a ${OPENSSHD_VERSION_MINOR} -ge 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi + if [ ${OPENSSHD_RUNNING} -eq 1 -a -n "${SSH_DAEMON_OPTIONS_FILE}" -a \( ${OPENSSHD_VERSION_MAJOR} -gt 5 -o ${OPENSSHD_VERSION_MAJOR} -eq 5 -a ${OPENSSHD_VERSION_MINOR} -ge 1 \) ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi Register --test-no SSH-7408 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check SSH specific defined options" if [ ${SKIPTEST} -eq 0 ]; then LogText "Test: Checking specific defined options in ${SSH_DAEMON_OPTIONS_FILE}" @@ -151,7 +151,6 @@ StrictModes:YES,,NO:=\ TCPKeepAlive:NO,,YES:=\ UseDNS:NO,,YES:=\ - VerifyReverseMapping:YES,,NO:=\ X11Forwarding:NO,,YES:=\ AllowAgentForwarding:NO,,YES:=" diff --git a/include/tests_storage b/include/tests_storage index 8cf13b78..6ee1a78a 100644 --- a/include/tests_storage +++ b/include/tests_storage @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -18,7 +18,7 @@ # ################################################################################# # - InsertSection "Storage" + InsertSection "${SECTION_STORAGE}" # ################################################################################# # @@ -59,7 +59,7 @@ if [ ${FOUND} -eq 0 ]; then LogText "Result: firewire ohci driver is not explicitly disabled" - Display --indent 2 --text "- Checking firewire ohci driver (modprobe config)" --result "NOT DISABLED" --color WHITE + Display --indent 2 --text "- Checking firewire ohci driver (modprobe config)" --result "${STATUS_NOT_DISABLED}" --color WHITE ReportSuggestion "${TEST_NO}" "Disable drivers like firewire storage when not used, to prevent unauthorized storage or data theft" # after blacklisting modules, make sure to remove them from the initram filesystem: update-initramfs -u AddHP 2 3 @@ -77,4 +77,4 @@ WaitForKeyPress # #================================================================================ -# Lynis - Copyright 2007-2019, CISOfy, Michael Boelen - https://cisofy.com +# Lynis - Copyright 2007-2020, CISOfy, Michael Boelen - https://cisofy.com diff --git a/include/tests_storage_nfs b/include/tests_storage_nfs index 3d3ceab5..6aaafc79 100644 --- a/include/tests_storage_nfs +++ b/include/tests_storage_nfs @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com diff --git a/include/tests_system_integrity b/include/tests_system_integrity index 8b6910c1..825f3d70 100644 --- a/include/tests_system_integrity +++ b/include/tests_system_integrity @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -25,7 +25,7 @@ # ################################################################################# # - InsertSection "Software: system integrity" + InsertSection "${SECTION_SYSTEM_INTEGRITY}" Display --indent 2 --text "- Checking file integrity tools" # ################################################################################# @@ -51,4 +51,4 @@ WaitForKeyPress # #================================================================================ -# Lynis - Copyright 2007-2019 Michael Boelen, CISOfy - https://cisofy.com +# Lynis - Copyright 2007-2020 Michael Boelen, CISOfy - https://cisofy.com diff --git a/include/tests_time b/include/tests_time index d3bda505..0d1d65cb 100644 --- a/include/tests_time +++ b/include/tests_time @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -22,7 +22,7 @@ # ################################################################################# # - InsertSection "Time and Synchronization" + InsertSection "${SECTION_TIME_AND_SYNCHRONIZATION}" # ################################################################################# # @@ -36,6 +36,7 @@ NTP_CONFIG_TYPE_EVENTBASED=0 NTP_CONFIG_TYPE_STARTUP=0 NTPD_RUNNING=0 # Specific for ntpd + OPENNTPD_COMMUNICATION=0 # if ntpctl can communicate SYSTEMD_NTP_ENABLED=0 # ################################################################################# @@ -79,9 +80,36 @@ Display --indent 2 --text "- NTP daemon found: dntpd" --result "${STATUS_FOUND}" --color GREEN fi - # Check running processes - FIND=$(${PSBINARY} ax | ${GREPBINARY} "ntpd" | ${GREPBINARY} -v "dntpd" | ${GREPBINARY} -v "grep") - if [ -n "${FIND}" ]; then + # Check for OpenNTPD, ntpctl comes with a "regular" install + if [ -n "${NTPCTLBINARY}" ]; then + # In contrast to timectl, "synchronised: yes" is not grepped. + # Reason: openntpd syncs only if large time corrections are not required or -s is passed. + # This might be not intended by the administrator (-s is NOT the default!) + FIND=$(${PSBINARY} ax | ${GREPBINARY} "ntpd: ntp engine" | ${GREPBINARY} -v "grep") + # Status code 0 is when communication over the socket is successful + if ${NTPCTLBINARY} -s status > /dev/null 2> /dev/null; then + FOUND=1; NTP_DAEMON_RUNNING=1; NTP_CONFIG_TYPE_DAEMON=1; NTP_DAEMON="openntpd" + LogText "result: found openntpd (method: ntpctl)" + OPENNTPD_COMMUNICATION=1 + elif [ -n "${FIND}" ] ; then + # Reasons for ntpctl to fail might be someone spawned a new process thus overwriting the socket, + # then ended it, but another openntpd process is still running + FOUND=1; NTP_DAEMON_RUNNING=1; NTP_CONFIG_TYPE_DAEMON=1; NTP_DAEMON="openntpd" + LogText "result: found openntpd (method: ps)" + else + LogText "result: running openntpd not found, but ntpctl is installed" + fi + + if [ "${NTP_DAEMON}" = "openntpd" ]; then + Display --indent 2 --text "- NTP daemon found: OpenNTPD" --result "${STATUS_FOUND}" --color GREEN + fi + fi + + # Check running processes (ntpd from ntp.org) + # As checking by process name is ambiguous (openntpd has the same process name), + # this check will be skipped if openntpd has been found. + FIND=$(${PSBINARY} ax | ${GREPBINARY} "ntpd" | ${GREPBINARY} -v "dntpd" | ${GREPBINARY} -v "ntpd: " | ${GREPBINARY} -v "grep") + if [ "${NTP_DAEMON}" != "openntpd" ] && [ -n "${FIND}" ]; then FOUND=1; NTPD_RUNNING=1; NTP_DAEMON_RUNNING=1; NTP_CONFIG_TYPE_DAEMON=1 NTP_DAEMON="ntpd" LogText "Result: found running NTP daemon in process list" @@ -95,70 +123,54 @@ fi # Check timedate daemon (systemd) - if [ -n "${TIMEDATECTL}" ]; then - FIND=$(${TIMEDATECTL} status | ${EGREPBINARY} "(NTP|System clock) synchronized: yes") - if [ -n "${FIND}" ]; then - # Check for systemd-timesyncd - if [ -f ${ROOTDIR}etc/systemd/timesyncd.conf ]; then - LogText "Result: found ${ROOTDIR}etc/systemd/timesyncd.conf" - FOUND=1; NTP_DAEMON_RUNNING=1; NTP_CONFIG_TYPE_DAEMON=1; NTP_DAEMON="systemd-timesyncd" - Display --indent 2 --text "- NTP daemon found: systemd (timesyncd)" --result "${STATUS_FOUND}" --color GREEN - SYSTEMD_NTP_ENABLED=1 - else - LogText "Result: ${ROOTDIR}etc/systemd/timesyncd.conf does not exist" - fi - else - LogText "Result: time synchronization not performed according timedatectl command" - fi - else - LogText "Result: timedatectl command not available on this system" + FIND=$(${PSBINARY} ax | ${GREPBINARY} "systemd-timesyncd" | ${GREPBINARY} -v "grep") + if [ -n "${FIND}" ]; then + FOUND=1; NTP_DAEMON_RUNNING=1; NTP_CONFIG_TYPE_DAEMON=1; NTP_DAEMON="systemd-timesyncd" + Display --indent 2 --text "- NTP daemon found: systemd (timesyncd)" --result "${STATUS_FOUND}" --color GREEN + LogText "Result: Found running systemd-timesyncd in process list" fi # Check crontab for OpenBSD/FreeBSD # Check anacrontab for Linux CRONTAB_FILES="/etc/anacrontab /etc/crontab" + # Regex for matching multiple time synchronisation binaries + # Partial sanity check for sntp and ntpdig, but this does not consider all corner cases + CRONTAB_REGEX='ntpdate|rdate|sntp.+-(s|j|--adj)|ntpdig.+-(S|s)' for I in ${CRONTAB_FILES}; do if [ -f ${I} ]; then - LogText "Test: checking for ntpdate or rdate in crontab file ${I}" - FIND=$(${EGREPBINARY} "ntpdate|rdate" ${I} | ${GREPBINARY} -v '^#') + LogText "Test: checking for ntpdate, rdate, sntp or ntpdig in crontab file ${I}" + FIND=$(${EGREPBINARY} "${CRONTAB_REGEX}" ${I} | ${GREPBINARY} -v '^#') if [ -n "${FIND}" ]; then FOUND=1; NTP_CONFIG_TYPE_SCHEDULED=1 Display --indent 2 --text "- Checking NTP client in crontab file (${I})" --result "${STATUS_FOUND}" --color GREEN - LogText "Result: found ntpdate or rdate reference in crontab file ${I}" + LogText "Result: found ntpdate, rdate, sntp or ntpdig reference in crontab file ${I}" else #Display --indent 2 --text "- Checking NTP client in crontab file (${I})" --result "${STATUS_NOT_FOUND}" --color WHITE - LogText "Result: no ntpdate or rdate reference found in crontab file ${I}" + LogText "Result: no ntpdate, rdate, sntp or ntpdig reference found in crontab file ${I}" fi else LogText "Result: crontab file ${I} not found" fi done - # Don't run check in cron job directory on Solaris - # /etc/cron.d/FIFO is a special file and test get stuck at this file + # Notes: only test for normal files. File /etc/cron.d/FIFO on solaris is a special file and test may hang + # Linux systems may have a .placeholder file FOUND_IN_CRON=0 # Check cron jobs for I in ${CRON_DIRS}; do - if [ -d ${I} ]; then - if FileIsReadable ${I}; then - FIND=$(${LSBINARY} ${I} | ${GREPBINARY} -v FIFO) + for J in "${I}"/*; do # iterate over folders in a safe way + # Check: regular file, readable and not called .placeholder + FIND=$(echo "${J}" | ${EGREPBINARY} '/.placeholder$') + if [ -f "${J}" ] && [ -r "${J}" ] && [ -z "${FIND}" ]; then + LogText "Test: checking for ntpdate, rdate, sntp or ntpdig in ${J}" + FIND=$("${EGREPBINARY}" "${CRONTAB_REGEX}" "${J}" | "${GREPBINARY}" -v "^#") if [ -n "${FIND}" ]; then - for J in ${FIND}; do - LogText "Test: checking for ntpdate or rdate in ${I}/${J}" - FIND2=$(${EGREPBINARY} "rdate|ntpdate" ${I}/${J} | ${GREPBINARY} -v "^#") - if [ -n "${FIND2}" ]; then - LogText "Positive match found: ${FIND2}" - FOUND=1; FOUND_IN_CRON=1; NTP_CONFIG_TYPE_SCHEDULED=1 - fi - done - else - LogText "Result: ${I} is empty, skipping search in directory" + FOUND=1; FOUND_IN_CRON=1; NTP_CONFIG_TYPE_SCHEDULED=1 + LogText "Result: found ntpdate, rdate, sntp or ntpdig in ${J}" fi - else - LogText "Result: could not search in directory due to permissions" fi - fi + done done if [ ${FOUND_IN_CRON} -eq 1 ]; then @@ -476,7 +488,8 @@ # Other should preferably have no access, or read-only at max FILE_ARRAY="${ROOTDIR}etc/chrony.conf ${ROOTDIR}usr/pkg/etc/chrony.conf \ - ${ROOTDIR}etc/inet/ntp.conf ${ROOTDIR}etc/ntp.conf ${ROOTDIR}usr/local/etc/ntp.conf" + ${ROOTDIR}etc/inet/ntp.conf ${ROOTDIR}etc/ntp.conf ${ROOTDIR}usr/local/etc/ntp.conf\ + ${ROOTDIR}etc/ntpd.conf ${ROOTDIR}etc/openntpd/ntpd.conf ${ROOTDIR}usr/local/etc/ntpd.conf" Register --test-no TIME-3170 --weight L --network NO --category security --description "Check configuration files" if [ ${SKIPTEST} -eq 0 ]; then @@ -494,6 +507,106 @@ # ################################################################################# # + # Test : TIME-3180 + # Description : Report if ntpctl cannot communicate with OpenNTPD + if [ "${NTP_DAEMON_RUNNING}" -eq 1 ] && [ -n "${NTPCTLBINARY}" ] && [ "${NTP_DAEMON}" = "openntpd" ]; then + PREQS_MET="YES" + else + PREQS_MET="NO" + fi + Register --test-no TIME-3180 --preqs-met "${PREQS_MET}" --weight L --network NO --category security --description "Report if ntpctl cannot communicate with OpenNTPD" + if [ ${SKIPTEST} -eq 0 ]; then + if [ "${OPENNTPD_COMMUNICATION}" -eq 0 ]; then + ReportWarning "${TEST_NO}" "OpenNTPD found, but ntpctl cannot communicate with" "${NTPCTLBINARY} -s status" "Restart OpenNTPD" + fi + fi +# +################################################################################# +# + # Test : TIME-3181 + # Description : Check status of OpenNTPD time synchronisation + if [ "${NTP_DAEMON_RUNNING}" -eq 1 ] && [ -n "${NTPCTLBINARY}" ] && [ "${NTP_DAEMON}" = "openntpd" ] && [ "${OPENNTPD_COMMUNICATION}" -eq 1 ]; then + PREQS_MET="YES" + else + PREQS_MET="NO" + fi + + Register --test-no TIME-3181 --preqs-met "${PREQS_MET}" --weight L --network NO --category security --description "Check status of OpenNTPD time synchronisation" + if [ ${SKIPTEST} -eq 0 ]; then + FIND=$(${NTPCTLBINARY} -s status | ${GREPBINARY} "clock synced" ) + if [ -z "${FIND}" ]; then + ReportWarning "${TEST_NO}" "OpenNTPD is not synchronising system time" "${NTPCTLBINARY} -s status" "text:Set time manually once or check network connectivity." + fi + fi +# +################################################################################# +# + # Test : TIME-3182 + # Description : Check OpenNTPD has working peers + + if [ "${NTP_DAEMON_RUNNING}" -eq 1 ] && [ -n "${NTPCTLBINARY}" ] && [ "${NTP_DAEMON}" = "openntpd" ] && [ "${OPENNTPD_COMMUNICATION}" -eq 1 ]; then + PREQS_MET="YES" + else + PREQS_MET="NO" + fi + + Register --test-no TIME-3182 --preqs-met "${PREQS_MET}" --weight L --network NO --category security --description "Check OpenNTPD has working peers" + if [ ${SKIPTEST} -eq 0 ]; then + # Format is "xx/yy peers valid, ..." + FIND=$(${NTPCTLBINARY} -s status | ${EGREPBINARY} -o '[0-9]+/[0-9]+' | ${CUTBINARY} -d '/' -f 1) + if [ -z "${FIND}" ] || [ "${FIND}" -eq 0 ]; then + ReportWarning "${TEST_NO}" "OpenNTPD has no peers" "${NTPCTLBINARY} -s status" + fi + fi + +# +################################################################################# +# + + # Test : TIME-3185 + # Description : Check systemd-timesyncd synchronized time + + if [ "${NTP_DAEMON}" = "systemd-timesyncd" ]; then + PREQS_MET="YES" + else + PREQS_MET="NO" + fi + + + Register --test-no TIME-3185 --preqs-met "${PREQS_MET}" --weight L --network NO --category "security" --description "Check systemd-timesyncd synchronized time" + SYNCHRONIZED_FILE="/run/systemd/timesync/synchronized" + + if [ ${SKIPTEST} -eq 0 ]; then + # On earlier systemd versions (237), '/run/systemd/timesync/synchronized' does not exist, so use '/var/lib/systemd/timesync/clock' + if [ ! -e "${SYNCHRONIZED_FILE}" ]; then + SYNCHRONIZED_FILE="/var/lib/systemd/timesync/clock" + fi + # DynamicUser=yes moves the clock file to '/var/lib/private/systemd/timesync/clock' + if [ ! -e "${SYNCHRONIZED_FILE}" ]; then + SYNCHRONIZED_FILE="/var/lib/private/systemd/timesync/clock" + fi + if [ -e "${SYNCHRONIZED_FILE}" ]; then + FIND=$(( $(date +%s) - $(${STATBINARY} -L --format %Y "${SYNCHRONIZED_FILE}") )) + # Check if last sync was more than 2048 seconds (= the default of systemd) ago + if [ "${FIND}" -ge 2048 ]; then + COLOR=RED + ReportWarning "${TEST_NO}" "systemd-timesyncd did not synchronized the time recently." + else + COLOR=GREEN + fi + Display --indent 2 --text "- Last time synchronization" --result "${FIND}s" --color "${COLOR}" + LogText "Result: systemd-timesyncd synchronized time ${FIND} seconds ago." + else + Display --indent 2 --text "- Last time synchronization" --result "${STATUS_NOT_FOUND}" --color RED + ReportWarning "${TEST_NO}" "systemd-timesyncd never successfully synchronized time" + fi + fi + unset SYNCHRONIZED_FILE + +# +################################################################################# +# + Report "ntp_config_found=${NTP_CONFIG_FOUND}" Report "ntp_config_type_daemon=${NTP_CONFIG_TYPE_DAEMON}" Report "ntp_config_type_eventbased=${NTP_CONFIG_TYPE_EVENTBASED}" diff --git a/include/tests_tooling b/include/tests_tooling index 00c37369..15475c61 100644 --- a/include/tests_tooling +++ b/include/tests_tooling @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -37,7 +37,7 @@ # ################################################################################# # - InsertSection "Software: System tooling" + InsertSection "${SECTION_SYSTEM_TOOLING}" # ################################################################################# # @@ -373,6 +373,33 @@ # ################################################################################# # + # Test : TOOL-5130 + # Description : Check for Suricata + Register --test-no TOOL-5130 --weight L --network NO --category security --description "Check for active Suricata daemon" + if [ ${SKIPTEST} -eq 0 ]; then + # Suricata presence + if [ -n "${SURICATABINARY}" ]; then + Report "ids_ips_tooling[]=suricata" + LogText "Result: Suricata is installed (${SURICATABINARY})" + # Suricata status + # Suricata sets its process name to Suricata-Main on Linux, but this might differ on other platforms, + # so fall back to checking the full commandline instead if the first test fails + if IsRunning "Suricata-Main" || IsRunning --full "${SURICATABINARY} "; then + # Only satisfy test TOOL-5190 if Suricata is actually running + IDS_IPS_TOOL_FOUND=1 + LogText "Result: Suricata daemon is active" + Display --indent 2 --text "- Checking Suricata status" --result "${STATUS_RUNNING}" --color GREEN + else + LogText "Result: Suricata daemon not active" + Display --indent 2 --text "- Checking Suricata status" --result "${STATUS_NOT_RUNNING}" --color YELLOW + fi + else + LogText "Result: Suricata not installed (suricata not found)" + fi + fi +# +################################################################################# +# # Test : TOOL-5160 # Description : Check for OSSEC Register --test-no TOOL-5126 --weight L --network NO --category security --description "Check for active OSSEC daemon" diff --git a/include/tests_usb b/include/tests_usb index 24c74982..d99d5a66 100644 --- a/include/tests_usb +++ b/include/tests_usb @@ -19,7 +19,7 @@ # ################################################################################# # - InsertSection "USB Devices" + InsertSection "${SECTION_USB_DEVICES}" # ################################################################################# # @@ -73,7 +73,7 @@ fi if [ ${FOUND} -eq 0 ]; then LogText "Result: usb-storage driver is not explicitly disabled" - Display --indent 2 --text "- Checking usb-storage driver (modprobe config)" --result "NOT DISABLED" --color WHITE + Display --indent 2 --text "- Checking usb-storage driver (modprobe config)" --result "${STATUS_NOT_DISABLED}" --color WHITE if [ "${USBGUARD_FOUND}" -eq "0" ]; then ReportSuggestion "${TEST_NO}" "Disable drivers like USB storage when not used, to prevent unauthorized storage or data theft" fi @@ -91,39 +91,46 @@ # Description : Check USB authorizations Register --test-no USB-2000 --os Linux --weight L --network NO --category security --description "Check USB authorizations" if [ ${SKIPTEST} -eq 0 ]; then - LogText "Test: Checking USB devices authorization to connect to the system" FOUND=0 - USBDEVICESPATH="${ROOTDIR}sys/bus/usb/devices/usb" - for device in "${USBDEVICESPATH}"*; do - if [ -e "${device}/authorized" -o -e "${device}/authorized_default" ]; then - if [ "$(cat "${device}/authorized_default")" = "1" ]; then - FOUND=1 - LogText "Test: ${device} is authorized by default" + USBDEVICESPATH="${ROOTDIR}sys/bus/usb/devices" + LogText "Test: checking presence of USB devices path (${USBDEVICESPATH})" + if [ -d "${USBDEVICESPATH}" ]; then + + LogText "Test: Checking USB devices authorization to connect to the system" + for device in $(find ${USBDEVICESPATH} -name "usb*" -type l -print); do + if [ -e "${device}/authorized" -o -e "${device}/authorized_default" ]; then + if [ "$(cat "${device}/authorized_default")" = "1" ]; then + FOUND=1 + LogText "Test: ${device} is authorized by default (authorized_default=1)" + Report "usb_authorized_default_device[]=${device}" + fi + if [ "$(cat "${device}/authorized")" = "1" ]; then + FOUND=1 + LogText "Test: ${device} is authorized currently (authorized=1)" + Report "usb_authorized_device[]=${device}" + fi + else + LogText "Test: no authorized or authorized_default file, assuming ${device} is authorized by default" Report "usb_authorized_default_device[]=${device}" - elif [ "$(cat "${device}/authorized")" = "1" ]; then FOUND=1 - LogText "Test: ${device} is authorized currently" - Report "usb_authorized_device[]=${device}" fi + done + + if [ ${FOUND} -eq 1 ]; then + LogText "Result: Some USB devices are authorized by default (or temporary) to connect to the system" + Display --indent 2 --text "- Checking USB devices authorization" --result "${STATUS_ENABLED}" --color YELLOW + # TODO: create documentation and enable the suggestion + #if [ ${USBGUARD_FOUND} -eq 0 ]; then + # ReportSuggestion "${TEST_NO}" "Disable USB devices authorization, to prevent unauthorized storage or data theft" + #fi + AddHP 0 3 else - LogText "Test: ${device} is authorized by default" - Report "usb_authorized_default_device[]=${device}" - FOUND=1 + LogText "Result: None USB devices are authorized by default (or temporary) to connect to the system" + Display --indent 2 --text "- Checking USB devices authorization" --result "${STATUS_DISABLED}" --color GREEN + AddHP 3 3 fi - done - - if [ ${FOUND} -eq 1 ]; then - LogText "Result: Some USB devices are authorized by default (or temporary) to connect to the system" - Display --indent 2 --text "- Checking USB devices authorization" --result "${STATUS_ENABLED}" --color YELLOW - # To-Be-Added: create documentation and enable the suggestion - #if [ ${USBGUARD_FOUND} -eq 0 ]; then - # ReportSuggestion "${TEST_NO}" "Disable USB devices authorization, to prevent unauthorized storage or data theft" - #fi - AddHP 0 3 else - LogText "Result: None USB devices are authorized by default (or temporary) to connect to the system" - Display --indent 2 --text "- Checking USB devices authorization" --result "${STATUS_DISABLED}" --color GREEN - AddHP 3 3 + LogText "Result: devices path does not exist" fi fi diff --git a/include/tests_virtualization b/include/tests_virtualization index 825eefeb..e4df170e 100644 --- a/include/tests_virtualization +++ b/include/tests_virtualization @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -22,7 +22,7 @@ # ################################################################################# # - InsertSection "Virtualization" + InsertSection "${SECTION_VIRTUALIZATION}" # ################################################################################# # diff --git a/include/tests_webservers b/include/tests_webservers index 54db20d7..45588492 100644 --- a/include/tests_webservers +++ b/include/tests_webservers @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com @@ -22,7 +22,7 @@ # ################################################################################# # - InsertSection "Software: webserver" + InsertSection "${SECTION_WEBSERVER}" # ################################################################################# # diff --git a/include/tool_tips b/include/tool_tips index 4f2f3b6e..6ff7534e 100644 --- a/include/tool_tips +++ b/include/tool_tips @@ -6,7 +6,7 @@ # ------------------ # # Copyright 2007-2013, Michael Boelen -# Copyright 2007-2019, CISOfy +# Copyright 2007-2020, CISOfy # # Website : https://cisofy.com # Blog : http://linux-audit.com |