Skip to content

Instantly share code, notes, and snippets.

@MegaManSec
Last active January 7, 2024 14:12
Show Gist options
  • Save MegaManSec/216edf6de5e2625d30a4ce8f0656d7e1 to your computer and use it in GitHub Desktop.
Save MegaManSec/216edf6de5e2625d30a4ce8f0656d7e1 to your computer and use it in GitHub Desktop.
We were suffering a fairly large HTTP ddos, that would try and create vBulletin forum accounts, causing huge overhead with mysql, php, and apache. This was one of the solutions to that.
#!/bin/bash
#We were suffering a fairly large HTTP ddos, that would try and create vBulletin forum accounts, causing huge overhead with mysql, php, and apache.
#This script will ban anyone that goes to the pages $BADLIST more than $REGLIMIT
#It will also rename a file if it has been gone to more than $LIMIT times
#then it will add a redirect in htaccess
#what files we match (must end with .php$)
FPAT='^\/+[^/]+\.php$'
#trigger on LIMIT requests in the last INTERVAL seconds
INTERVAL=300
LIMIT=100
REGLIMIT=10
#save some time and only consider last LOGHIST lines from access log which shoul
#be enough to include the recent INTERVAL seconds even unter high load
#perhaps 2000 per INTERVAL/60 minutes is a good value
LOGHIST=1000
#files that we consider bad.
BADLIST="register\.php|login\.php|"
#----------------------------------------------------------------
LOGFILE='/var/log/apache2/access.log'
DOCROOT='/var/www/'
HTA='/var/.htaccess'
SINCE=$(($(date +%s)-${INTERVAL}))
TMPFILE='/tmp/fgtfile.tmp'
REGTMP='/tmp/fgtreg.tmp'
rm -f $TMPFILE &> /dev/null
rm -f $REGTMP &> /dev/null
D=0
E=0
didntget=1
VERBOSE=0
if [ "$1" = "verbose" ]; then
VERBOSE=1
fi
tail -n${LOGHIST} $LOGFILE | egrep 'TS:[0-9]{10}' | while read LINE; do
TS=$(echo "${LINE}" | egrep -o 'TS:[0-9]{10}' | cut -c 4-)
if [ $TS -lt $SINCE ]; then
#echo -n .
didntget=0
D=$((D+1))
if [ $VERBOSE -eq 1 -a $((${D}%200)) -eq 0 ]; then
echo "$D irrelevant lines"
fi
continue
fi
if [ $VERBOSE -eq 1 -a $D -ne 0 ]; then
echo "LOGHIST should have been $((${LOGHIST}-${D})) for this one (only first msg matters)"
D=0
fi
#if [ $didntget -eq 1 ]; then
# echo "LOGHIST too low -_-, didn't get everything"
# didntget=0
#fi
#echo -n "$D "
#PAGE=$(echo "${LINE}" | awk '{print $3}')
#if echo "${PAGE}" | egrep "${FPAT}" &> /dev/null; then
#echo "${PAGE}" >> $TMPFILE
#fi
E=$((E+1))
if [ $VERBOSE -eq 1 -a $((${E}%50)) -eq 0 ]; then
echo "$E relevant lines"
fi
echo "${LINE}" | awk '{print $3}' >> $TMPFILE
echo "${LINE}" >> $REGTMP
done
if [ $VERBOSE -eq 1 ]; then
echo "stage 1 complete"
fi
if [ ! -f $TMPFILE ]; then
exit 1
fi
C=0
for f in `cat $TMPFILE | egrep "${FPAT}" | sort | uniq`; do
NUM=$(cat $TMPFILE | grep "$f" | wc -l)
if echo $f | grep -E 'vbshout|register|css|' &> /dev/null; then
continue
fi
if [ ! -f "${DOCROOT}${f}" ]; then
continue
fi
#echo "$f has ${NUM}"
if [ $NUM -gt $LIMIT ]; then
C=$((${C}+1))
#echo "would rename $f (${NUM} accesses in ${INTERVAL} secs)"
cd $DOCROOT
FN=$(basename $f .php)
if echo $FN | grep '[0-9]$' &> /dev/null; then
#haz number
FNB="$(echo $FN | sed -E 's/[0-9]+$//g')"
NFN="${FNB}$(($(echo $FN | egrep -o '[0-9]+$')+1))"
else
FNB="${FN}"
NFN="${FN}1"
fi
FNB="${FNB}.php"
FN="${FN}.php"
NFN="${NFN}.php"
#echo "FN: '${FN}' FNB: '${FNB}' NFN: '${NFN}'"
echo -n "$(date) ${FN} -> ${NFN} (${FNB})"
mv ${FN} ${NFN}
if cat $HTA | egrep "^redirect /${FNB} .*$" &> /dev/null; then
cat $HTA | sed -E "s,^redirect /${FNB} .*$,redirect /${FNB} /${NFN},g" > /tmp/newhta
cat /tmp/newhta > $HTA
echo
else
echo "redirect /${FNB} /${NFN}" >> $HTA
echo '*'
fi
fi
done
if [ $VERBOSE -eq 1 ]; then
echo "stage 2 complete"
fi
cat $REGTMP | egrep -i $BADLIST | awk '{print $1}' | sort | uniq -c | while read f; do
NUM=$(echo "$f" | awk '{print $1}')
IP=$(echo "$f" | awk '{print $2}')
NB=$(cat ./no.ban | grep "${IP}" | wc -l)
if [ $VERBOSE -eq 1 ]; then
echo "$(date) there have been $NUM connection(s) from $IP"
fi
if [ $NUM -gt $REGLIMIT ]; then
if [ $NB -eq 0 ]; then
echo "$(date) firewalling ${IP} due to a bad file"
/sbin/iptables -A INPUT -s "${IP}" -j DROP
else
echo "not banning $IP because it is on the noban list"
fi
fi
done
if [ $C -eq 1 ]; then
echo "${C} page was changed"
elif [ $C -gt 1 ]; then
echo "${C} pages were changed"
elif [ $VERBOSE -eq 1 ]; then
echo "${C} pages were changed"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment