check_testssl.sh 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. #!/bin/bash
  2. testssl_bin='/usr/local/src/testssl.sh/testssl.sh'
  3. PROGNAME=`basename $0`
  4. VERSION='1.0'
  5. AUTHOR='2020, Wazakindjes'
  6. # Some return val00s
  7. ST_OK=0
  8. ST_WARN=1
  9. ST_CRIT=2
  10. ST_UNK=3
  11. ST_NOPROC=4
  12. ST_PARAM=5
  13. print_version() {
  14. echo "$PROGNAME version $VERSION ($AUTHOR)"
  15. }
  16. print_usage() {
  17. echo "Usage:"
  18. echo "$PROGNAME [--testssl-bin <path>] <URI> [testssl arguments]"
  19. echo "$PROGNAME --help|--halp|-h"
  20. echo "$PROGNAME --version|-v"
  21. echo ""
  22. echo "Options:"
  23. echo " --testssl-bin)"
  24. echo " This script by default assumes testssl.sh is accessible via the path: $testssl_bin,"
  25. echo " but you can set a custom location instead."
  26. echo " --help|--halp|-h)"
  27. echo " Display help/usage information."
  28. echo " --version|-v)"
  29. echo " Display version information."
  30. echo ""
  31. echo "URI format:"
  32. echo "At the time of writing, this can be any of the following: host|host:port|URL|URL:port"
  33. echo "Refer to \`testssl.sh --help\` for the up-to-date list and additional information."
  34. echo ""
  35. echo "IMPORTANT NOTES"
  36. echo " * The order of options is important, as the first argument *not* starting with -- will be used as the URI."
  37. echo " * All arguments coming after it (if any) will be passed as-is to testssl.sh."
  38. echo " * We pass --quiet --color 0 --jsonfile ourselves in order to properly check for warning/critical stuff, so better not specify those yourself. ;]"
  39. echo " * In order to actually parse that JSON, we rely on the \`jq\` tool which might need to be installed first."
  40. echo " jq *must* be available under the \$PATH used by the Nagios/icinga2 agent (check with e.g. \`su -s /bin/bash -c 'echo $PATH' nagios\` (as root))"
  41. }
  42. print_header() {
  43. echo "$PROGNAME is a Nagios/icinga2 plugin to monitor a service's SSL/TLS security/encryption strength."
  44. echo "It makes use of testssl.sh which can be found here: https://github.com/drwetter/testssl.sh"
  45. }
  46. # Always need at least one arg lol
  47. testssl_uri=
  48. if [[ -z $1 ]]; then
  49. print_usage
  50. exit $ST_UNK
  51. fi
  52. while test -n "$1"; do
  53. case "$1" in
  54. --help|--halp|-h)
  55. print_version
  56. echo ""
  57. print_header
  58. echo ""
  59. print_usage
  60. exit $ST_UNK
  61. ;;
  62. --version|-v)
  63. print_version
  64. exit $ST_UNK
  65. ;;
  66. --testssl-bin)
  67. testssl_bin="$2"
  68. ;;
  69. *)
  70. testssl_uri="$1"
  71. shift
  72. break
  73. ;;
  74. esac
  75. shift
  76. done
  77. if [[ ! -f $testssl_bin || ! -x $testssl_bin ]]; then
  78. echo "testssl.sh script wasn't found or isn't executable: $testssl_bin"
  79. exit $ST_NOPROC
  80. fi
  81. jq_bin=`which jq`
  82. if [[ ! -f $jq_bin || ! -x $jq_bin ]]; then
  83. echo "The 'jq' tool wasn't found or isn't executable: $jq_bin"
  84. exit $ST_NOPROC
  85. fi
  86. if [[ -z $testssl_uri ]]; then
  87. echo "Missing URI to test"
  88. exit $ST_PARAM
  89. fi
  90. jaysonfiel=`mktemp /tmp/check_testssl.json.XXXXXXXX`
  91. stdfiel=`mktemp /tmp/check_testssl.std.XXXXXXXX`
  92. if [[ -z $jaysonfiel && -z $stdfiel ]]; then
  93. echo "Unable to create tempfiles"
  94. exit $ST_CRIT
  95. fi
  96. if [[ ! -f $jaysonfiel || ! -w $jaysonfiel ]]; then
  97. echo "Unable to create JSON tempfile (or it's not writeable): $jaysonfiel"
  98. rm -f "$stdfiel"
  99. exit $ST_CRIT
  100. fi
  101. if [[ ! -f $stdfiel || ! -w $stdfiel ]]; then
  102. echo "Unable to create misc tempfile (or it's not writeable): $stdfiel"
  103. rm -f "$jaysonfiel"
  104. exit $ST_CRIT
  105. fi
  106. perf_start=`date +%s`
  107. testssl_out="$("$testssl_bin" "$@" --quiet --color 0 --jsonfile "$jaysonfiel" "$testssl_uri" 2>&1 >"$stdfiel")"
  108. perf_end=`date +%s`
  109. perf_runtime=$((perf_end - perf_start))
  110. exitval=$ST_OK
  111. statustxt='OK'
  112. if [[ ! -z $testssl_out ]]; then
  113. exitval=$ST_WARN
  114. statustxt='WARNING'
  115. echo "stderr from testssl.sh isn't empty:"
  116. echo "$testssl_out"
  117. echo ""
  118. fi
  119. if [[ ! -z `jq '.[] | select(.finding == "Scan interrupted") | .finding' "$jaysonfiel"` ]]; then
  120. echo "WARNING - Scan interrupted"
  121. echo "Additional information:"
  122. cat "$stdfiel"
  123. rm -f "$jaysonfiel" "$stdfiel"
  124. exit $ST_WARN
  125. fi
  126. jq_ok=`jq '.[] | select(.severity == "OK")' "$jaysonfiel"`
  127. jq_info=`jq '.[] | select(.severity == "INFO")' "$jaysonfiel"`
  128. jq_low=`jq '.[] | select(.severity == "LOW")' "$jaysonfiel"`
  129. jq_medium=`jq '.[] | select(.severity == "MEDIUM")' "$jaysonfiel"`
  130. jq_high=`jq '.[] | select(.severity == "HIGH")' "$jaysonfiel"`
  131. jq_warn=`jq '.[] | select(.severity == "WARN")' "$jaysonfiel"`
  132. jq_crit=`jq '.[] | select(.severity == "CRIT")' "$jaysonfiel"`
  133. jq_fatal=`jq '.[] | select(.severity == "FATAL")' "$jaysonfiel"`
  134. perf_ok=`echo "$jq_ok" | jq '.finding' | wc -l`
  135. perf_info=`echo "$jq_info" | jq '.finding' | wc -l`
  136. perf_low=`echo "$jq_low" | jq '.finding' | wc -l`
  137. perf_medium=`echo "$jq_medium" | jq '.finding' | wc -l`
  138. perf_high=`echo "$jq_high" | jq '.finding' | wc -l`
  139. perf_warn=`echo "$jq_warn" | jq '.finding' | wc -l`
  140. perf_crit=`echo "$jq_crit" | jq '.finding' | wc -l`
  141. perf_fatal=`echo "$jq_fatal" | jq '.finding' | wc -l`
  142. perf_checkcount=`jq '.[].id' "$jaysonfiel" | wc -l`
  143. # We group some shit for the summary, since there likely are false positives due to having e.g. mitigations for BEAST in place
  144. out_ok=$((perf_ok + perf_info))
  145. out_warn=$((perf_medium + perf_warn + perf_low))
  146. out_crit=$((perf_high + perf_crit + perf_fatal))
  147. if [[ $out_crit -gt 0 ]]; then
  148. exitval=$ST_CRIT
  149. statustxt='CRITICAL'
  150. elif [[ $out_warn -gt 0 ]]; then
  151. exitval=$ST_WARN
  152. statustxt='WARNING'
  153. fi
  154. output="high severity: $out_crit, warnings: $out_warn, ok: $out_ok"
  155. perfdata="'scantime'=$perf_runtime 'check_count'=$perf_checkcount 'status_info'=$perf_info 'status_low'=$perf_low 'status_medium'=$perf_medium 'status_high'=$perf_high 'status_warn'=$perf_warn 'status_crit'=$perf_crit 'status_fatal'=$perf_fatal 'status_ok'=$perf_ok"
  156. echo "$statustxt - $output | $perfdata"
  157. if [[ ! -z `head -1 $jaysonfiel` ]]; then
  158. echo "Additional information (scanner JSON output):"
  159. if [[ ! -z $jq_fatal ]]; then
  160. echo -e "\n====FATAL===="
  161. echo "$jq_fatal"
  162. fi
  163. if [[ ! -z $jq_crit ]]; then
  164. echo -e "\n====CRIT===="
  165. echo "$jq_crit"
  166. fi
  167. if [[ ! -z $jq_high ]]; then
  168. echo -e "\n====HIGH===="
  169. echo "$jq_high"
  170. fi
  171. if [[ ! -z $jq_warn ]]; then
  172. echo -e "\n====WARN===="
  173. echo "$jq_warn"
  174. fi
  175. if [[ ! -z $jq_medium ]]; then
  176. echo -e "\n====MEDIUM===="
  177. echo "$jq_medium"
  178. fi
  179. if [[ ! -z $jq_low ]]; then
  180. echo -e "\n====LOW===="
  181. echo "$jq_low"
  182. fi
  183. #if [[ ! -z $jq_info ]]; then
  184. # echo -e "\n"
  185. # echo "$jq_info"
  186. #fi
  187. #if [[ ! -z $jq_ok ]]; then
  188. # echo -e "\n"
  189. # echo "$jq_ok"
  190. #fi
  191. fi
  192. rm -f "$jaysonfiel" "$stdfiel"
  193. exit $exitval