#!/usr/bin/perl #First file finish on frame ~803 - after that is some client server communication #Second file finish on frame ~2347 - after that is some client server communication #Both files are identical. #frame #16 contains the file length 00 6a 0b 00 .j.. use strict; use warnings; use Getopt::Long; use Pod::Usage; use Net::Pcap; use NetPacket::Ethernet; use NetPacket::IP; use NetPacket::TCP; use NetPacket::UDP; use Digest::MD5 qw(md5 md5_hex md5_base64); my $file; my $filter = 'tcp'; #only tcp frames my $is_verbose = 0; my $index = 1; my $err; my $packets; my $filter_c; my $start = 0; my $size = 0; my $curentSize = 0; my $curentFile = 0; my $ack=0; my $srcPort = 4444; my @pkts = ( ); my @headers = ( ); my %cSeq=(); print_md5("index.php"); print_md5("index.phpmfKSxSANkeTeNrah.gif"); get_arguments(); print_md5($file); # start reading the file $packets = Net::Pcap::open_offline( $file, \$err ); if( defined $err ) { die 'Unable to read the PCAP file ' . $err . "\n"; } # create the filter Net::Pcap::compile( $packets, \$filter_c, $filter, 0, -1 ); Net::Pcap::setfilter( $packets, $filter_c ); Net::Pcap::loop( $packets, -1, \&save_files, '' ); Net::Pcap::close( $packets ); print "Packets: [",scalar(@pkts),"]\n"; if($is_verbose) { resolvePuzzle(); } my $i; for($i = 1; $i <= $curentFile; $i++) { print_md5("file_$i.pe"); } print "\nFinished\n"; sub resolvePuzzle { my $j=0; my %hashTable = (); my $startDate = $headers[0]->{'tv_sec'}; for($j = 0; $j < scalar(@pkts); $j++) { my $ether = NetPacket::Ethernet->decode(($pkts[$j])); my $ip = NetPacket::IP->decode( $ether->{'data'} ); my $trans = NetPacket::TCP->decode( $ip->{'data'} ); my $fcheck = $trans->{'flags'}; my $FinAck = 0x10 | 0x01; my $Syn = 0x02; my $SynAck = 0x02 | 0x10; my $currentKey = $ip->{'src_ip'}.":".$trans->{'dest_port'}; if(($fcheck & $FinAck) == $FinAck) { my $source = $ip->{'src_ip'}.":".$trans->{'src_port'}; my $destination = $ip->{'dest_ip'}.":".$trans->{'dest_port'}; print "[", $j + 2 ,"] -> FIN ACK found. Connection closed [$source -> $destination]\n"; } if(($fcheck & $Syn) == $Syn) { if(not exists $cSeq{$currentKey}) { initData(0,$ip->{'id'},$headers[$j]->{'tv_sec'},$currentKey); initData(3,$trans->{'seqnum'},$headers[$j]->{'tv_sec'},$currentKey); initData(6,$trans->{'src_port'},$headers[$j]->{'tv_sec'},$currentKey); } processData("IP identification", 0, $ip->{'id'}, $headers[$j]->{'tv_sec'}, $j+2, $currentKey); processData("Sequence number", 3, $trans->{'seqnum'}, $headers[$j]->{'tv_sec'}, $j+2, $currentKey); processData("Source port", 6,$trans->{'src_port'}, $headers[$j]->{'tv_sec'}, $j+2, $currentKey); } if(($fcheck & $SynAck) == $SynAck) { print "[", $j + 2 ,"] -> SYN ACK found.\n"; } if(exists $hashTable{$ip->{'src_ip'}}) { $hashTable{$ip->{'src_ip'}} += 1; } else { $hashTable{$ip->{'src_ip'}} = 1; } } my $key; foreach $key (keys %hashTable) { print "[$hashTable{$key}] packet(s) from $key\n"; } } sub initData { my $id = shift; my $value = shift; my $sec = shift; my $currentKey = shift; if(not defined $cSeq{$currentKey}) { $cSeq{$currentKey} = (); } $cSeq{$currentKey}[$id] = $value; $cSeq{$currentKey}[$id+1] = 0; $cSeq{$currentKey}[$id+2] = $sec; } sub processData { my $name = shift; my $id = shift; my $value = shift; my $sec = shift; my $packetNo = shift; my $currentKey = shift; if(defined $value && $cSeq{$currentKey}[$id] != $value) { print "[", $packetNo,"] -> ",$currentKey," -> $name changed from [",$cSeq{$currentKey}[$id],"] to [", $value, "]. Count [",$cSeq{$currentKey}[$id+1],"], seconds [",$sec - $cSeq{$currentKey}[$id+2],"].\n"; $cSeq{$currentKey}[$id] = $value; $cSeq{$currentKey}[$id+1] = 1; $cSeq{$currentKey}[$id+2] = $sec; } else { $cSeq{$currentKey}[$id+1] += 1; } } sub get_arguments { GetOptions("source=s"=>\$file, "verbose!"=>\$is_verbose); if(( not defined($file)) || (not -e $file )) { die 'File expected! Use -s '; } } sub print_md5 { my $filename = shift; if(-e $filename) { my $digest = get_md5($filename); print "Filename [$filename], MD5 [$digest]\n"; } else { print "File [$filename] not found.\n" } } sub get_md5 { my $filename = shift; my $ctx; my $digest; open (MYFILE, $filename); $ctx = Digest::MD5->new; $ctx->addfile(*MYFILE); $digest = $ctx->hexdigest; close (MYFILE); return $digest; } sub save_files { my $user_data = shift; my $header = shift; my $pack = shift; my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst); my $tcpData; my $psize; my $csize; my $dsize; my ($ether,$ip,$trans); my $fcheck; $index++; # strip header information $ether = NetPacket::Ethernet->decode( $pack ); $ip = NetPacket::IP->decode( $ether->{'data'} ); $trans = NetPacket::TCP->decode( $ip->{'data'} ); push(@pkts, $pack); push(@headers, $header); if($trans->{'src_port'}== $srcPort) { $fcheck = $trans->{'flags'}; $tcpData = $trans->{'data'}; $psize = $header->{'len'}; $csize = $header->{'caplen'}; $dsize = 0; if($tcpData ne '') { if( $start < 1) { print "ACK flag found:", $fcheck, "\n"; print "ACK sq num: $trans->{'acknum'}\n"; $curentFile++; $start = 1; #the first pachet sent contains the size of the file $size = vec(reverse($tcpData),0,length($tcpData) * 0x08); my $str = "file_$curentFile.pe"; print "[$index] -> Found file size (",length($tcpData),"): $size.\n"; print "\tDumping packets to $str.\n"; open (MYFILE, ">$str"); } else { $curentSize += length($tcpData); if($curentSize <= $size) { if($ack != $trans->{'acknum'}) { close (MYFILE); die "WARNING: Worng ack, expected [$ack], curent [$trans->{'acknum'}].\n"; } print MYFILE $tcpData; } if($curentSize == $size) { close (MYFILE); print "\t[$index] -> File dump finished length [$curentSize].\n"; } } } if(($fcheck & 0x10) == 0x10) { $ack = $trans->{'acknum'}; } if(($fcheck & 0x01) == 0x01 && ($fcheck & 0x10) == 0x10 ) #FIN ACK { $srcPort = 4445; print "\t[$index] --> FIN & ACK found. Changing port.\n"; $start = 0; $curentSize = 0; $size = 0; } } } 0; __END__