#!/usr/local/bin/perl # File: ppcap.pl use Net::Pcap qw(pcap_open_offline pcap_loop); use Net::Packet; use NetPacket::Ethernet qw(:ALL); use NetPacket::IP qw(:ALL); use NetPacket::TCP; use Config::Auto; use Data::Dumper; # ########################################################################## # Read and process config info. This code simply reads in various settings # from a flat text file. It makes it easier to change the way the code # runs without actually having to edit the code. We might not even use # all of the vars, but we'll read them all just in case. # ########################################################################## my $startTime = time; my $config = Config::Auto::parse("./ppcap.conf"); my $debug = $config->{debugLevel}; my $capFile = $config->{defaultCapFile}; my $synExpected = $config->{synExpected}; my $senderAddr = $config->{senderAddress}; my $receiverAddr = $config->{receiverAddress}; # ########################################################################## # If the user specified a pcap capture file on the command line, then # we'll use it, otherwise, we'll use the one specified as the default # in the conf file. # ########################################################################## if ($ARGV[0]) { $capFile = $ARGV[0]; } # ########################################################################## # Now open the pcap file and process each line. # ########################################################################## my $pcap = pcap_open_offline($capFile,\$error_msg); print "###############################################################\n"; print "Opened $capFile\n"; print "###############################################################\n"; my $packetCount = 1; pcap_loop($pcap, -1, \&process_packet, "user data"); print "###############################################################\n"; my $endTime = time; my $totalTime = $endTime - $startTime; print "Analysis completed in $totalTime seconds\n"; exit; # ########################################################################## # # Subroutine: process_packet # # As with any Net::Pcap program, this is the routine that does all the # work. It will be called once for each packet in the trace. # # Valid NetPacket::TCP fields (with sample values) are: # 'hlen' => 5, # 'urg' => 0, # '_parent' => undef, # 'src_port' => 2182, # 'flags' => 24, # 'options' => '', # 'seqnum' => 722539488, # 'data' => 'somedataastextstring', # 'cksum' => 7802, # 'winsize' => 64402, # 'acknum' => 1583632711, # '_frame' => '', # 'dest_port' => 3025, # 'reserved' => 0 # # Valid NetPacket::IP fields (with sample values) are: # 'len' => 54, # 'dest_ip' => '192.168.23.2', # 'options' => '', # 'ttl' => 128, # 'src_ip' => '192.168.23.129', # 'tos' => 0, # 'id' => 296, # '_parent' => undef, # 'hlen' => 5, # 'proto' => 17, # 'foffset' => 0, # 'flags' => 0, # 'ver' => 4, # 'cksum' => 35259, # 'data' => 'somedataastextstring', # '_frame' => '' # sub process_packet { my ($user_data, $header, $raw_pkt) = @_; my $IPinfo = NetPacket::IP->decode(eth_strip($raw_pkt)); my $TCPinfo = NetPacket::TCP->decode( NetPacket::IP::strip(NetPacket::Ethernet::strip($raw_pkt))); # ###################################################################### # Now we have a packet in both IP and TCP versions (see above for 'field' # names. # ###################################################################### if (($IPinfo->{'proto'} == IP_PROTO_TCP) && $debug) { print "Packet $packetCount Looks like a TCP packet\n"; } my $dataLength = length($TCPinfo->{'data'}); my $sourceAddr = $IPinfo->{'src_ip'}; my $destAddr = $IPinfo->{'dest_ip'}; my $sourcePort = $TCPinfo->{'src_port'}; my $destPort = $TCPinfo->{'dest_port'}; if ($TCPinfo->{'data'} =~ /\x4d\x5a/) { print "Possible program (MZ Signature) at packet $packetCount, packet from $sourceAddr to $destAddr\n"; if ($debug) { dumpData($TCPinfo->{'data'},$dataLength); } } if ($TCPinfo->{'data'} =~ /This program cannot be run in DOS mode/) { print "Found program (DOS Stub) at packet $packetCount, packet from $sourceAddr to $destAddr\n"; if ($debug) { dumpData($TCPinfo->{'data'},$dataLength); } } if ($TCPinfo->{'data'} =~ /jar/i) { print "Found possible java applet at packet $packetCount, packet from $sourceAddr to $destAddr\n"; if ($debug) { dumpData($TCPinfo->{'data'},$dataLength); } } $packetCount++; } # ########################################################################## # # Subroutine: dumpData # # ########################################################################## sub dumpData { my ($data, $dataLength) = @_; my $packetPointer = 0; while ($packetPointer < $dataLength) { my $dataSegment = substr($data, $packetPointer, 16); printf ("# %.4X : ", $packetPointer); my $i = 0; print map ($i++ % 16 ? "$_ " : " $_ ", unpack ('H2 ' x 16,$dataSegment) ); $dataSegment =~ s/[\x00-\x1f\x7f-\xff]/./g; print " $dataSegment\n"; $packetPointer += 16; } print "\n" }