#!/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 http://nbi.fr/, Inspiration of the moment 10/10/2007 * Olivier Mehani , 2016 * Wilco de Boer , 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