1#!/bin/sh 2 3: << =cut 4 5=head1 NAME 6 7debsecan - Plugin to monitor the number of CVE vulnerabilities present on a Debian-ish 8system (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). 9 10The 'cve' mode is a better indication of the risk level of the system (as 11multiple packages with the same vulnerable source get counted repeatedly), but 12the 'pkg' provides valuable information to identify packages with high number 13of vulnerabilities that should be considered for deletion. 14 15Simply symlink this plugin into your Munin plugins directory as 16- debsecan_pkg (the extra_info will list the number of CVE affecting each package) 17- debsecan_cve (the extra_info will list the number of packages affected by each CVE) 18 19For backward compatibility, a symlink without a mode will default to 'pkg'. 20 21=head1 CONFIGURATION 22 23The default configuration is as follows. 24 25 [debsecan] 26 env.suite jessie 27 env.fixed_warning 1 28 env.fixed_critical 1000 29 env.remote_warning 1 30 env.remote_critical 10 31 32The name of the group needs to match the name of the symlink to be applied. 33Shell globbing patterns are allowed. 34 35=head1 AUTHORS 36 37* Nicolas BOUTHORS <nbouthors@nbi.fr> http://nbi.fr/, Inspiration of the moment 10/10/2007 38* Olivier Mehani <shtrom+munin@ssji.net>, 2016 39 40=head1 LICENSE 41 42Public Domain 43 44=head1 MAGIC MARKERS 45 46%# family=auto 47%# capabilities=autoconf 48 49=cut 50 51# Auto enable if we have debsecan only 52if [ "$1" = "autoconf" ] ; then 53 if [ -x /usr/bin/debsecan ]; then 54 echo yes 55 else 56 echo 'no (/usr/bin/debsecan not found)' 57 fi 58 exit 0 59fi 60 61# Fail if we don't have debsecan 62if [ ! -x /usr/bin/debsecan ]; then 63 echo 'error: /usr/bin/debsecan not found' >&2 64 exit 1 65fi 66 67SUITE=${suite:-sid} 68FIXEDWARN=${fixed_warning:-1} 69FIXEDCRIT=${fixed_critical:-1000} 70REMOTEWARN=${remote_warning:-1} 71REMOTECRIT=${remote_critical:-10} 72 73MODE=$(echo "$0" | sed 's/.*_//') 74case "${MODE}" in 75 'cve') 76 TITLE_ADD="unique " 77 FIELD=1 78 ;; 79 'pkg' | *) 80 TITLE_ADD="package " 81 FIELD=2 82 ;; 83esac 84 85if [ "$1" = "config" ] ; then 86 cat <<EOF_ 87graph_title DebSecan: ${TITLE_ADD}vulnerabilities 88graph_info ${TITLE_ADD}vulnerabilities for ${SUITE} 89graph_args -l 0 --base 1000 90graph_vlabel number of CVE 91graph_category system 92graph_period second 93graph_info This graph show the number of known ${TITLE_ADD}vulnerabilities present on your system. Use debsecan to see details. 94remote.label remote 95remote.colour FF0000 96remote.type GAUGE 97remote.draw AREASTACK 98remote.min 0 99remote.info The number of ${TITLE_ADD}remotely exploitable CVEs with any priority 100remote.warning ${REMOTEWARN} 101remote.critical ${REMOTECRIT} 102high.label high 103high.colour DD2200 104high.type GAUGE 105high.draw AREASTACK 106high.min 0 107high.info The number of ${TITLE_ADD}CVEs marked high priority 108medium.label medium 109medium.colour FFAA00 110medium.type GAUGE 111medium.draw AREASTACK 112medium.min 0 113medium.info The number of ${TITLE_ADD}CVEs marked medium priority 114low.label low 115low.colour 0000FF 116low.type GAUGE 117low.draw AREASTACK 118low.min 0 119low.info The number of ${TITLE_ADD}CVEs marked low priority 120other.label other 121other.colour 00AAFF 122other.type GAUGE 123other.draw AREASTACK 124other.min 0 125other.info The number of ${TITLE_ADD}CVEs with unspecified priority 126fixed.label fixed 127fixed.type GAUGE 128fixed.draw LINE2 129fixed.min 0 130fixed.info The number of ${TITLE_ADD}CVEs fixed by available updates 131fixed.warning ${FIXEDWARN} 132fixed.critical ${FIXEDCRIT} 133EOF_ 134 exit 0 135fi 136 137ALL=$(debsecan --suite "${SUITE}" 2> /dev/null) 138REMOTE=$(echo "$ALL" | grep -w 'remotely') 139NONREMOTE=$(echo "$ALL" | grep -wv 'remotely') 140 141HIGH=$(echo "${NONREMOTE}" | grep -w 'high urgency') 142MEDIUM=$(echo "${NONREMOTE}" | grep -w 'medium urgency') 143LOW=$(echo "${NONREMOTE}" | grep -w 'low urgency') 144OTHER=$(echo "${NONREMOTE}" | grep -wv 'urgency') 145FIXED=$(echo "${ALL}" | grep -w '(fixed') 146 147# Arguments: Field offset to aggregate by 148count_entries() { 149 CUT_FIELD="${1}" 150 cut -f "${CUT_FIELD}" -d " "| sort | uniq -c 151} 152 153case "${MODE}" in 154 'cve') 155 remote_count=$(echo "${REMOTE}" | count_entries "${FIELD}" | wc -l) 156 high_count=$(echo "${HIGH}" | count_entries "${FIELD}" | wc -l) 157 medium_count=$(echo "${MEDIUM}" | count_entries "${FIELD}" | wc -l) 158 low_count=$(echo "${LOW}" | count_entries "${FIELD}" | wc -l) 159 other_count=$(echo "${OTHER}" | count_entries "${FIELD}" | wc -l) 160 fixed_count=$(echo "${FIXED}" | count_entries "${FIELD}" | wc -l) 161 ;; 162 'pkg' | *) 163 remote_count=$(echo "${REMOTE}" | wc -l) 164 high_count=$(echo "${HIGH}" | wc -l) 165 medium_count=$(echo "${MEDIUM}" | wc -l) 166 low_count=$(echo "${LOW}" | wc -l) 167 other_count=$(echo "${OTHER}" | wc -l) 168 fixed_count=$(echo "${FIXED}" | wc -l) 169 ;; 170esac 171 172# Reformat the output of the cut|sort|uniq... to a more human-friendly "item (count)" format 173CVECOUNTRE='s/^ *\([0-9]\+\) \+\([^ ]\+\)/\2 (\1)/' 174 175# shellcheck disable=SC2005 disable=SC2046 176# The nested $(echo ...)s are needed to yet the newlines 177cat <<EOF 178remote.value $remote_count 179remote.extinfo $(echo $(echo "${REMOTE}" | count_entries "${FIELD}" | sort -nr | sed "${CVECOUNTRE}")) 180high.value $high_count 181high.extinfo $(echo $(echo "${HIGH}" | count_entries "${FIELD}" | sort -nr | sed "${CVECOUNTRE}")) 182medium.value $medium_count 183medium.extinfo $(echo $(echo "${MEDIUM}" | count_entries "${FIELD}" | sort -nr | sed "${CVECOUNTRE}")) 184low.value $low_count 185low.extinfo $(echo $(echo "${LOW}" | count_entries "${FIELD}" | sort -nr | sed "${CVECOUNTRE}")) 186other.value $other_count 187other.extinfo $(echo $(echo "${OTHER}" | count_entries "${FIELD}" | sort -nr | sed "${CVECOUNTRE}")) 188fixed.value $fixed_count 189fixed.extinfo $(echo $(echo "${FIXED}" | count_entries "${FIELD}" | sort -nr | sed "${CVECOUNTRE}")) 190EOF 191