Last active
January 7, 2024 14:12
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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