#!/usr/bin/perl -w

# A quick decoder for captured network data, for the Reverse Challenge.
# Requires tcpdump to be in the current path.
#
# Dion Mendel 27th May 2002


use strict;

if (scalar @ARGV != 1) {
   print "Usage: $0 <capture file>\n";
   print "Decodes a tcpdump style capture file for the Reverse Challenge\n";
   exit 1;
}

my $filename = $ARGV[0];
my @packets = &get_packets($filename);

my ($pdu, $val, $last, $handler_to_agent, @decoded);

foreach $pdu (@packets) {
   # ensure these packets use the protocol
   next unless (($pdu->[20] == 2) or ($pdu->[20] == 3));

   # print IP addresses and direction
   printf "%d.%d.%d.%d -> %d.%d.%d.%d ",
          $pdu->[12], $pdu->[13], $pdu->[14], $pdu->[15],
          $pdu->[16], $pdu->[17], $pdu->[18], $pdu->[19];
   $handler_to_agent = $pdu->[20] == 2;
   printf "(%s)\n", $handler_to_agent ? "handler -> agent" : "agent -> handler";

   # decode data
   $last = scalar(@$pdu) - 1;
   @decoded = &decode(@$pdu[22..$last]);

   # dump packet
   &dump($handler_to_agent, @decoded);
   print "----------------------------------------------------------------\n";
}

exit (0);

