# - private.bashlib - # - WatchWB - # Settings & functions private to this module # # # - inject - # Do all the dirty work here # determination, affair counting, dropping, etc. ... # inject() { local funtag="[${FUNCNAME[0]}]" local penalty=${1:-1} local retcode local isdropped local haveit this_ip this_state this_affairs this_severity trace "$funtag Triggered by rule [$RULESET/$RULE] '$Pattern'" # If bandit is determined in the preprocessor don't repaet here # BANDIT=`get_bandit` if ipset -q test whitelist "$BANDIT" then return 3 # Flag whitelisted IP address and bailout fi # IP valiadation automagically done by the IPSET command # ... no longer needed in Watcher 1.3 and beyond # validate_IP $BANDIT # if [ $? -ne 0 ] # then trace "$funtag Got junk for bandit '$BANDIT' ... bailing out ..." # return 255 # fi # CLASS=`get_class $BANDIT` # IP address classification not needed for WEB access CLASS=Httpd # ... so set some dummy as default HTTP_METHOD=`get_method` HTTP_CODE=`get_httpcode` if [ -z "$WEB_CLASS" ]; then WEB_CLASS="Unknown"; fi trace "$funtag $CLASS $BANDIT, WEB-Class: '$WEB_CLASS', HTERR: '$HTTP_CODE'" # # See if this bandit is already known ... # # haveit=`$SQL "select IP from $TABLE where IP='$BANDIT';"` haveit=`$SQL "select IP,state,affairs,severity from $TABLE where IP='$BANDIT';"` if [ -n "$haveit" ] then IFS='|' read -r this_ip this_state this_affairs this_severity <<< "$haveit" fi # Introduction of bandit? if [ -z "$haveit" ] then # Fix IPset first of all $IPSET -exist add tarpit $BANDIT timeout $((2**AFFAIRS * TIME_SLICE)) comment "tarpit,$THIS_TYPE,$AFFAIRS" STATE='INTRO' SEVERITY='Initial' AFFAIRS=$penalty ACTION="Initial $AFFAIRS/$MAX_AFFAIRS, Penalty: $penalty" Comment="Break-in" if [ -n "$GEOTRACK" ]; then do_geotrack $BANDIT $ME; fi # Immediate drop (Experimental) if [[ $AFFAIRS -ge $MAX_AFFAIRS ]] then ACTION="Immediate drop, Penalty: $penalty" STATE='DROP' SEVERITY='Immediate' fi $SQL "insert into $TABLE (IP,origin,ruleset,rule,class,web_class,method,state,severity,type,affairs, date_event,date_intro,instance,comment) values ('$BANDIT','$ME','$RULESET','$RULE','$CLASS','$WEB_CLASS','$HTTP_METHOD', '$STATE','$SEVERITY','$THIS_TYPE',$AFFAIRS, datetime(current_timestamp,'localtime'), datetime(current_timestamp,'localtime'), $INSTANCE_ID, '$Comment' );" retcode=1 else # OK. Have this culprit already # AFFAIRS=`$SQL "select affairs from $TABLE where IP='$BANDIT';"` AFFAIRS=$this_affairs # Limit exeeded ? if [ $AFFAIRS -gt $MAX_AFFAIRS ] then trace "$funtag DROPed culprit $BANDIT reoccured ... taken into custody" $IPSET -exist add custody $BANDIT comment "custody,$THIS_TYPE,$WEB_CLASS" retcode=1 return $retcode # Take the short way out ... just return fi # Limit reached ? if [ $AFFAIRS -lt $MAX_AFFAIRS ] then # Count up bandit's affairs ((AFFAIRS++)) # Fix IPset first of all ... $IPSET -exist add tarpit $BANDIT timeout $((2**AFFAIRS * TIME_SLICE)) comment "$THIS_TYPE,$AFFAIRS" STATE='COUNT' ACTION="Count $AFFAIRS/$MAX_AFFAIRS" SEVERITY='Counted' # $SQL "update $TABLE set affairs=$AFFAIRS, rule='$RULE', class='$CLASS', $SQL "update $TABLE set affairs=affairs+1, rule='$RULE', class='$CLASS', state='$STATE', severity='$SEVERITY', method='$HTTP_METHOD', date_event=datetime(current_timestamp,'localtime') where IP='$BANDIT';" retcode=1 else # Drop if the limit is reached # Fix IPset first of all ... $IPSET -exist add tarpit $BANDIT timeout $((2**AFFAIRS * TIME_SLICE)) comment "tarpit,$THIS_TYPE,$AFFAIRS" STATE='DROP' ACTION="Dropped @ $AFFAIRS" SEVERITY='Dropped' $SQL "update $TABLE set class='$CLASS', web_class='$WEB_CLASS', state='$STATE', severity='$SEVERITY', origin='$ME', rule='$RULE', method='$HTTP_METHOD', affairs=$AFFAIRS, date_event=datetime(current_timestamp,'localtime'), comment='$ACTION' where IP='$BANDIT';" retcode=1 # Last round in tarpit for the culprit fi fi write_affairs $BANDIT $AFFAIRS $RULE $INSTANCE_ID $RULESET # clog "$funtag" "$CLASS" "$BANDIT" "'$ACTION'" # trace "$funtag $CLASS $BANDIT '$ACTION'" clog "$funtag" "$THIS_TYPE" "$BANDIT" "'$ACTION'" trace "$funtag $THIS_TYPE $BANDIT '$ACTION'" return $retcode } get_method() { local funtag="[${FUNCNAME[0]}]" echo "$REPLY" | awk ' /[ \042]*(GET )/ { print "GET"; exit } /[ \042]*(POST )/ { print "POST"; exit } /[ \042]*(PUT )/ { print "PUT"; exit } /[ \042]*(HEAD )/ { print "HEAD"; exit } /[ \042]*(DELETE )/ { print "DELETE"; exit } /[ \042]*(OPTIONS )/ { print "OPTIONS"; exit } ' <<< $REPLY } get_instance() { local funtag="[${FUNCNAME[0]}]" awk ' match($0,"[[]Instance: ") { tail=substr($0,RSTART+RLENGTH) split(tail,parts,":") print parts[1] }' <<< $REPLY } get_insttype() { local funtag="[${FUNCNAME[0]}]" awk ' match($0,"]@") { print substr($0,RSTART+RLENGTH) } ' <<< $REPLY } get_httpcode() { local funtag="[${FUNCNAME[0]}]" awk 'match($0,/[ ]+[1-9][0-9]{2}[ ]+/) { print substr($0,RSTART+1,RLENGTH-2) } ' <<< $REPLY } write_affairs() { local u_seconds=`date +%s%6N` $SQL "insert into affairs_by_ip (ip_addr, affair_num, rule, date_event, time_useconds, instance, ruleset) VALUES ('$1',$2,'$3', datetime(current_timestamp,'localtime'), $u_seconds, $4,'$5');" } get_sets() { local funtag="[${FUNCNAME[0]}]" local sets sets=`find rules/ -type d | cut -f2 -d"/"` echo $sets } # # Create the dispatcher 'filter' # filter() { # $1 ... the instance type local funtag="[${FUNCNAME[0]}]" local retcode rs # Call ruleset for the instance typ first # and the 'Common' ruleset as a catch-all if [ ! -z "$1" ] then # for rs in "$1" Common for rs in Common "$1" do RULESET=$rs ruleset-$rs; retcode=$? [[ $retcode -ne 0 ]] && return $retcode done else trace "$funtag No ruleset for $REPLY" fi # Never reached on match in a ruleset RULE=NO_RULE_MATCH return 0 }