2015-01-30 13:13:38 +01:00
|
|
|
#!/bin/sh
|
|
|
|
|
2016-03-13 16:00:39 +01:00
|
|
|
#################################################################################
|
|
|
|
#
|
|
|
|
# Lynis
|
|
|
|
# ------------------
|
|
|
|
#
|
|
|
|
# Copyright 2007-2013, Michael Boelen
|
2020-03-20 14:50:25 +01:00
|
|
|
# Copyright 2007-2020, CISOfy
|
2016-03-13 16:00:39 +01:00
|
|
|
#
|
|
|
|
# Website : https://cisofy.com
|
|
|
|
# Blog : http://linux-audit.com
|
|
|
|
# GitHub : https://github.com/CISOfy/lynis
|
|
|
|
#
|
|
|
|
# Lynis comes with ABSOLUTELY NO WARRANTY. This is free software, and you are
|
|
|
|
# welcome to redistribute it under the terms of the GNU General Public License.
|
|
|
|
# See LICENSE file for usage of this software.
|
|
|
|
#
|
|
|
|
#################################################################################
|
|
|
|
|
2015-01-30 13:13:38 +01:00
|
|
|
if [ $# -eq 0 ]; then
|
2019-06-24 15:23:30 +02:00
|
|
|
Display --indent 2 --text "${RED}Error: ${WHITE}Provide a file${NORMAL}"
|
2015-01-30 13:13:38 +01:00
|
|
|
Display --text " "; Display --text " "
|
|
|
|
ExitFatal
|
2017-04-30 17:59:35 +02:00
|
|
|
else
|
2019-09-19 14:05:15 +02:00
|
|
|
FILE=$(echo $1 | grep -E "^http|https")
|
2017-04-30 17:59:35 +02:00
|
|
|
if HasData "${FILE}"; then
|
2019-06-24 15:23:30 +02:00
|
|
|
echo "Provide a file (not a URL)"
|
|
|
|
ExitFatal
|
2017-04-30 17:59:35 +02:00
|
|
|
else
|
2015-01-30 13:13:38 +01:00
|
|
|
if [ -f $1 ]; then
|
|
|
|
AUDIT_FILE="$1"
|
2017-04-30 17:59:35 +02:00
|
|
|
else
|
2015-01-30 13:13:38 +01:00
|
|
|
Display --indent 2 --text "File $1 does not exist"
|
|
|
|
ExitFatal
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
Display --indent 2 --text "File to audit = ${AUDIT_FILE}"
|
|
|
|
fi
|
|
|
|
|
|
|
|
#####################################################
|
|
|
|
|
|
|
|
#
|
|
|
|
##################################################################################################
|
|
|
|
#
|
|
|
|
|
2020-10-22 00:13:42 +02:00
|
|
|
InsertSection "${SECTION_IMAGE}"
|
2015-01-30 13:13:38 +01:00
|
|
|
|
|
|
|
PKGMGR=""
|
2017-03-06 08:41:21 +01:00
|
|
|
FIND=$(grep "^FROM" ${AUDIT_FILE} | sed 's/ /:space:/g')
|
2015-01-30 13:13:38 +01:00
|
|
|
for I in ${FIND}; do
|
2017-03-06 08:41:21 +01:00
|
|
|
IMAGE=$(echo ${I} | sed 's/:space:/ /g' | awk '{ if ($1=="FROM") { print $2 }}')
|
2018-08-28 08:45:04 +02:00
|
|
|
TAG=$(echo ${IMAGE} | cut -d':' -f2)
|
2015-01-30 13:13:38 +01:00
|
|
|
Display --indent 2 --text "Found image:" --result "${IMAGE}"
|
|
|
|
|
2018-08-15 13:47:17 +02:00
|
|
|
IS_DEBIAN=$(echo ${IMAGE} | grep -i debian)
|
|
|
|
IS_FEDORA=$(echo ${IMAGE} | grep -i fedora)
|
2017-03-06 08:41:21 +01:00
|
|
|
IS_UBUNTU=$(echo ${IMAGE} | grep -i ubuntu)
|
2018-08-15 13:47:17 +02:00
|
|
|
IS_ALPINE=$(echo ${IMAGE} | grep -i alpine)
|
2018-08-28 08:45:04 +02:00
|
|
|
IS_LATEST=$(echo ${TAG} | grep -i latest)
|
2018-08-15 13:47:17 +02:00
|
|
|
|
2019-07-16 13:20:30 +02:00
|
|
|
if [ -n "${IS_DEBIAN}" ]; then IMAGE="debian"; fi
|
|
|
|
if [ -n "${IS_FEDORA}" ]; then IMAGE="fedora"; fi
|
|
|
|
if [ -n "${IS_UBUNTU}" ]; then IMAGE="ubuntu"; fi
|
|
|
|
if [ -n "${IS_ALPINE}" ]; then IMAGE="alpine"; fi
|
|
|
|
if [ -n "${IS_LATEST}" ]; then
|
2019-06-24 15:40:38 +02:00
|
|
|
ReportWarning "dockerfile" "latest TAG used. Specifying a targeted OS image and version is better for reproducible results."
|
2018-08-28 08:45:04 +02:00
|
|
|
fi
|
2015-01-30 13:13:38 +01:00
|
|
|
|
|
|
|
case ${IMAGE} in
|
|
|
|
"debian")
|
2016-04-28 09:15:54 +02:00
|
|
|
LogText "Image = Debian based"
|
2015-01-30 13:13:38 +01:00
|
|
|
PKGMGR="apt"
|
|
|
|
;;
|
|
|
|
"fedora*")
|
2016-04-28 09:15:54 +02:00
|
|
|
LogText " Image = Fedora based"
|
2015-01-30 13:13:38 +01:00
|
|
|
PKGMGR="yum"
|
|
|
|
;;
|
|
|
|
"ubuntu")
|
2016-04-28 09:15:54 +02:00
|
|
|
LogText " Image = Ubuntu based"
|
2015-01-30 13:13:38 +01:00
|
|
|
PKGMGR="apt"
|
|
|
|
;;
|
2018-08-15 13:47:17 +02:00
|
|
|
"alpine")
|
|
|
|
LogText " Image = Alpine based"
|
|
|
|
PKGMGR="apk"
|
|
|
|
;;
|
2015-01-30 13:13:38 +01:00
|
|
|
*)
|
|
|
|
Display --indent 2 --text "Unknown image" --result "" --color YELLOW
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
|
|
|
|
#
|
|
|
|
##################################################################################################
|
|
|
|
#
|
2020-10-22 00:13:42 +02:00
|
|
|
InsertSection "${SECTION_BASICS}"
|
2015-01-30 13:13:38 +01:00
|
|
|
|
2019-09-19 14:05:15 +02:00
|
|
|
MAINTAINER=$(grep -E -i "*MAINTAINER" ${AUDIT_FILE} | sed 's/=/ /g' | cut -d'"' -f 2)
|
|
|
|
if [ -z "${MAINTAINER}" ]; then
|
2016-08-10 07:24:10 +02:00
|
|
|
ReportWarning "dockerfile" "No maintainer found. Unclear who created this file."
|
2017-04-30 17:59:35 +02:00
|
|
|
else
|
2015-01-30 13:13:38 +01:00
|
|
|
Display --indent 2 --text "Maintainer" --result "${MAINTAINER}"
|
|
|
|
fi
|
2019-06-24 15:23:30 +02:00
|
|
|
|
2019-09-19 14:05:15 +02:00
|
|
|
ENTRYPOINT=$(grep "^ENTRYPOINT" ${AUDIT_FILE} | cut -d' ' -f2 )
|
|
|
|
if [ -z "${ENTRYPOINT}" ]; then
|
2018-08-15 13:54:56 +02:00
|
|
|
ReportWarning "dockerfile" "No ENTRYPOINT defined in Dockerfile."
|
|
|
|
else
|
|
|
|
Display --indent 2 --text "ENTRYPOINT" --result "${ENTRYPOINT}"
|
|
|
|
fi
|
|
|
|
|
|
|
|
FIND=$(grep "^CMD" ${AUDIT_FILE} | cut -d' ' -f2 )
|
2019-06-24 15:23:30 +02:00
|
|
|
if [ -z "${FIND}" ]; then
|
2018-08-15 13:54:56 +02:00
|
|
|
ReportWarning "dockerfile" "No CMD defines in Dockerfile."
|
|
|
|
else
|
|
|
|
CMD=$(echo ${FIND})
|
|
|
|
Display --indent 2 --text "CMD" --result "${CMD}"
|
|
|
|
fi
|
|
|
|
|
|
|
|
FIND=$(grep "^USER" ${AUDIT_FILE} | cut -d' ' -f2 )
|
2019-06-24 15:23:30 +02:00
|
|
|
if [ -z "${FIND}" ]; then
|
2018-10-05 10:19:23 +02:00
|
|
|
ReportWarning "dockerfile" "No user declared in Dockerfile. Container will execute command as root"
|
2018-08-15 13:54:56 +02:00
|
|
|
else
|
|
|
|
USER=$(echo ${FIND})
|
|
|
|
Display --indent 2 --text "User" --result "${USER}"
|
|
|
|
fi
|
2015-01-30 13:13:38 +01:00
|
|
|
#
|
|
|
|
##################################################################################################
|
|
|
|
#
|
2020-10-22 00:13:42 +02:00
|
|
|
InsertSection "${SECTION_SOFTWARE}"
|
2015-01-30 13:13:38 +01:00
|
|
|
|
|
|
|
case $PKGMGR in
|
|
|
|
"apt")
|
2019-09-19 14:05:15 +02:00
|
|
|
FIND=$(grep -E "apt-get(.*) install" ${AUDIT_FILE})
|
2015-01-30 13:13:38 +01:00
|
|
|
if [ ! "${FIND}" = "" ]; then
|
2016-04-28 09:15:54 +02:00
|
|
|
LogText "Found installation via apt-get"
|
2017-04-30 17:59:35 +02:00
|
|
|
else
|
2016-04-28 09:15:54 +02:00
|
|
|
LogText "No installations found via apt-get"
|
2015-01-30 13:13:38 +01:00
|
|
|
fi
|
|
|
|
;;
|
2018-08-15 13:47:17 +02:00
|
|
|
"apk")
|
2019-09-19 14:05:15 +02:00
|
|
|
FIND=$(grep -E "apk(.*) add" ${AUDIT_FILE})
|
2018-08-15 13:47:17 +02:00
|
|
|
if [ ! "${FIND}" = "" ]; then
|
|
|
|
LogText "Found installation via apk"
|
|
|
|
else
|
|
|
|
LogText "No installations found via apk"
|
|
|
|
fi
|
|
|
|
;;
|
2015-01-30 13:13:38 +01:00
|
|
|
*)
|
2016-04-28 09:15:54 +02:00
|
|
|
LogText "Unknown package manager"
|
2015-01-30 13:13:38 +01:00
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
2019-09-19 14:05:15 +02:00
|
|
|
FIND=$(grep -E " (gcc|libc6-dev|make)" ${AUDIT_FILE} | grep -v "^#")
|
2015-01-30 13:13:38 +01:00
|
|
|
if [ ! "${FIND}" = "" ]; then
|
2016-08-10 07:24:10 +02:00
|
|
|
ReportWarning "dockerfile" "Possible development utilities found, which is not advised for production environment"
|
2016-04-28 09:15:54 +02:00
|
|
|
LogText "Details: ${FIND}"
|
2015-01-30 13:13:38 +01:00
|
|
|
fi
|
|
|
|
|
|
|
|
# SSH
|
2017-03-06 08:41:21 +01:00
|
|
|
FIND_OPENSSH=$(grep openssh ${AUDIT_FILE})
|
2015-01-30 13:13:38 +01:00
|
|
|
if [ ! "${FIND_OPENSSH}" = "" ]; then
|
|
|
|
Display --indent 2 --text "OpenSSH" --result "FOUND" --color RED
|
|
|
|
ReportSuggestion "dockerfile" "Don't use OpenSSH in container, use 'docker exec' instead"
|
|
|
|
fi
|
|
|
|
#
|
|
|
|
##################################################################################################
|
|
|
|
#
|
2020-10-22 00:13:42 +02:00
|
|
|
InsertSection "${SECTION_DOWNLOADS}"
|
2015-01-30 13:13:38 +01:00
|
|
|
|
|
|
|
FILE_DOWNLOAD=0
|
|
|
|
|
2016-04-28 09:15:54 +02:00
|
|
|
LogText "Checking usage of cURL"
|
2017-03-06 08:41:21 +01:00
|
|
|
FIND_CURL=$(grep curl ${AUDIT_FILE})
|
2016-03-03 12:50:43 +01:00
|
|
|
if [ ! "${FIND_CURL}" = "" ]; then
|
2015-01-30 13:13:38 +01:00
|
|
|
Display --indent 4 --text "Download tool" --result "curl"
|
|
|
|
FILE_DOWNLOAD=1
|
|
|
|
fi
|
|
|
|
|
2016-04-28 09:15:54 +02:00
|
|
|
LogText "Checking usage of wget"
|
2017-03-06 08:41:21 +01:00
|
|
|
FIND_WGET=$(grep wget ${AUDIT_FILE})
|
2017-04-30 17:59:35 +02:00
|
|
|
if HasData "${FIND_WGET}"; then
|
2015-01-30 13:13:38 +01:00
|
|
|
Display --indent 4 --text "Download tool" --result "wget"
|
|
|
|
FILE_DOWNLOAD=1
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
2017-03-06 08:41:21 +01:00
|
|
|
FIND=$(grep "^ADD http" ${AUDIT_FILE})
|
2017-04-30 17:59:35 +02:00
|
|
|
if HasData "${FIND}"; then
|
2015-01-30 13:13:38 +01:00
|
|
|
FILE_DOWNLOAD=1
|
2016-08-10 07:24:10 +02:00
|
|
|
ReportWarning "dockerfile" "Found download of file via ADD. Unclear if the integrity of this file is checked, or file is signed"
|
2016-04-28 09:15:54 +02:00
|
|
|
LogText "Details: ${FIND}"
|
2015-01-30 13:13:38 +01:00
|
|
|
fi
|
|
|
|
|
|
|
|
if [ ${FILE_DOWNLOAD} -eq 1 ]; then
|
|
|
|
|
2019-09-19 14:05:15 +02:00
|
|
|
SSL_USED_FIND=$(grep -E "(https)" ${AUDIT_FILE})
|
2015-01-30 13:13:38 +01:00
|
|
|
|
2017-04-30 17:59:35 +02:00
|
|
|
if HasData "${SSL_USED_FIND}"; then
|
2015-01-30 13:13:38 +01:00
|
|
|
SSL_USED="YES"
|
|
|
|
COLOR="GREEN"
|
2017-04-30 17:59:35 +02:00
|
|
|
else
|
2015-01-30 13:13:38 +01:00
|
|
|
SSL_USED="NO"
|
|
|
|
COLOR="RED"
|
|
|
|
ReportSuggestion "Use SSL downloads when possible to increase security (DNSSEC, HTTPS, validation of domain, avoid MitM)"
|
|
|
|
fi
|
|
|
|
Display --indent 2 --text "Integrity testing performed" --result "${SSL_USED}" --color ${COLOR}
|
2019-09-19 14:05:15 +02:00
|
|
|
HASHING_USED=$(grep -E "(sha1sum|sha256sum|sha512sum)" ${AUDIT_FILE})
|
2015-01-30 13:13:38 +01:00
|
|
|
Display --indent 2 --text "Hashing" --result "${HASHING_USED}"
|
2019-09-19 14:05:15 +02:00
|
|
|
KEYS_USED=$(grep -E "(apt-key adv)" ${AUDIT_FILE}| sed 's/RUN apt-key adv//g'| sed 's/--keyserver/Key Server:/g' | sed 's/--recv/Key Value:/g')
|
2018-08-15 13:56:56 +02:00
|
|
|
Display --indent 2 --text "Signing keys used" --result "${KEYS_USED}"
|
2015-01-30 13:13:38 +01:00
|
|
|
Display --indent 2 --text "All downloads properly checked" --result "?"
|
2017-04-30 17:59:35 +02:00
|
|
|
else
|
2015-01-30 13:13:38 +01:00
|
|
|
Display --indent 2 --text "No files seems to be downloaded in this Dockerfile"
|
|
|
|
|
|
|
|
fi
|
|
|
|
#
|
|
|
|
##################################################################################################
|
|
|
|
#
|
2020-10-22 00:13:42 +02:00
|
|
|
InsertSection "${SECTION_PERMISSIONS}"
|
2015-01-30 13:13:38 +01:00
|
|
|
|
2017-03-06 08:41:21 +01:00
|
|
|
FIND=$(grep -i "chmod 777" ${AUDIT_FILE})
|
2017-04-30 17:59:35 +02:00
|
|
|
if HasData "${FIND}"; then
|
2016-08-10 07:24:10 +02:00
|
|
|
ReportWarning "dockerfile" "Warning: chmod 777 found"
|
2015-01-30 13:13:38 +01:00
|
|
|
fi
|
|
|
|
#
|
|
|
|
##################################################################################################
|
|
|
|
#
|
|
|
|
|
2016-04-28 09:15:54 +02:00
|
|
|
# Removing temp file
|
|
|
|
LogText "Action: Removing temporary file ${TMP_FILE}"
|
|
|
|
if [ -f ${TMP_FILE} ]; then
|
|
|
|
rm -f ${TMP_FILE}
|
|
|
|
fi
|
2015-01-30 13:13:38 +01:00
|
|
|
|
|
|
|
|
|
|
|
# The End
|