#! /usr/bin/perl -w # Network Forensics Puzzle Contest #3 # Alan Tu # January 16, 2010 # http_rx.pl v1.01 # Extracts HTTP response bodies from output of either "Follow TCP Stream" in Wireshark or stream.pl # Usage: http_rx.pl filename # Outputs the response bodies to filename.1, filename.2, etc use strict; use HTTP::Response; # use this module to parse the HTTP response content use Digest::MD5; my $fn = shift or die "Usage: $0 filename\n"; die "$fn does not exist\n" unless -f $fn; open(IN, $fn) or die "$!\n"; binmode(IN); local $/ = undef; # slurp the whole file my $data = ; close(IN); my $message = 1; # the number of the current HTTP response message my $ptr = 0; # pointer to the beginning of the current message while ($ptr < length($data)) { my $r = HTTP::Response->parse(substr($data, $ptr)); # create HTTP::Response object my $l = $r->header("content-length"); # get the content-length if specified my $message_offset = index(substr($data, $ptr), "\x0d\x0a\x0d\x0a") + 4; # start of the HTTP content $l = 0 if $r->code == 304; # no data for 304 responses if (defined($l)) # content length is known { $r = HTTP::Response->parse(substr($data, $ptr, $message_offset + $l)); # recreate HTTP::Response object of the correct length } my $c = $r->decoded_content; open(OUT, ">$fn.$message"); # print out the decoded HTTP response binmode(OUT); print OUT $c; printf(STDERR "Writing file %s, length %d bytes, MD5 hash %s\n", "$fn.$message", length($c), Digest::MD5::md5_hex($c)); close(OUT); exit unless defined($l); # if no length was specified, nothing more to do $ptr += $message_offset + $l; # skip past the HTTP header and past the current message to the next one $message++; }