Originally published February 29, 2020 @ 5:04 pm
Lynis is an excellent security audit tool for Linux and various Unix derivatives. I have a small wrapper script that runs Lynis via a cron job, does a selective diff with the previous run’s output, and sends me an email.
Unfortunately, Lynis does not update itself automatically and this is the sort of application that needs to be up-to-date. I installed mine via a tarball – the most common and recommended way for this utility – and so it does not update when I patch the system.
Here is a, perhaps, unnecessarily convoluted script that checks the version of Lynis and updates it, if required. In a nutshell, all this script does is download the most recent version of Lynis and overwrites the existing version on your machine.
But there are a lot of checks in the background designed to detect a variety of issues. When writing this sort of scripts I try to hard-code as little as possible. Primarily, because the folks maintaining such online resources usually have little regard for automation and can make silly changes to names and URLs without notice.
The script is below for your review. If you’re going to use it, I suggest downloading it from my GitHub repo to avoid any copy-paste weirdness.
#!/bin/bash
#
# |
# ___/"\___
# __________/ o \__________
# (I) (G) \___/ (O) (R)
# Igor Os
# igor@comradegeneral.com
# 2020-02-29
# ----------------------------------------------------------------------------
# Update current installation of Lynis. Only use this script if Lynis was
# installed via a tarball. If you have a version installed via RPM or another
# package managements tool, uninstall it first.
# ----------------------------------------------------------------------------
configure() {
echo "Running script configuration"
# Specify Lynis executable
LYNIS=/usr/bin/lynis
[ -x "${LYNIS}" ] || (echo "Lynis executable ${LYNIS} not found. Exiting..." && exit 1110)
this_script=$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")
# Get update info
echo "Getting update info"
update_info="$(${LYNIS} update info)"
[ -z "${update_info}" ] && (echo "Unable to get update info. Exiting..." && exit 1120)
# Parse update info
echo "Parsing update info"
update_status="$(echo "${update_info}" | grep -E '^\s+Status' | awk '{print $NF}')"
release_date="$(echo "${update_info}" | grep -E '^\s+Release' | awk '{print $NF}')"
current_version="$(echo "${update_info}" | grep -E '^\s+Version' | awk '{print $NF}')"
update_location="$(echo "${update_info}" | grep -E '^\s+Update location' | awk '{print $NF}' | sed 's/\/$//g')"
update_host="$(echo "${update_location}" | grep -oP "(?<=:\/\/).*?(?=\/)")"
([ -z "${update_status}" ] || [ -z "${current_version}" ] || \
[ -z "${release_date}" ] || [ -z "${update_location}" ] || [ -z "${update_host}" ]) && \
(echo "Unable to parse update info. Exiting..." && exit 1130)
# Resolve update host
echo "Resolving update host"
update_host_ip="$(dig +short "${update_host}" | \
grep -m1 -oE "([0-9]{1,3}\.){3}([0-9]{1,3})")"
[ -z "${update_host_ip}" ] && \
(echo "Unable to resolve ${update_host}. Exiting..." && exit 1135)
# Verify update host port access
echo "Verifying update host port access"
nc -v -i1 -w1 "${update_host_ip}" 443 2>/dev/null 1>&2 || \
(echo "Unable to access ${update_host_ip}:443. Exiting..." && exit 1137)
# Verify access to update URL
echo "Verifying update location availability"
if [ ! $(curl -s0SfkL "${update_location}" 2>/dev/null | \
grep -oP "(?<=\<title\>).*?(?=\<\/title\>)" 2>/dev/null | \
grep -c Lynis) -gt 0 ]
then
echo "Unable to reach ${update_location}. Exiting..."
exit 1140
fi
# Determine download URL
echo "Checking for download URL"
base_url="$(awk -F'/' '{print $1"/"$2"/"$3}' <<<"${update_location}")"
path_url="$(curl -s0SfkL "${update_location}" 2>/dev/null | awk 'BEGIN{
RS="</a>"
IGNORECASE=1
}
{
for(o=1;o<=NF;o++){
if ( $o ~ /href/){
gsub(/.*href=2/,"",$o)
gsub(/2.*/,"",$o)
print $(o)
}
}
}' | grep -m1 -iE "(lynis.*downloads)|(downloads.*lynis)")"
[ -z "${path_url}" ] && (echo "Unable to determine download URL. Exiting..." && exit 1150)
download_url="${base_url}/${path_url}"
# Determine latest version download URL
echo "Checking for the latest version download link"
version_url="$(curl -s0SfkL "${download_url}" 2>/dev/null | awk 'BEGIN{
RS="</a>"
IGNORECASE=1
}
{
for(o=1;o<=NF;o++){
if ( $o ~ /href/){
gsub(/.*href=2/,"",$o)
gsub(/2.*/,"",$o)
print $(o)
}
}
}' | grep -m1 -iE "lynis.*\.(tar\.gz|tgz)")"
[ -z "${version_url}" ] && (echo "Unable to determine latest version download link. Exiting..." && exit 1150)
version_file="$(echo "${version_url}" | awk -F'/' '{print $NF}')"
}
lynis_update() {
# Check if update is needed
if [ "${update_status}" == "Outdated" ]
then
echo "Update is required."
# Download the latest version
echo "Downloading ${version_file}"
curl -s0SfkL "${version_url}" > ~/"${version_file}"
[ $(file --mime-type ~/"${version_file}" -F$'\t' | awk -F'\t *' '$2 ~/^application\/x-gzip/ { print $1 }') ] || \
(echo "Unable to download ${version_url}. Exiting..." && exit 1160)
# Uncompress the latest version
echo "Uncompressing ~/${version_file}"
[ -d ~/lynis ] && /bin/mv ~/lynis ~/lynis_$(date +'%Y-%m-%d_%H%M') 2>/dev/null
cd ~ && tar xfz ~/"${version_file}" || (echo "Unable to uncompress ~/${version_file}. Exiting..." && exit 1170)
[ -d /usr/local/lynis ] && cd /usr/local && tar cfz ~/lynis_previous_$(date +'%Y-%m-%d_%H%M').tar.gz lynis && \
/bin/rm -rf lynis && cd ~
/bin/mv -f ~/lynis /usr/local/ && ln -s /usr/local/lynis/lynis ${LYNIS} 2>/dev/null
/bin/rm ~/"${version_file}" 2>/dev/null
${LYNIS} update info
echo "Update complete"
else
echo "Update is not required at this time. Exiting"
exit 0
fi
}
# ----------------------------------------------------------------------------
# RUNTIME
# \(^_^)/ __|__
# __|__ *---o0o---*
# __|__ *---o0o---*
# *---o0o---*
# ----------------------------------------------------------------------------
configure
lynis_update

Experienced Unix/Linux System Administrator with 20-year background in Systems Analysis, Problem Resolution and Engineering Application Support in a large distributed Unix and Windows server environment. Strong problem determination skills. Good knowledge of networking, remote diagnostic techniques, firewalls and network security. Extensive experience with engineering application and database servers, high-availability systems, high-performance computing clusters, and process automation.























