Adds a basic fuzzing mixin, as well as a TDS username fuzzer to demonstrate usage
git-svn-id: file:///home/svn/framework3/trunk@7241 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
acf1b2eda7
commit
cae0d61491
|
@ -12,14 +12,7 @@ module Msf
|
|||
###
|
||||
class Auxiliary < Msf::Module
|
||||
|
||||
#
|
||||
# Auxiliary mixins
|
||||
#
|
||||
require 'msf/core/auxiliary/scanner'
|
||||
require 'msf/core/auxiliary/report'
|
||||
require 'msf/core/auxiliary/dos'
|
||||
require 'msf/core/auxiliary/timed'
|
||||
require 'msf/core/auxiliary/wmapmodule'
|
||||
require 'msf/core/auxiliary/mixins'
|
||||
|
||||
#
|
||||
# Returns MODULE_AUX to indicate that this is an auxiliary module.
|
||||
|
|
|
@ -0,0 +1,285 @@
|
|||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# This module provides methods useful for developing fuzzers
|
||||
#
|
||||
###
|
||||
module Auxiliary::Fuzzer
|
||||
|
||||
#
|
||||
# Creates an instance of a fuzzer module
|
||||
#
|
||||
def initialize(info = {})
|
||||
super
|
||||
register_advanced_options([
|
||||
OptString.new('FuzzTracer', [ true, 'Sets the magic string to embed into fuzzer string inputs', 'MSFROCKS']),
|
||||
OptString.new('FuzzChar', [ true, 'Sets the character to use for generating long strings', 'X'])
|
||||
], Msf::Auxiliary::Fuzzer)
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Self-reflective iterators
|
||||
#
|
||||
def fuzz_numbers
|
||||
res = []
|
||||
self.methods.grep(/^fuzzer_number/).each do |m|
|
||||
@last_fuzzer_input = m
|
||||
block_given? ? self.send(m) {|x| yield(x) } : (res << self.send(m))
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def fuzz_strings
|
||||
res = []
|
||||
self.methods.grep(/^fuzzer_string/).each do |m|
|
||||
@last_fuzzer_input = m
|
||||
block_given? ? self.send(m) {|x| yield(x) } : (res << self.send(m))
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
#
|
||||
# General input mangling routines
|
||||
#
|
||||
def fuzz_string_corrupt_byte(str)
|
||||
res = []
|
||||
0.upto(str.length - 1) do |offset|
|
||||
0.upto(255) do |val|
|
||||
buf = str.dup
|
||||
buf[offset,1] = [val].pack('C')
|
||||
block_given? ? yield(buf) : (res << buf)
|
||||
end
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
#
|
||||
# Useful generators (many derived from AxMan)
|
||||
#
|
||||
|
||||
def fuzzer_string_format
|
||||
res = %W{ %s %p %n %x %@ %.257d %.65537d %.2147483648d %.257f %.65537f %.2147483648f}
|
||||
block_given? ? res.each { |n| yield(n) } : res
|
||||
end
|
||||
|
||||
def fuzzer_string_filepath_dos
|
||||
res = %W{ aux con nul com1 com2 com3 com4 lpt1 lpt2 lp3 lpt4 prn }
|
||||
block_given? ? res.each { |n| yield(n) } : res
|
||||
end
|
||||
|
||||
def fuzzer_number_power2
|
||||
res = [
|
||||
0x100000000,
|
||||
0x80000000,
|
||||
0x40000000,
|
||||
0x20000000,
|
||||
0x10000000,
|
||||
0x01000000,
|
||||
0x00100000,
|
||||
0x00010000,
|
||||
0x00001000,
|
||||
0x00000100,
|
||||
0x00000010,
|
||||
0x00000001
|
||||
]
|
||||
block_given? ? res.each { |n| yield(n) } : res
|
||||
end
|
||||
|
||||
def fuzzer_number_power2_plus
|
||||
res = []
|
||||
fuzzer_number_power2 do |num|
|
||||
res << num + 1
|
||||
res << num + 2
|
||||
res << num - 1
|
||||
res << num - 2
|
||||
res << num * -1
|
||||
res << (num + 1) * -1
|
||||
res << (num + 2) * -1
|
||||
end
|
||||
block_given? ? res.each { |n| yield(n) } : res
|
||||
end
|
||||
|
||||
def fuzzer_gen_string(len)
|
||||
datastore['FuzzChar'][0,1] * len
|
||||
end
|
||||
|
||||
def fuzzer_string_small
|
||||
res = []
|
||||
1.upto(512) do |len|
|
||||
buf = fuzzer_gen_string(len)
|
||||
block_given? ? yield(buf) : (res << buf)
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def fuzzer_string_long
|
||||
res = []
|
||||
64.step(8192,64) do |len|
|
||||
buf = fuzzer_gen_string(len)
|
||||
buf[len / 2, datastore['FuzzTracer'].length] = datastore['FuzzTracer']
|
||||
block_given? ? yield(buf) : (res << buf)
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def fuzzer_string_giant
|
||||
res = []
|
||||
512.step(65532 * 2, 512) do |len|
|
||||
buf = fuzzer_gen_string(len)
|
||||
buf[len / 2, datastore['FuzzTracer'].length] = datastore['FuzzTracer']
|
||||
block_given? ? yield(buf) : (res << buf)
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def fuzzer_string_uri_types
|
||||
res = %W{
|
||||
aaa aaas about acap adiumxtra afp aim apt aw bolo callto cap chrome cid
|
||||
content crid cvs data dav designates dict disk dns doi ed2k example examples
|
||||
fax feed file finger fish ftp gg gizmoproject go gopher h323 hcp http https
|
||||
iax2 icap im imap info ipp irc ircs iris iris.beep iris.lws iris.xpc iris.xpcs
|
||||
itms jar javascript keyparc lastfm ldap ldaps lsid magnet mailto mid mms modem
|
||||
ms-help msnim msrp msrps mtqp mupdate mvn news nfs nntp notes opaquelocktoken
|
||||
over pop pres prospero psyc res rlogin rmi rsync rtsp secondlife service sftp
|
||||
sgn shell shttp sip sips skype smb sms snews snmp soap.beep soap.beeps soldat
|
||||
ssh steam svn tag teamspeak tel telephone telnet tftp thismessage tip tv unreal
|
||||
urn ut2004 vbscript vemmi ventrilo view-source wais webcal worldwind wtai wyciwyg
|
||||
wysiwyg xfire xmlrpc.beep xmpp xri ymsgr z39.50r z39.50s
|
||||
}
|
||||
block_given? ? res.each { |n| yield(n) } : res
|
||||
end
|
||||
|
||||
def fuzzer_string_uri_dividers
|
||||
res = %W{ : :/ :// }
|
||||
block_given? ? res.each { |n| yield(n) } : res
|
||||
end
|
||||
|
||||
def fuzzer_string_path_prefixes
|
||||
res = %W{ C:\\ \\\\localhost\\ / }
|
||||
block_given? ? res.each { |n| yield(n) } : res
|
||||
end
|
||||
|
||||
def fuzzer_string_uris_small
|
||||
res = []
|
||||
fuzzer_string_uri_types do |proto|
|
||||
fuzzer_string_uri_dividers do |div|
|
||||
fuzzer_string_small do |str|
|
||||
buf = proto + div + str
|
||||
block_given? ? yield(buf) : (res << buf)
|
||||
end
|
||||
end
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def fuzzer_string_uris_long
|
||||
res = []
|
||||
fuzzer_string_uri_types do |proto|
|
||||
fuzzer_string_uri_dividers do |div|
|
||||
fuzzer_string_long do |str|
|
||||
buf = proto + div + str
|
||||
block_given? ? yield(buf) : (res << buf)
|
||||
end
|
||||
end
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def fuzzer_string_uris_giant
|
||||
res = []
|
||||
fuzzer_string_uri_types do |proto|
|
||||
fuzzer_string_uri_dividers do |div|
|
||||
fuzzer_string_giant do |str|
|
||||
buf = proto + div + str
|
||||
block_given? ? yield(buf) : (res << buf)
|
||||
end
|
||||
end
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def fuzzer_string_uris_format
|
||||
res = []
|
||||
fuzzer_string_uri_types do |proto|
|
||||
fuzzer_string_uri_dividers do |div|
|
||||
fuzzer_string_format do |str|
|
||||
buf = proto + div + str
|
||||
block_given? ? yield(buf) : (res << buf)
|
||||
end
|
||||
end
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def fuzzer_string_uris_dos
|
||||
res = []
|
||||
fuzzer_string_uri_types do |proto|
|
||||
fuzzer_string_uri_dividers do |div|
|
||||
fuzzer_string_filepath_dos do |str|
|
||||
buf = proto + div + str
|
||||
block_given? ? yield(buf) : (res << buf)
|
||||
end
|
||||
end
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def fuzzer_string_paths_small
|
||||
res = []
|
||||
fuzzer_string_path_prefixes do |pre|
|
||||
fuzzer_string_small do |str|
|
||||
buf = pre + str
|
||||
block_given? ? yield(buf) : (res << buf)
|
||||
end
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def fuzzer_string_paths_long
|
||||
res = []
|
||||
fuzzer_string_path_prefixes do |pre|
|
||||
fuzzer_string_long do |str|
|
||||
buf = pre + str
|
||||
block_given? ? yield(buf) : (res << buf)
|
||||
end
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def fuzzer_string_paths_giant
|
||||
res = []
|
||||
fuzzer_string_path_prefixes do |pre|
|
||||
fuzzer_string_giant do |str|
|
||||
buf = pre + str
|
||||
block_given? ? yield(buf) : (res << buf)
|
||||
end
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def fuzzer_string_paths_format
|
||||
res = []
|
||||
fuzzer_string_path_prefixes do |pre|
|
||||
fuzzer_string_format do |str|
|
||||
buf = pre + str
|
||||
block_given? ? yield(buf) : (res << buf)
|
||||
end
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def fuzzer_string_paths_dos
|
||||
res = []
|
||||
fuzzer_string_path_prefixes do |pre|
|
||||
fuzzer_string_filepath_dos do |str|
|
||||
buf = pre + str
|
||||
block_given? ? yield(buf) : (res << buf)
|
||||
end
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
#
|
||||
# Auxiliary mixins
|
||||
#
|
||||
require 'msf/core/auxiliary/scanner'
|
||||
require 'msf/core/auxiliary/report'
|
||||
require 'msf/core/auxiliary/dos'
|
||||
require 'msf/core/auxiliary/fuzzer'
|
||||
require 'msf/core/auxiliary/timed'
|
||||
require 'msf/core/auxiliary/wmapmodule'
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::MSSQL
|
||||
include Msf::Auxiliary::Fuzzer
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'TDS Protocol Login Request Fuzzer',
|
||||
'Description' => %q{
|
||||
This module sends a series of malformed TDS login requests.
|
||||
},
|
||||
'Author' => [ 'hdm' ],
|
||||
'License' => MSF_LICENSE,
|
||||
'Version' => '$Revision$'
|
||||
))
|
||||
end
|
||||
|
||||
# A copy of the mssql_login method with the ability to overload each option
|
||||
def do_login(opts={})
|
||||
|
||||
@connected = false
|
||||
disconnect if self.sock
|
||||
connect
|
||||
@connected = true
|
||||
|
||||
pkt = ""
|
||||
idx = 0
|
||||
db = ""
|
||||
|
||||
pkt << [
|
||||
0x00000000, # Dummy size
|
||||
opts[:tds_version] || 0x71000001, # TDS Version
|
||||
opts[:size] || 0x00000000, # Size
|
||||
opts[:version] || 0x00000007, # Version
|
||||
opts[:pid] || rand(1024+1), # PID
|
||||
opts[:connection_id] || 0x00000000, # ConnectionID
|
||||
opts[:flags_opt1] || 0xe0, # Option Flags 1
|
||||
opts[:flags_opt2] || 0x03, # Option Flags 2
|
||||
opts[:flags_sql_type] || 0x00, # SQL Type Flags
|
||||
opts[:flags_reserved] || 0x00, # Reserved Flags
|
||||
opts[:timezone] || 0x00000000, # Time Zone
|
||||
opts[:collation] || 0x00000000 # Collation
|
||||
].pack('VVVVVVCCCCVV')
|
||||
|
||||
|
||||
cname = Rex::Text.to_unicode( opts[:cname] || Rex::Text.rand_text_alpha(rand(8)+1) )
|
||||
uname = Rex::Text.to_unicode( opts[:uname] || "sa" )
|
||||
pname = opts[:pname_raw] || mssql_tds_encrypt( opts[:pname] || "" )
|
||||
aname = Rex::Text.to_unicode(opts[:aname] || Rex::Text.rand_text_alpha(rand(8)+1) )
|
||||
sname = Rex::Text.to_unicode( opts[:sname] || rhost )
|
||||
dname = Rex::Text.to_unicode( opts[:dname] || db )
|
||||
|
||||
idx = pkt.size + 50 # lengths below
|
||||
|
||||
pkt << [idx, cname.length / 2].pack('vv')
|
||||
idx += cname.length
|
||||
|
||||
pkt << [idx, uname.length / 2].pack('vv')
|
||||
idx += uname.length
|
||||
|
||||
pkt << [idx, pname.length / 2].pack('vv')
|
||||
idx += pname.length
|
||||
|
||||
pkt << [idx, aname.length / 2].pack('vv')
|
||||
idx += aname.length
|
||||
|
||||
pkt << [idx, sname.length / 2].pack('vv')
|
||||
idx += sname.length
|
||||
|
||||
pkt << [0, 0].pack('vv')
|
||||
|
||||
pkt << [idx, aname.length / 2].pack('vv')
|
||||
idx += aname.length
|
||||
|
||||
pkt << [idx, 0].pack('vv')
|
||||
|
||||
pkt << [idx, dname.length / 2].pack('vv')
|
||||
idx += dname.length
|
||||
|
||||
# The total length has to be embedded twice more here
|
||||
pkt << [
|
||||
0,
|
||||
0,
|
||||
0x12345678,
|
||||
0x12345678
|
||||
].pack('vVVV')
|
||||
|
||||
pkt << cname
|
||||
pkt << uname
|
||||
pkt << pname
|
||||
pkt << aname
|
||||
pkt << sname
|
||||
pkt << aname
|
||||
pkt << dname
|
||||
|
||||
# Total packet length
|
||||
pkt[0,4] = [pkt.length].pack('V')
|
||||
|
||||
# Embedded packet lengths
|
||||
pkt[pkt.index([0x12345678].pack('V')), 8] = [pkt.length].pack('V') * 2
|
||||
|
||||
# Packet header and total length including header
|
||||
pkt = "\x10\x01" + [pkt.length + 8].pack('n') + [0].pack('n') + [1].pack('C') + "\x00" + pkt
|
||||
|
||||
resp = mssql_send_recv(pkt,opts[:timeout])
|
||||
|
||||
info = {:errors => []}
|
||||
info = mssql_parse_reply(resp,info)
|
||||
info
|
||||
end
|
||||
|
||||
def run
|
||||
last_str = nil
|
||||
last_inp = nil
|
||||
last_err = nil
|
||||
|
||||
cnt = 0
|
||||
fuzz_strings do |str|
|
||||
# capped at 16-bit lengths
|
||||
next if str.length > 65535
|
||||
cnt += 1
|
||||
|
||||
if(cnt % 100 == 0)
|
||||
print_status("Fuzzing with iteration #{cnt} using #{@last_fuzzer_input}")
|
||||
end
|
||||
|
||||
begin
|
||||
do_login(:uname => str, :timeout => 0.50)
|
||||
rescue ::Interrupt
|
||||
print_status("Exiting on interrupt: iteration #{cnt} using #{@last_fuzzer_input}")
|
||||
raise $!
|
||||
rescue ::Exception => e
|
||||
last_err = e
|
||||
ensure
|
||||
disconnect
|
||||
end
|
||||
|
||||
if(not @connected)
|
||||
if(last_str)
|
||||
print_status("The service may have crashed: method=#{last_inp} string=#{last_str.unpack("H*")[0]} error=#{last_err}")
|
||||
else
|
||||
print_status("Could not connect to the service: #{last_err}")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
last_str = str
|
||||
last_inp = @last_fuzzer_input
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue