#!/usr/bin/perl
#
# FendIIS.pl
# Scans a C or B class network (can also takes ip addresses from a file) 
# for hosts infected with the Code Red II worm. It does this by checking for the
# presence of /scripts/root.exe which is the backdoor Code Red II leaves behind.
#
# Pings the host then if the host is alive sends a HEAD http method and analizes 
# the response to see if the server is running IIS. If so then it continues to 
# scan for /scripts/root.exe if not it does not scan, dubs the host not 
# infected and moves onto the next one.
#
# Purpose: 
# If you are managing a large network and need to identify weak links in the 
# chain that are infected with Code Red II, this is the tool for the job.
# 
# Usage:
# chmod 755 FendIIS.pl
# ./FendIIS.pl
#
# Author:  Matt 'Zola' Stevens.
# Contact: Zola@hackermail.com
#

#use strict;
#use warnings;
use Net::Ping;
use IO::Socket;
use Getopt::Long;

my $ping = Net::Ping->new($> ? 'tcp' : 'icmp', 1);
my $padding = 30;
my $single;
my $range;
my $file;

GetOptions(
    'r=s' => \$range,
    'f=s' => \$file,
    's=s' => \$single
);

usage() unless ($range || $file || $single);
    
if ($range) {
    usage() if ($file || $single);
    if ($range !~ /\d+\.\d+\.\d+\.\d+/) {
        print "Wrong format for range. See usage.\n";
        exit 1;
    }
    range($range);
}

if ($file) {
    usage() if ($range || $single);
    unless (-e $file) {
        print "File does not exit.\n";
        exit 1;
    }
    file();
}

if ($single) {
    usage() if ($range || $file);
    if ($single !~ /\d+\.\d+\.\d+\.\d+/) {
        print "Wrong format for ip address. See usage.\n";
        exit 1;
    }
    single();
}

sub range {
    my @octet = split(/\./, $_[0]);
    my $count = 0;
    my $i;
    my $j;

    if ($octet[3] == 255) {
        if ($octet[2] == 255) {
            usage() if (($octet[0] || $octet[1]) == 255);
            for ($i = 1;$i < 255;$i++) {
                for ($j = 1;$j < 255;$j++) {
                    if (probe("$octet[0].$octet[1].$i.$j")) {
                        $count++;
                    }
                }
            }
            results($count);
        } else {
            for ($i = 1;$i < 255;$i++) {
                if (probe("$octet[0].$octet[1].$octet[2].$i")) {
                    $count++;
                }
            }
            results($count);
        }
    } else {
        usage();
    }
}

sub file {
    my $count = 0;

    open(FILE, "<$file") || die "Could not open $file for reading: $!\n";
    
    while (<FILE>) {
        if (/(\d+\.\d+\.\d+\.\d+)/) {
            if (probe($1)) {
                $count++;
            }
        }
    }

    close(FILE);

    results($count);
}

sub single {
    my $count = 0;    

    if (probe($single)) {
        $count++;
    }

    results($count);
}

sub results {
    print "\nScan Complete.\n";
    if ($_[0] == 1) {
        print "Found one infected and vulnerable system.\n";
    } elsif ($_[0] > 1) {
        print "Found $_[0] infected and vulnerable systems.\n";
    } else {
        print "Could not find any infected or vulnerable systems.\n";
    }
}

# The meat and bones of this program.
sub probe {
    my $string = '/scripts/root.exe?/c+dir';
    my $node = $_[0];
    my $vuln = undef;
    my $iis  = undef;
    my $socket;

    print "Testing $node";
    print '.' x ($padding - length($node));

    unless ($ping->ping($node)) {
        print "not infected\n";
        return;
    }

    $socket = IO::Socket::INET->new(Proto    => 'tcp',
                                    PeerAddr => $node,
                                    PeerPort => 80);

    unless (defined $socket) {
        print "not infected\n";
        return;
    }

    print $socket "HEAD / HTTP/1.0\r\n\r\n";

    while (<$socket>) {
        if (/IIS/) {
            $iis = 1;
        }
    }

    close $socket;

    unless (defined $iis) {
        print "not infected\n";
        return;
    }

    $socket = IO::Socket::INET->new(Proto    => 'tcp',
                                    PeerAddr => $node,
                                    PeerPort => 80);
    
    print $socket "GET $string HTTP/1.0\r\n\r\n";

    while (<$socket>) {
        if (/<DIR>/) {
            $vuln = 1;
        }
    }

    close $socket;

    unless (defined $vuln) {
        print "not infected\n";
        return;
    }

    print "Infected and Vulnerable!\n";
    return 1;
}

sub usage {
    die "
    Usage:
        perl $0 [option][range/file]

    Options:
        -r  : Scan a C or a B class range
        -f  : Scan ip addresses from a file
        -s  : Scan a single hostname/ip

    Examples:
        Scan a C class
        perl $0 -r 192.168.1.255

        Scan a B class
        perl $0 -r 192.168.255.255

        Scan all hosts/ips in a file
        perl $0 -f ip-addresses.txt

        Probe a single host/ip
        perl $0 -s 192.168.1.14
    
    Note:
        You can not use more than one option at a time.\n";
}