Files
metasploit-gs/tools/exploit/find_badchars.rb
T

167 lines
4.0 KiB
Ruby
Raw Normal View History

2009-12-19 09:57:41 +00:00
#!/usr/bin/env ruby
2018-03-20 11:33:34 +00:00
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
2010-05-03 17:13:09 +00:00
#
2009-12-19 09:57:41 +00:00
# This script is intended to assist an exploit developer in deducing what
# "bad characters" exist for a given input path to a program.
#
msfbase = __FILE__
while File.symlink?(msfbase)
2013-09-30 13:47:53 -05:00
msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
end
2009-12-19 09:57:41 +00:00
2016-07-05 02:33:45 -05:00
gem 'rex-text'
2015-10-06 10:30:52 -05:00
$:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib')))
2012-04-15 23:35:38 -05:00
require 'msfenv'
$:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']
2009-12-19 09:57:41 +00:00
require 'rex'
OutStatus = "[*] "
OutError = "[-] "
$args = Rex::Parser::Arguments.new(
2013-09-30 13:47:53 -05:00
"-b" => [ true, "The list of characters to avoid: '\\x00\\xff'" ],
"-h" => [ false, "Help banner" ],
"-i" => [ true, "Read memory contents from the supplied file path" ],
"-t" => [ true, "The format that the memory contents are in (empty to list)" ])
2009-12-19 09:57:41 +00:00
def usage
2013-09-30 13:47:53 -05:00
$stderr.puts("\n" + " Usage: #{File.basename($0)} <options>\n" + $args.usage)
exit
2009-12-19 09:57:41 +00:00
end
def show_format_list
2013-09-30 13:47:53 -05:00
$stderr.puts("Supported formats:\n")
$stderr.puts(" raw raw binary data\n")
$stderr.puts(" windbg output from windbg's \"db\" command\n")
$stderr.puts(" gdb output from gdb's \"x/bx\" command\n")
$stderr.puts(" hex hex bytes like \"\\xFF\\x41\" or \"eb fe\"\n")
2009-12-19 09:57:41 +00:00
end
def debug_buffer(name, buf)
2013-09-30 13:47:53 -05:00
str = "\n#{buf.length} bytes of "
str << name
str += ":" if buf.length > 0
str += "\n\n"
$stderr.puts str
if buf.length > 0
$stderr.puts Rex::Text.to_hex_dump(buf)
end
2009-12-19 09:57:41 +00:00
end
# Input defaults
badchars = ''
fmt = 'raw'
input = $stdin
# Output
new_badchars = ''
2014-03-04 15:00:48 -06:00
# Parse the argument and rock it
2009-12-19 09:57:41 +00:00
$args.parse(ARGV) { |opt, idx, val|
2013-09-30 13:47:53 -05:00
case opt
when "-i"
begin
input = File.new(val)
rescue
$stderr.puts(OutError + "Failed to open file #{val}: #{$!}")
exit
end
when "-b"
badchars = Rex::Text.dehex(val)
2013-09-30 13:47:53 -05:00
when "-t"
if (val =~ /^(raw|windbg|gdb|hex)$/)
fmt = val
else
if val.nil? or val.length < 1
show_format_list
else
$stderr.puts(OutError + "Invalid format: #{val}")
end
exit
end
when "-h"
usage
end
2009-12-19 09:57:41 +00:00
}
if input == $stdin
2013-09-30 13:47:53 -05:00
$stderr.puts(OutStatus + "Please paste the memory contents in \"" + fmt + "\" format below (end with EOF):\n")
2009-12-19 09:57:41 +00:00
end
# Working data set
from_msf = Rex::Text.charset_exclude(badchars)
from_dbg = ''
# Process the input
from_dbg = input.read
case fmt
2013-09-30 13:47:53 -05:00
when "raw"
# this should already be in the correct format :)
when "windbg"
translated = ''
from_dbg.each_line do |ln|
translated << ln.chomp[10,47].gsub!(/(-| )/, '')
end
from_dbg = Rex::Text.hex_to_raw(translated)
2016-07-05 02:33:45 -05:00
2013-09-30 13:47:53 -05:00
when "gdb"
translated = ''
from_dbg.each_line do |ln|
translated << ln.chomp.split(':')[1].gsub!(/0x/, '\x').gsub!(/ /, '')
end
from_dbg = Rex::Text.hex_to_raw(translated)
when "hex"
translated = ''
from_dbg.each_line do |ln|
translated << ln.chomp.gsub!(/ /,'')
end
from_dbg = Rex::Text.hex_to_raw(translated)
2009-12-19 09:57:41 +00:00
end
=begin
# Uncomment these to debug stuff ..
debug_buffer("BadChars", badchars)
debug_buffer("memory contents", from_dbg)
debug_buffer("Rex::Text.charset_exclude() output", from_msf)
=end
# Find differences between the two data sets
2011-07-05 16:22:39 +00:00
from_msf = from_msf.unpack('C*')
from_dbg = from_dbg.unpack('C*')
2009-12-19 09:57:41 +00:00
minlen = from_msf.length
minlen = from_dbg.length if from_dbg.length < minlen
(0..(minlen-1)).each do |idx|
2013-09-30 13:47:53 -05:00
ch1 = from_msf[idx]
ch2 = from_dbg[idx]
if ch1 != ch2
str = "Byte at index 0x%04x differs (0x%02x became 0x%02x)" % [idx, ch1, ch2]
$stderr.puts OutStatus + str
new_badchars << ch1
end
2009-12-19 09:57:41 +00:00
end
# show the results
if new_badchars.length < 1
2013-09-30 13:47:53 -05:00
$stderr.puts(OutStatus + "All characters matched, no new bad characters discovered.")
2009-12-19 09:57:41 +00:00
else
2013-09-30 13:47:53 -05:00
$stderr.puts(OutStatus + "Proposed BadChars: \"" + Rex::Text.to_hex(new_badchars) + "\"")
2009-12-19 09:57:41 +00:00
end