Archive for February, 2008

Stupid DDOS attacks – a simple script and common sense

Today we had some fun; a DDOS attack from some kind of botnet. We can hundreds (thousands) of IPs sending something to Apache like;


$MyNick Aando|$Lock EXTENDEDPROT

The new Linux kernel iptables can DROP/REJECT based on strings, but I was not going to recompile and install an experimental kernel for this ‘little problem’, risking more downtime than need-be.

So I used sniffing to detect problems:


tcpdump -n -vvv -i eth0 -A|grep -B 1 $MyNick|grep .80: > /tmp/ip.log

(grepping for port .80: because it is attacking my webserver)

Then a killer perl script to block the offending IPs:


#!/usr/bin/perl

%ips=();
open(F, "tail -f /tmp/ip.log|");
while(){
chomp;
/.*) (d+?.d+?.d+?.d+?)..*?>/;
$ip = $1;
next if $ip=~/127.0.0/;
if (!$ips{$ip}) {
$ips{$ip} = 1;
`iptables -A INPUT -p tcp --source $ip --dport 80 -j REJECT`;
print "$ip blockedn";
}
}
close F;

This’ll do it; server freed up and we could serve again nicely 🙂 No need for recompiling at all!

Apache logs: simple log analyzer in Perl – II

I added top 30 and bandwidth / minute;


#!/usr/bin/perl

# get handler to the logfile
open(LOG_FILE, "tail -f /var/log/httpd/access_log.users|");

# start the main loop
%users = ();
$cp=0;
$ct=time();
while() {
chomp;

$cp = time() + 5*60 if $cp==0;
if (-f "/tmp/killtraffic") {
%users=();
`rm -f /tmp/killtraffic`;
}

my $t1 = time(); # timestamp for checkpointing

my ($dom, $ip, $date, $req, $code, $ref, $client, $in, $out)
= /(.*?) (.*?) .*?[(.*?)] "(.*?)" (.*?) .*?"(.*?)" "(.*?)" (.*?) (.*)/;

my ($method, $uri, $proto) = ($req =~ /(.*?) (.*?) (.*)/);

my $get = 0;
if ($uri =~ /(.*?)?(.*)$/) {
$uri = $1;
$get = $2;
}

my $url = $dom;

if (!$users{$url}) {
$users{$url} = $in + $out;
} else {
$users{$url} = $users{$url} + $in + $out;
}

$cpc = time();
if ( $cpc > $cp ) {
$cp=0;
my $s="";
$m = (time()-$ct) / 60;
$count = 0;
foreach(keys %users) {
$s.=($users{$_}/1024)." kb - ".($users{$_}/1024/$m)." kb/min - ".$_."n";
$count++;
last if $count>30;
}
`echo "Count started $m minutes agon" > /tmp/traffic.log`;
`echo "$s"|sort -n -r >> /tmp/traffic.log`;
}
}


# never get here:
close LOG_FILE;

Apache logs: simple log analyzer in Perl

Get Apache to log your bandwidth by putting in httpd.conf/apache2.conf;

LogFormat “%V %h %l %u %t “%r” %>s %b “%{Referer}i” “%{User-agent}i” %I %O” combined_io
CustomLog /var/log/httpd/access_log.users combined_io

And run the following perl script;


#!/usr/bin/perl

# get handler to the logfile
open(LOG_FILE, "tail -f /var/log/httpd/access_log.users|");

# start the main loop
%users = ();
$cp=0;
while() {
chomp;

$cp = time() + 5*60 if $cp==0; # set to refresh the traffic.log file every 5 min

my $t1 = time(); # timestamp for checkpointing

my ($dom, $ip, $date, $req, $code, $ref, $client, $in, $out)
= /(.*?) (.*?) .*?[(.*?)] "(.*?)" (.*?) .*?"(.*?)" "(.*?)" (.*?) (.*)/;

my ($method, $uri, $proto) = ($req =~ /(.*?) (.*?) (.*)/);

my $get = 0;
if ($uri =~ /(.*?)?(.*)$/) {
$uri = $1;
$get = $2;
}

my $url = $dom;

if (!$users{$url}) {
$users{$url} = $in + $out;
} else {
$users{$url} = $users{$url} + $in + $out;
}

$cpc = time();
if ( $cpc > $cp ) {
$cp=0;
my $s = "";
foreach(keys %users) {
$s.=($users{$_}/1024)." kb - ".$_."n";
}
`echo "$s"|sort -n -r > /tmp/traffic.log`;
}
}


# never get here:
close LOG_FILE;

By viewing /tmp/traffic.log, you’ll see what/who is using most traffic.

A better killall and such

Didn’t you sometimes wish you had a ‘superkill’; a kill that kills all processes with a certain text in it. Killall is supposed to do that, but actually never does, as you have to type the complete command which is a pain. So I usually type:

ps auxw|grep -i apache|awk ‘{print $2}’|xargs kill -9

in this case killing Apache (1 and 2).

To make life easier, as a regular part of my Debian and Ubuntu installs, I now have the command ‘sk’ (superkill) in /usr/sbin/sk;

#!/bin/sh

ps uaxw|grep -i $1|grep -v $0|grep -v grep|awk ‘{print $2}’|xargs kill -9

allowing me to run;

sk apache

and gone it is.

Now that I am writing this anyway; here is another missing command 🙂

find /some/directory -maxdepth 1 -type f -mtime +2 -exec rm {} ;

Into a file /usr/sbin/ro;

#!/bin/sh

find $1 -maxdepth 1 -type f -mtime +$2 -exec rm {} ;