# Dumps the details of decoded packets.
sub dump($@)
{
   my ($to_agent, @data) = @_;
   my ($cmd, $port, $str);

   $cmd = $data[1];
   if ($to_agent) {
      if ($cmd == 1) {
         printf "Request for status report.\n";
      }
      elsif ($cmd == 2) {
         printf "Initialise agent.\n", $data[2];
         if ($data[2] == 0) {
            printf("All replies are sent to handler at %d.%d.%d.%d\n",
                   $data[3], $data[4], $data[4], $data[6]);
         }
         elsif ($data[2] == 2) {
            printf("All replies are to be sent to handlers at:\n" .
                   "%d.%d.%d.%d\n" .
                   "%d.%d.%d.%d\n" .
                   "%d.%d.%d.%d\n" .
                   "%d.%d.%d.%d\n" .
                   "%d.%d.%d.%d\n" .
                   "%d.%d.%d.%d\n" .
                   "%d.%d.%d.%d\n" .
                   "%d.%d.%d.%d\n" .
                   "%d.%d.%d.%d\n" .
                   "%d.%d.%d.%d\n",
                   $data[3], $data[4], $data[5], $data[6],
                   $data[7], $data[8], $data[9], $data[10],
                   $data[11], $data[12], $data[13], $data[14],
                   $data[15], $data[16], $data[17], $data[18],
                   $data[19], $data[20], $data[21], $data[22],
                   $data[23], $data[24], $data[25], $data[26],
                   $data[27], $data[28], $data[29], $data[30],
                   $data[31], $data[32], $data[33], $data[34],
                   $data[35], $data[36], $data[37], $data[38],
                   $data[39], $data[40], $data[41], $data[42]);
         }
         else {
            printf("All replies are sent to handler at %d.%d.%d.%d\n" .
                   "(plus 9 other randomly generated hosts)\n",
                   $data[3], $data[4], $data[4], $data[6]);
         }

      }
      elsif ($cmd == 3) {
         $str = pack("C*", @data[2..$#data]);
         $str = substr($str, 0, index($str, "\0"));
         printf("Execute the given command and send output to handler:\n%s\n",
                $str);
      }
      elsif ($cmd == 4) {
         $port = ($data[6] << 8) + $data[7];
         if ($data[8] != 0) {
            $str = pack("C*", @data[9..$#data]);
            $str = substr($str, 0, index($str, "\0"));
            printf("Perform custom DNS flood on victim %s,\n" .
                   "using spoofed source port %d\n", $str, $port);
         }
         else {
            printf("Perform custom DNS flood on victim %d.%d.%d.%d,\n" .
                   "using spoofed source port %d\n",
                   $data[2], $data[3], $data[4], $data[5], $port);
         }
      }
      elsif ($cmd == 5) {
         $port = ($data[6] << 8) + $data[7];
         if ($data[12] != 0) {
            $str = pack("C*", @data[13..$#data]);
            $str = substr($str, 0, index($str, "\0"));
            printf("Perform jolt2 attack on victim %s,\n", $str);
         }
         else {
            printf("Perform jolt2 attack on victim %d.%d.%d.%d,\n",
                   $data[4], $data[5], $data[6], $data[7]);
         }
         if ($data[2] != 0) {
            printf("using udp port %d,\n", $data[3]);
         }
         else {
            printf("using icmp,\n");
         }
         printf("and spoofed source IP of %d.%d.%d.%d\n",
                $data[8], $data[9], $data[10], $data[11]);
      }
      elsif ($cmd == 6) {
         printf("open a backdoor root shell\n" .
                "(default port is 23281 and default password is SeNiF)\n");
      }
      elsif ($cmd == 7) {
         $str = pack("C*", @data[2..$#data]);
         $str = substr($str, 0, index($str, "\0"));
         printf("Execute the given command, " .
                "do not send output to handler:\n%s\n", $str);
      }
      elsif ($cmd == 8) {
         printf("Terminate current action (if any)\n");
      }
      elsif ($cmd == 9) {
         $port = ($data[7] << 8) + $data[8];
         if ($data[9] != 0) {
            $str = pack("C*", @data[10..$#data]);
            $str = substr($str, 0, index($str, "\0"));
            printf("Perform custom DNS flood on victim %s,\n" .
                   "using spoofed source port %d and parameter %d\n",
                   $str, $port, $data[6]);
         }
         else {
            printf("Perform custom DNS flood on victim %d.%d.%d.%d,\n" .
                   "using spoofed source port %d and parameter %d\n",
                   $data[2], $data[3], $data[4], $data[5], $port, $data[6]);
         }
      }
      elsif ($cmd == 10) {
         $port = ($data[6] << 8) + $data[7];
         if ($data[13] != 0) {
            $str = pack("C*", @data[14..$#data]);
            $str = substr($str, 0, index($str, "\0"));
            printf("Perform synflood on victim %s\n", $str);
         }
         else {
            printf("Perform synflood on victim %d.%d.%d.%d\n",
                   $data[2], $data[3], $data[4], $data[5]);
         }
         printf("using port %d,\n", $port);
         if ($data[8] != 0) {
            printf("using spoofed source IP address %d.%d.%d.%d\n",
                   $data[9], $data[10], $data[11], $data[12]);
         }
         else {
            printf("using random spoofed source IP addresses\n");
         }
      }
      elsif ($cmd == 11) {
         $port = ($data[6] << 8) + $data[7];
         if ($data[14] != 0) {
            $str = pack("C*", @data[15..$#data]);
            $str = substr($str, 0, index($str, "\0"));
            printf("Perform synflood on victim %s\n", $str);
         }
         else {
            printf("Perform synflood on victim %d.%d.%d.%d\n",
                   $data[2], $data[3], $data[4], $data[5]);
         }
         printf("using port %d and parameter %d\n", $port, $data[13]);
         if ($data[8] != 0) {
            printf("using spoofed source IP address %d.%d.%d.%d\n",
                   $data[9], $data[10], $data[11], $data[12]);
         }
         else {
            printf("using random spoofed source IP addresses\n");
         }
      }
      elsif ($cmd == 12) {
         $port = ($data[11] << 8) + $data[12];
         if ($data[13] != 0) {
            $str = pack("C*", @data[14..$#data]);
            $str = substr($str, 0, index($str, "\0"));
            printf("Perform custom DNS flood (using dns server %s)\n", $str);
         }
         else {
            printf("Perform custom DNS flood (using dns server %d.%d.%d.%d)\n",
                   $data[2], $data[3], $data[4], $data[5]);
         }
         printf("on victim %d.%d.%d.%d\n" .
                "using spoofed source port %d,\n" .
                "and parameter %d\n",
                $data[6], $data[7], $data[8], $data[9], $port, $data[10]);
      }
   }
   else {
      if ($cmd == 1) {
         if ($data[3] == 1) {
            printf "agent is currently executing task: %s\n",
                   &task_name($data[4]);
         }
         else {
            printf "agent is not executing any task\n";
         }

      }
      elsif ($cmd == 3) {
         printf "output of command executed by agent:\n";
         $str = pack("C*", @data[2..$#data]);
         $str = substr($str, 0, index($str, "\0"));
         printf "%s\n", $str;
      }
      elsif ($cmd == 4) {
         $str = pack("C*", @data[2..$#data]);
         $str = substr($str, 0, index($str, "\0"));
         if (length($str) == 1) {
            printf "continuing output of command executed by agent:%s\n";
         }
         else {
            printf "end of output of command executed by agent\n";
         }
      }
   }
}

# Returns human readable string of possible tasks.
sub task_name($)
{
   my ($number) = @_;
   return "no task" if $number == 0;
   return "custom dns flood" if $number == 4;
   return "jolt 2 attack" if $number == 5;
   return "providing backdoor" if $number == 6;
   return "custom dns flood" if $number == 9;
   return "syn flood" if $number == 10;
   return "syn flood" if $number == 11;
   return "custom dns flood (with specified DNS server)" if $number == 12;
   return "unknown";
}

# Function to decode a given array.
sub decode(@)
{
   my (@src) = @_;
   my ($i, $val, @dst);

   @dst = ();
   for ($i = $#src; $i >= 1; $i--) {
      $val = $src[$i] - ($src[$i - 1] + 23);
      while ($val < 0) {
         $val += 256;
      }
      $dst[$i] = $val;
   }
   $val = $src[0] - 23;
   while ($val < 0) {
      $val += 256;
   }
   $dst[0] = $val;

   return @dst;
}

# Returns list of packets from a tcpdump file.  Packets are returned as
# an array of integers.
sub get_packets($)
{
   my (@filename) = @_;
   my (@output, @text_packets, @packets, @tmp, $line, $packet, $grab);

   @output = `tcpdump -n -x -r $filename`;

   @text_packets = ();
   $packet = "";
   $grab = 0; 
   foreach $line (@output) {
      chomp($line);
      if ($line =~ /^\S/) {
         if ($line =~ /ip-proto-11/) {
            $grab = 1;
            if ($packet ne "") {
               push @text_packets, $packet;
               $packet = "";
            }
         }
         else {
            $grab = 0;
         }
      }
      elsif ($grab) {
         $packet .= $line;
      }
   }
   if ($packet ne "") {
      push @text_packets, $packet;
      $packet = "";
   }

   # *sigh* there must be a better way to do this
   @packets = ();
   foreach $packet (@text_packets) {
      $packet =~ s/\s//g;
      @tmp = unpack "a2" x (length($packet) / 2), $packet;
      my @pdu = map { oct('0x' . $_) } @tmp;
      push @packets, \@pdu;
   }
   return @packets;
}

