From 867ac1955dded463362c817f5315428b90f11ba5 Mon Sep 17 00:00:00 2001 From: Oliver Ladner Date: Thu, 6 Jan 2011 14:04:33 +0100 Subject: [PATCH] initial upload --- delicious_backup.sh | 24 +++++ find_big_files.sh | 22 +++++ helmet.sh | 114 +++++++++++++++++++++++ libssl-restart-daemons.sh | 6 ++ lighttpd_restart_oom.sh | 25 +++++ openssl-chk-crt.sh | 54 +++++++++++ policyd-550.sh | 11 +++ rblcheck.sh | 190 ++++++++++++++++++++++++++++++++++++++ tls_stats.sh | 6 ++ www-perms.sh | 43 +++++++++ 10 files changed, 495 insertions(+) create mode 100755 delicious_backup.sh create mode 100755 find_big_files.sh create mode 100755 helmet.sh create mode 100755 libssl-restart-daemons.sh create mode 100755 lighttpd_restart_oom.sh create mode 100755 openssl-chk-crt.sh create mode 100755 policyd-550.sh create mode 100755 rblcheck.sh create mode 100755 tls_stats.sh create mode 100755 www-perms.sh diff --git a/delicious_backup.sh b/delicious_backup.sh new file mode 100755 index 0000000..d8593e9 --- /dev/null +++ b/delicious_backup.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# +# Fetches all your delicious bookmarks +# and validates the XML before saving. +# Requires xmlstarlet + +DEL_USER=foo +DEL_PASS=bar +API_URL=api.del.icio.us/v1/posts/all +BKP_FILE=/home/username/deliciousbackup.xml + +# When no backup exists, just do it +if [ ! -f $BKP_FILE ]; then + curl -s https://$DEL_USER:$DEL_PASS@$API_URL > $BKP_FILE +else + curl -s https://$DEL_USER:$DEL_PASS@$API_URL > $BKP_FILE.tmp + # if XML is valid, move to final destination + if [ $(xmlstarlet validate $BKP_FILE.tmp > /dev/null 2>&1; echo $?) -gt 0 ]; then + rm $BKP_FILE.tmp + echo "Downloaded XML file not valid. Previous backup preserved." + else + mv $BKP_FILE.tmp $BKP_FILE + fi +fi diff --git a/find_big_files.sh b/find_big_files.sh new file mode 100755 index 0000000..71bf3cb --- /dev/null +++ b/find_big_files.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# $Id: find_big_files.sh 11 2009-02-06 08:48:41Z oli $ +# +# Find and report big files + +MIN_SIZE="$1M" +DIRS="/usr /home /etc /bin /var /sbin /tmp" +EXCLUDE="" + +# df +DF=$(df -h) + +if [ ! $1 ]; then + echo "Usage: $0 " + exit 1 +else + DO_IT=`find $DIRS -size +$MIN_SIZE -print -exec ls -lha {} \; | grep -v '$EXCLUDE' | awk {'print $5"\t"$6" "$7" "$8'}` + LOL=`echo $DO_IT | wc -l` + if [ "$LOL" -gt "0" ]; then + echo $DO_IT + fi +fi diff --git a/helmet.sh b/helmet.sh new file mode 100755 index 0000000..44c6b98 --- /dev/null +++ b/helmet.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash +# Author: Oliver Ladner +# License: GPLv2 +# +# This tool scans a Debian-based system for threats in programs, +# configurations, permissions etc. and calculates a score to +# compare different systems. +# +# This script runs noninteractive, so you can rely on these return +# codes: +# 0 script run ok, nothing serious found +# 1 OS detection failed +# 2 script run ok, critical stuff found +# +# Requirements: +# - + +H_VERSION="0.0.1" + +showhelp() { +cat << EOF +Usage: $(basename $0) [OPTION]... + + -h|--help This information + -m|--no-md5 Don't check MD5 sums of packages + -s|--no-ssh No SSH-related checks + -v|--verbose Be verbose + -V|--version Show version + --force-debian If OS detection fails, assume Debian + --force-ubuntu If OS detection fails, assume Ubuntu +EOF +} + +# Argument handling +while [ $# -gt 0 ]; do + case $1 in + -h|--help) showhelp; exit; shift 1 ;; + -V|--version) echo $(basename $0) $H_VERSION; exit; shift 1 ;; + -v|--verbose) verb=echo; shift 1 ;; + -m|--no-md5) md5=false; shift 1 ;; + -s|--no-ssh) ssh=false; shift 1 ;; + *) showhelp; exit ;; + esac +done + +DEBIANCODES=([3]=woody/sarge [4]=etch [5]=lenny [6]=squeeze [7]=wheezy) + +# Debian is missing lsb_release command +if [[ $(which lsb_release) ]]; then + H_DISTRO=$(lsb_release -s -i) + H_RELEASE=$(lsb_release -s -r) + H_CODE=$(lsb_release -s -c) +# FIXME probably a strange check for Debian +elif [[ $(grep -c '^[[:digit:]]' /etc/debian_version) > 0 ]]; then + H_DISTRO=$(awk -F': ' '/Vendor:/ {print $2}' /etc/dpkg/origins/debian) + H_RELEASE=$(cat /etc/debian_version) + H_CODE=${DEBIANCODES[$(echo $H_RELEASE | cut -b1)]} +else + echo "Not a Debian-based, please install the package lsb-release and send" . + " the output of 'lsb_release -a' if available to info@lugh.ch." + exit 1 +fi + +H_KERNEL=$(uname -r) +H_ARCH=$(uname -m) + +check_md5() { + # http://kemovitra.blogspot.com/2010/07/checking-integrity-of-debianubuntu.html + if [ $md5 ]; then + MD5SUMS="not run" + else + if [ $H_DISTRO == "Debian" ]; then + $verb "Copying all /var/lib/dpkg/info/*.md5sums to shared memory..." + TEMPMD5=$(mktemp -t) + cat /var/lib/dpkg/info/*.md5sums | sort > $TEMPMD5 && cd / + $verb "Running md5sum, searching for 'FAILED' files..." + MD5SUMS=$(md5sum -c $TEMPMD5 2>&1 | grep ': FAILED' | awk -F':' {'print "/"$1'} && rm $TEMPMD5) + else + MD5SUMS="Check not supported on $H_DISTRO" + fi + fi +} + +check_ssh() { + if [[ $(grep -i -c 'PermitRootLogin.*yes' /etc/ssh/ss*conf*) > 0 ]]; then + SSHD="Root login enabled!" + else + SSHD="root login disabled" + fi +} + +check_md5 +check_ssh + +# Output +#------- +column -t -s':' -c 80 << EOF +Distribution:$H_DISTRO +Release/Codename:$H_RELEASE ($H_CODE) +Kernel/Architecture:$H_KERNEL ($H_ARCH) + +# MD5 CHECK +Packages with wrong MD5 hashes +$MD5SUMS +# SSH daemon settings +$SSHD +EOF + +# /usr/bin/printf "\u00A9 2010 Oliver Ladner\n" #unicode ausgabe + +# Define default return code +exit 0 + +# vim: ts=3:sw=3 diff --git a/libssl-restart-daemons.sh b/libssl-restart-daemons.sh new file mode 100755 index 0000000..22dc18b --- /dev/null +++ b/libssl-restart-daemons.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +# +# Shows all applications using libssl +# They need to be restarted after an OpenSSL upgrade + +lsof | grep libssl | awk {'print $1"\t "$3'} | sort | uniq diff --git a/lighttpd_restart_oom.sh b/lighttpd_restart_oom.sh new file mode 100755 index 0000000..d22e652 --- /dev/null +++ b/lighttpd_restart_oom.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# +# Monitors if lighttpd uses too much mem, and if so, restarts it + +# 100MB +MAXRAM=200000 + +while true; do +CHECK=$(ps auxww | grep 'lighttpd -f' | grep -v grep | awk '{print $6}') +sleep 5 + + if [ $CHECK -gt $MAXRAM ]; then + logger "lighttpd OOM ($CHECK KB used)" + /etc/init.d/lighttpd stop + sleep 15 + /etc/init.d/lighttpd start + sleep 5 + elif [ -z $CHECK ]; then + logger "lighttpd not running, starting" + /etc/init.d/lighttpd start + sleep 15 + else + logger "lighttpd normal ($CHECK KB used)" + fi +done diff --git a/openssl-chk-crt.sh b/openssl-chk-crt.sh new file mode 100755 index 0000000..40e59e5 --- /dev/null +++ b/openssl-chk-crt.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# Recursively search for SSL certificate +# files and display valid period +# +# Won't run on Solaris without modifications (find, date etc) + +# We need arguments +if [ "$1" = "-h" -o "$1" = "--help" ]; then + echo -e "Usage: `basename $0` [option] [path]" + echo -e "Options: -v\tonly show valid certs\r" + echo -e " -e\tonly show expired certs" + exit +fi + +# probably(tm) too complicated ;-) +if [ "$1" = "-e" ]; then + ONLY_EXPIRED=TRUE + MYPATH="$2" +elif [ "$1" = "-v" ]; then + ONLY_VALID=TRUE + MYPATH="$2" +else +if [ ! -z $1 ]; then + if [ "$2" = "-e" ]; then + ONLY_EXPIRED=TRUE + elif [ "$2" = "-v" ]; then + ONLY_VALID=TRUE + else + ONLY_VALID=FALSE + ONLY_EXPIRED=FALSE + fi + MYPATH=$1 +else + MYPATH="." + ONLY_VALID=FALSE + ONLY_EXPIRED=FALSE +fi +fi + +FOO=`find $MYPATH -type f -iname "*.crt*" | grep -v '.svn'` +for i in `echo $FOO`; do + MYPATH=$(dirname $i) + MYFILE=$(basename $i) + + # date conversion + DATE_STRING=$(openssl x509 -text -in $i | grep 'Not After' | awk -F": " '{print $2}') + NOT_AFTER=$(date -d "$DATE_STRING" +%s) + UNIX2HUMAN=$(date -d "1970-01-01 $NOT_AFTER sec" +%c) + if [ $NOT_AFTER -le $(date +%s) ]; then + if [ $ONLY_EXPIRED ]; then echo "$MYPATH/$MYFILE" && echo "Certificate expired $UNIX2HUMAN"; fi + else + if [ $ONLY_VALID ]; then echo "$MYPATH/$MYFILE" && echo "Certificate is valid"; fi + fi +done diff --git a/policyd-550.sh b/policyd-550.sh new file mode 100755 index 0000000..feb4f1d --- /dev/null +++ b/policyd-550.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# $Id: policyd-550.sh 16 2009-04-28 12:51:28Z oli $ +# +# Shows all mails rejected by policyd-weight. +# Requires that $REJECTMSG in /etc/policyd-weight.conf +# contains "550 Mail" + +LOGFILE="/var/log/mail.log" + +echo -e "Score\tRecipient\t\tSender" +grep -B1 '550 Mail' $LOGFILE | awk -F'<' '{print $4,$5}' | grep 'rate:' | sed -r -e 's/(to|from)=//g' -e 's/(>|;)//g' -e 's/rate: //g' | awk '{print $3"\t"$2"\t\t"$1}' | sort -n diff --git a/rblcheck.sh b/rblcheck.sh new file mode 100755 index 0000000..0435f14 --- /dev/null +++ b/rblcheck.sh @@ -0,0 +1,190 @@ +#!/usr/bin/env bash +# Checks if given IP is listed on any of the "major" DNSBL. +# I used this list: http://spamlinks.net/filter-dnsbl-lists.htm +# +# Requires these commands: host, dig, awk, tr, dirname +# - We can't rely on host/dig return codes! + +# Return codes: +# 0 = no listings +# 4 = listed + +# Define all DNSBL to test against +dnsbl=(b.barracudacentral.org +bl.deadbeef.com +#bl.emailbasura.org +bl.spamcannibal.org +bl.spamcop.net +blackholes.five-ten-sg.com +blacklist.woody.ch +bogons.cymru.com +cbl.abuseat.org +cdl.anti-spam.org.cn +combined.abuse.ch +combined.rbl.msrbl.net +db.wpbl.info +dnsbl-1.uceprotect.net +dnsbl-2.uceprotect.net +dnsbl-3.uceprotect.net +dnsbl.ahbl.org +dnsbl.cyberlogic.net +dnsbl.inps.de +dnsbl.njabl.org +dnsbl.sorbs.net +dnsrbl.swinog.ch +#duinv.aupads.org +dul.dnsbl.sorbs.net +dul.ru +dyna.spamrats.com +#dynip.rothen.com +#fl.chickenboner.biz +hostkarma.junkemailfilter.com +http.dnsbl.sorbs.net +images.rbl.msrbl.net +ips.backscatterer.org +ircbl.ahbl.org +ix.dnsbl.manitu.net +korea.services.net +misc.dnsbl.sorbs.net +noptr.spamrats.com +#ohps.dnsbl.net.au +#omrs.dnsbl.net.au +#opm.blitzed.org +orvedb.aupads.org +#osps.dnsbl.net.au +#osrs.dnsbl.net.au +#owfs.dnsbl.net.au +#owps.dnsbl.net.au +phishing.rbl.msrbl.net +#probes.dnsbl.net.au +#proxy.bl.gweep.ca +#proxy.block.transip.nl +psbl.surriel.com +rbl.efnet.org +rbl.interserver.net +#rdts.dnsbl.net.au +#relays.bl.gweep.ca +relays.bl.kundenserver.de +#relays.nether.net +relaytest.kundenserver.de +#residential.block.transip.nl +#ricn.dnsbl.net.au +#rmst.dnsbl.net.au +short.rbl.jp +smtp.dnsbl.sorbs.net +socks.dnsbl.sorbs.net +spam.abuse.ch +spam.dnsbl.sorbs.net +spam.rbl.msrbl.net +spam.spamrats.com +spamlist.or.kr +spamrbl.imp.ch +#t3direct.dnsbl.net.au +#tor.ahbl.org +tor.dnsbl.sectoor.de +torserver.tor.dnsbl.sectoor.de +ubl.lashback.com +ubl.unsubscore.com +virbl.bit.nl +virbl.dnsbl.bit.nl +virus.rbl.jp +virus.rbl.msrbl.net +web.dnsbl.sorbs.net +wormrbl.imp.ch +zen.spamhaus.org +zombie.dnsbl.sorbs.net) + +# No need to edit anything below this line + +DNSBLCOUNT=${#dnsbl[*]} + +if [ -z $1 ]; then + echo "Usage: $(basename $0) " + exit 1 +fi + +INPUT=$1 +# If $INPUT is a DNS name, get IP +if [ $(echo $INPUT | grep -c '[a-z]') -gt 0 ]; then + INPUT=$(dig +short $INPUT | tail -1) +fi +LISTED=0 + +# Reverse an ip +function ip_reverse { + # FIXME dumb + INPUT=$(echo $INPUT | tr -s "." " ") + INPUT=$(echo $INPUT | awk '{for (i=NF;i>=1;i--) printf $i" "} END{print ""}') + OUTPUT=$(echo $INPUT | tr -s " " ".") + echo $OUTPUT +} + +# Query the RBL +function check_rbl { + ARG=$1 + if [ "$ARG" = "reachability" ]; then + RETURNED=$(host $a | grep -c NXDOMAIN) + + if [ $RETURNED -gt 0 ]; then + echo "$a ($b) not reachable, thus ignored." + # Delete this entry from the array via id + unset dnsbl[$b] + fi + WHATSLEFT=${#dnsbl[@]} + fi + + if [ "$ARG" = "node" ]; then + # dig lookup with reversed ip + QUERY=$(dig -t ANY +noauthority +noadditional +nostats $(ip_reverse).$i | grep -E -w '(status:|TXT|(A|CNAME))') + QUERY_END=$(echo $QUERY | awk '{ print $NF }') + + + case $QUERY in + + *NXDOMAIN*) + #echo "Not in $i" + ;; + #*127.0.0.2) + # echo "$(ip_reverse) LISTED in $i" + # ;; + + # Almost all DNSBLs got a TXT record for listed IPs, we want these + *TXT*) + REASON_REMOTE=$(echo $QUERY | grep TXT | cut -d'"' -f2 | head -1) + echo "LISTED in $i ($REASON_REMOTE) " + LISTED=$(($LISTED+1)) + ;; + # For those DNSBLs with no TXT record, just indicate the listing + *) + echo "LISTED in $i (no reason provided)" + LISTED=$(($LISTED+1)) + ;; + esac + fi +} + +echo -e "Mailserver:\t$INPUT" + +# dnsbl array counter +b=-1 + +# First check if the RBL is reachable +for a in "${dnsbl[@]}"; do + b=$(($b+1)) + check_rbl reachability +done + +echo -e "DNSBLs:\t\t$DNSBLCOUNT ($WHATSLEFT reachable)" + +# Then query +for i in "${dnsbl[@]}"; do + check_rbl node +done + +PERC=$(echo "scale=3; ($LISTED / $WHATSLEFT) * 100" | bc) +echo -e "Listings:\t$LISTED ($PERC %)" + +# Set return code +if [ $LISTED -gt 0 ]; then + exit 4 +fi diff --git a/tls_stats.sh b/tls_stats.sh new file mode 100755 index 0000000..49ccbbe --- /dev/null +++ b/tls_stats.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +# greps mail.log for TLS debug loglines and displays sender count +# and cipher used. + +MIN_MAILS=2 +zgrep 'Anonymous TLS connection established from' /var/log/mail.log* | sed -r 's/\[[0-9.]*\]://g' | awk {'print $15,$11'} | sort | uniq -c -i | while read line; do [[ $(grep -oE '^\s*[0-9]+' <<< $line) -gt $MIN_MAILS ]] && echo $line; done diff --git a/www-perms.sh b/www-perms.sh new file mode 100755 index 0000000..655c9c2 --- /dev/null +++ b/www-perms.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# Checks the webroot for files being owned by www daemon and +# writable at the same time. This is only needed by some files +# so we'll check with a whitelist. +# Requires bash 3.2 + +WWWROOT=/var/www/virtsrv +WWWUSER=www-data +WHITELIST="(mpd.lugh.ch/music|\ +mail.lugh.ch/config/conf|\ +/turba/config/conf|\ +admin.lugh.ch/webalizer|\ +admin.lugh.ch/munin|\ +oli.lugh.ch/cache|\ +/wp-content/cache|\ +/wp-content/w3tc/objectcache|\ +/wp-content/w3tc/dbcache|\ +/wp-content/w3tc/pgcache|\ +/wp-content/uploads|\ +/piwik/tmp|\ +/piwik/config/config.ini.php|\ +sitemap.xml*|\ +telperien.lugh.ch/gaestebuch/data|\ +telperien.lugh.ch/gaestebuch/data/book.dat +)" +listcount=0 +whitelist_matches=0 + +while IFS="" read -r matchedentry; do + if [[ "$matchedentry" =~ $WHITELIST ]]; then + whitelist_matches=$((whitelist_matches+1)) + else + echo -e "$matchedentry\r" + listcount=$((listcount+1)) + fi +done < <(find "$WWWROOT" -perm /u+w -user $WWWUSER -o -perm /g+w -group $WWWUSER) + +if [ $listcount -gt 0 ]; then + echo "Finished: $listcount items are writable by '$WWWUSER' ($whitelist_matches whitelisted)." +else + echo "No writable items found ($whitelist_matches whitelisted)." +fi +