In the Internet age we live in, it’s not uncommon for web servers to be hit with Unintentional, not so Distributed, Denial of Service (DoS) Attacks. The attacks itself is intentional, but it’s not trying to bring down the server. It’s just some stupid ‘bot running a probe as fast as it can and, as a side effect, bogging down your server.

Bots are evil, but at least smart bots rate limit themselves to keep off the radar.

The typical stupid bot is running a password probe against an admin login. If you run any WordPress sites, you see this. All. The. Time. There are many good options to prevent these attacks, including renaming well known URLs, IP filtering, and automatic IP banning software, like Fail2ban.

However, sometime you just need to make the attack go away now. For that, I have a couple of Bash functions/tcsh alias.

Finding the Bad Guy

The first step is to find the source of the attack. It works by pulling all of the IP addresses out of the web server log and sorting them by frequency. If an IP is hitting you hard enough to bog down your server then it’s going to appear often in the log.

The IP address making the request is the first field in most common web server log formats, so we pull it out with awk '{ print $1 }' access_log. Next we sort all of the the IPs and pass them to uniq -c which counts up the unique lines in it’s input. Finally, we pass the output of uniq in to sort -nr, which sorts it numerically, and pipe that in to head to give us the first 20 lines.

All together it looks like:

1
awk '{print $1 }' access_log | sort | uniq -c | sort -nr | head -20

And outputs is a list of IPs preceded by the number of times they appear in the log.

1
2
3
4
5
6
7
8
9
10
5076 10.112.144.129
1953 192.168.30.7
1496 10.161.138.191
1471 10.211.158.44
1458 192.168.168.180
1081 192.168.34.67
1057 10.169.27.153
 952 10.56.27.175
 842 192.168.158.86
 807 192.168.250.140

It’s pretty safe to say that an IP that appears thousands of times isn’t legit (WARNING: this is not true, and this post is not useful if your server is behind a proxy. You’ll just be seeing the proxy’s IP(s) for everything). Found a bad guy? Let’s block ‘em.

Blocking IPs on Linux

On Linux, the route command can be use with the reject option cause routing for a IP or network to fail. For an IP, it’s:

1
/sbin/route add -host 10.10.10.1 reject

For a network, it’s:

1
/sbin/route add -net 10.10.10.0 netmask 255.255.255.0 reject

Blocking IPs on FreeBSD

FreeBSD has a blackhole option to route that will drop traffic from an IP or network on the floor. For a single IP it’s:

1
/sbin/route add 10.10.10.1 127.0.0.1 -blackhole

For a network it’s:

1
/sbin/route add 10.10.10.0/24 127.0.0.1 -blackhole

Removing a block

Typically, I leave blocked things blocked. It’s not worth my time to clean them up and the block will be removed by the next reboot. However, if you find you’ve blocked something legitimate or just like things tidy, route will remove blocks as well.

Linux:

1
/sbin/route delete 10.10.10.1 reject

FreeBSD:

1
/sbin/route delete 10.10.10.1

Putting it All Together

Here are the Bash functions:

1
2
3
top-ips() { awk '{print $1 }' $@ | sort | uniq -c | sort -nr | head -20; }
ban-ip() { /sbin/route add -host $@ reject; }
bsd-ban-ip() { /sbin/route add $@ 127.0.0.1 -blackhole'; }

and the tcsh aliases:

1
2
3
alias top-ips 'awk '\''{print $1 }'\'' \!^ | sort | uniq -c | sort -nr | head -20'
alias ban-ip '/sbin/route add -host \!^ reject'
alias bsd-ban '/sbin/route add \!^ 127.0.0.1 -blackhole'

Use them as follows:

1
2
3
4
5
6
7
8
9
10
11
12
% top-ips /var/log/apache/access.log
5076 10.112.144.129
1953 192.168.30.7
1496 10.161.138.191
1471 10.211.158.44
1458 192.168.168.180
1081 192.168.34.67
1057 10.169.27.153
 952 10.56.27.175
 842 192.168.158.86
 807 192.168.250.140
% ban-ip 10.112.144.129

As I said at the beginning of this post, there are better long term, automated solutions, but when you need the stupid bot gone and your server back now, these aliases will get the job done.

Comments