munin-contrib/plugins/debian/debsecan_

202 lines
6.1 KiB
Bash
Executable File

#!/bin/sh
: << =cut
=head1 NAME
debsecan - Plugin to monitor the number of CVE vulnerabilities present on a Debian-ish
system (using debsecan). This plugin can either report the sum of vulnerabilities present in each packages ('pkg' mode, default), or the number of unique CVEs affecting the system ('cve' mode).
The 'cve' mode is a better indication of the risk level of the system (as
multiple packages with the same vulnerable source get counted repeatedly), but
the 'pkg' provides valuable information to identify packages with high number
of vulnerabilities that should be considered for deletion.
Simply symlink this plugin into your Munin plugins directory as
- debsecan_pkg (the extra_info will list the number of CVE affecting each package)
- debsecan_cve (the extra_info will list the number of packages affected by each CVE)
For backward compatibility, a symlink without a mode will default to 'pkg'.
=head1 CONFIGURATION
The default configuration is as follows.
[debsecan]
env.suite jessie
env.fixed_warning 1
env.fixed_critical 1000
env.remote_warning 1
env.remote_critical 10
The name of the group needs to match the name of the symlink to be applied.
Shell globbing patterns are allowed.
=head1 AUTHORS
* Nicolas BOUTHORS <nbouthors@nbi.fr> http://nbi.fr/, Inspiration of the moment 10/10/2007
* Olivier Mehani <shtrom+munin@ssji.net>, 2016
* Wilco de Boer <deboer.wilco@gmail.com>, 2021
=head1 LICENSE
Public Domain
=head1 MAGIC MARKERS
#%# family=auto
#%# capabilities=autoconf suggest
=cut
# Auto enable if we have debsecan only
if [ "$1" = "autoconf" ]; then
if [ -x /usr/bin/debsecan ]; then
echo yes
else
echo 'no (/usr/bin/debsecan not found)'
fi
exit 0
fi
# Suggest both modes when asked
if [ "$1" = "suggest" ]; then
echo pkg
echo cve
exit 0
fi
# Fail if we don't have debsecan
if [ ! -x /usr/bin/debsecan ]; then
echo 'error: /usr/bin/debsecan not found' >&2
exit 1
fi
# Suite is taken from environment but defaults to `os-release` content
SUITE=$(
. /etc/os-release
echo "${suite:-$VERSION_CODENAME}"
)
FIXEDWARN=${fixed_warning:-1}
FIXEDCRIT=${fixed_critical:-1000}
REMOTEWARN=${remote_warning:-1}
REMOTECRIT=${remote_critical:-10}
MODE=$(echo "$0" | sed 's/.*_//')
case "${MODE}" in
'cve')
TITLE_ADD="unique "
FIELD=1
;;
'pkg' | *)
TITLE_ADD="package "
FIELD=2
;;
esac
if [ "$1" = "config" ]; then
cat <<- EOF
graph_title DebSecan: ${TITLE_ADD}vulnerabilities
graph_info ${TITLE_ADD}vulnerabilities for ${SUITE}
graph_args -l 0 --base 1000
graph_vlabel number of CVE
graph_category system
graph_period second
graph_info This graph show the number of known ${TITLE_ADD}vulnerabilities present on your system. Use debsecan to see details.
remote.label remote
remote.colour FF0000
remote.type GAUGE
remote.draw AREASTACK
remote.min 0
remote.info The number of ${TITLE_ADD}remotely exploitable CVEs with any priority
remote.warning ${REMOTEWARN}
remote.critical ${REMOTECRIT}
high.label high
high.colour DD2200
high.type GAUGE
high.draw AREASTACK
high.min 0
high.info The number of ${TITLE_ADD}CVEs marked high priority
medium.label medium
medium.colour FFAA00
medium.type GAUGE
medium.draw AREASTACK
medium.min 0
medium.info The number of ${TITLE_ADD}CVEs marked medium priority
low.label low
low.colour 0000FF
low.type GAUGE
low.draw AREASTACK
low.min 0
low.info The number of ${TITLE_ADD}CVEs marked low priority
other.label other
other.colour 00AAFF
other.type GAUGE
other.draw AREASTACK
other.min 0
other.info The number of ${TITLE_ADD}CVEs with unspecified priority
fixed.label fixed
fixed.type GAUGE
fixed.draw LINE2
fixed.min 0
fixed.info The number of ${TITLE_ADD}CVEs fixed by available updates
fixed.warning ${FIXEDWARN}
fixed.critical ${FIXEDCRIT}
EOF
exit 0
fi
ALL=$(debsecan --suite "${SUITE}" 2> /dev/null)
REMOTE=$(printf '%s' "$ALL" | grep -w 'remotely')
NONREMOTE=$(printf '%s' "$ALL" | grep -wv 'remotely')
HIGH=$(printf '%s' "${NONREMOTE}" | grep -w 'high urgency')
MEDIUM=$(printf '%s' "${NONREMOTE}" | grep -w 'medium urgency')
LOW=$(printf '%s' "${NONREMOTE}" | grep -w 'low urgency')
OTHER=$(printf '%s' "${NONREMOTE}" | grep -wv 'urgency')
FIXED=$(printf '%s' "${ALL}" | grep -w '(fixed')
# Arguments: Field offset to aggregate by
count_entries() {
CUT_FIELD="${1}"
cut -f "${CUT_FIELD}" -d " " | sort | uniq -c
}
case "${MODE}" in
'cve')
remote_count=$(printf '%s' "${REMOTE}" | count_entries "${FIELD}" | wc -l)
high_count=$(printf '%s' "${HIGH}" | count_entries "${FIELD}" | wc -l)
medium_count=$(printf '%s' "${MEDIUM}" | count_entries "${FIELD}" | wc -l)
low_count=$(printf '%s' "${LOW}" | count_entries "${FIELD}" | wc -l)
other_count=$(printf '%s' "${OTHER}" | count_entries "${FIELD}" | wc -l)
fixed_count=$(printf '%s' "${FIXED}" | count_entries "${FIELD}" | wc -l)
;;
'pkg' | *)
remote_count=$(printf '%s' "${REMOTE}" | wc -l)
high_count=$(printf '%s' "${HIGH}" | wc -l)
medium_count=$(printf '%s' "${MEDIUM}" | wc -l)
low_count=$(printf '%s' "${LOW}" | wc -l)
other_count=$(printf '%s' "${OTHER}" | wc -l)
fixed_count=$(printf '%s' "${FIXED}" | wc -l)
;;
esac
# Reformat the output of the cut|sort|uniq... to a more human-friendly "item (count)" format
CVECOUNTRE='s/^ *\([0-9]\+\) \+\([^ ]\+\)/\2 (\1)/'
cat <<- EOF
remote.value $remote_count
remote.extinfo $(printf '%s' "${REMOTE}" | count_entries "${FIELD}" | sort -nr | sed "${CVECOUNTRE}" | xargs)
high.value $high_count
high.extinfo $(printf '%s' "${HIGH}" | count_entries "${FIELD}" | sort -nr | sed "${CVECOUNTRE}" | xargs)
medium.value $medium_count
medium.extinfo $(printf '%s' "${MEDIUM}" | count_entries "${FIELD}" | sort -nr | sed "${CVECOUNTRE}" | xargs)
low.value $low_count
low.extinfo $(printf '%s' "${LOW}" | count_entries "${FIELD}" | sort -nr | sed "${CVECOUNTRE}" | xargs)
other.value $other_count
other.extinfo $(printf '%s' "${OTHER}" | count_entries "${FIELD}" | sort -nr | sed "${CVECOUNTRE}" | xargs)
fixed.value $fixed_count
fixed.extinfo $(printf '%s' "${FIXED}" | count_entries "${FIELD}" | sort -nr | sed "${CVECOUNTRE}" | xargs)
EOF