Module: Metasploit::Framework::MSSQL::Client

Extended by:
ActiveSupport::Concern
Includes:
Tcp::Client
Included in:
LoginScanner::MSSQL
Defined in:
lib/metasploit/framework/mssql/client.rb

Constant Summary collapse

ENCRYPT_OFF =

Encryption

0x00
ENCRYPT_ON =

Encryption is available but off.

0x01
ENCRYPT_NOT_SUP =

Encryption is available and on.

0x02
ENCRYPT_REQ =

Encryption is not available.

0x03
TYPE_SQL_BATCH =

Packet Type

1
TYPE_PRE_TDS7_LOGIN =

(Client) SQL command

2
TYPE_RPC =

(Client) Pre-login with version < 7 (unused)

3
TYPE_TABLE_RESPONSE =

(Client) RPC

4
TYPE_ATTENTION_SIGNAL =

Request Completion, Error and Info Messages, Attention Acknowledgement

6
TYPE_BULK_LOAD =

(Client) Attention

7
TYPE_TRANSACTION_MANAGER_REQUEST =

(Client) SQL Command with binary data

14
TYPE_TDS7_LOGIN =

(Client) Transaction request manager

16
TYPE_SSPI_MESSAGE =

(Client) Login

17
TYPE_PRE_LOGIN_MESSAGE =

(Client) Login

18
STATUS_NORMAL =

Status

0x00
STATUS_END_OF_MESSAGE =
0x01
STATUS_IGNORE_EVENT =
0x02
STATUS_RESETCONNECTION =

TDS 7.1+

0x08
STATUS_RESETCONNECTIONSKIPTRAN =

TDS 7.3+

0x10

Instance Attribute Summary

Attributes included from Tcp::Client

#max_send_size, #send_delay, #sock

Instance Method Summary collapse

Methods included from Tcp::Client

#chost, #connect, #cport, #disconnect, #proxies, #rhost, #rport, #set_tcp_evasions, #ssl, #ssl_version

Instance Method Details

#mssql_login(user = 'sa', pass = '', db = '', domain_name = '') ⇒ Object

This method connects to the server over TCP and attempts to authenticate with the supplied username and password The global socket is used and left connected after auth


43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/metasploit/framework/mssql/client.rb', line 43

def (user='sa', pass='', db='', domain_name='')

  disconnect if self.sock
  connect
  mssql_prelogin

  if windows_authentication
    idx = 0
    pkt = ''
    pkt_hdr = ''
    pkt_hdr =  [
        TYPE_TDS7_LOGIN, #type
        STATUS_END_OF_MESSAGE, #status
        0x0000, #length
        0x0000, # SPID
        0x01,   # PacketID (unused upon specification
        # but ms network monitor stil prefer 1 to decode correctly, wireshark don't care)
        0x00   #Window
    ]

    pkt << [
        0x00000000,   # Size
        0x71000001,   # TDS Version
        0x00000000,   # Dummy Size
        0x00000007,   # Version
        rand(1024+1), # PID
        0x00000000,   # ConnectionID
        0xe0,         # Option Flags 1
        0x83,         # Option Flags 2
        0x00,         # SQL Type Flags
        0x00,         # Reserved Flags
        0x00000000,   # Time Zone
        0x00000000    # Collation
    ].pack('VVVVVVCCCCVV')

    cname = Rex::Text.to_unicode( Rex::Text.rand_text_alpha(rand(8)+1) )
    aname = Rex::Text.to_unicode( Rex::Text.rand_text_alpha(rand(8)+1) ) #application and library name
    sname = Rex::Text.to_unicode( rhost )
    dname = Rex::Text.to_unicode( db )

    workstation_name = Rex::Text.rand_text_alpha(rand(8)+1)

    ntlm_client = ::Net::NTLM::Client.new(
      user,
      pass,
      workstation: workstation_name,
      domain: domain_name,
    )
    type1 = ntlm_client.init_context
    # SQL 2012, at least, does not support KEY_EXCHANGE
    type1.flag &= ~ ::Net::NTLM::FLAGS[:KEY_EXCHANGE]
    ntlmsspblob = type1.serialize

    idx = pkt.size + 50 # lengths below

    pkt << [idx, cname.length / 2].pack('vv')
    idx += cname.length

    pkt << [0, 0].pack('vv') # User length offset must be 0
    pkt << [0, 0].pack('vv') # Password length offset must be 0

    pkt << [idx, aname.length / 2].pack('vv')
    idx += aname.length

    pkt << [idx, sname.length / 2].pack('vv')
    idx += sname.length

    pkt << [0, 0].pack('vv') # unused

    pkt << [idx, aname.length / 2].pack('vv')
    idx += aname.length

    pkt << [idx, 0].pack('vv') # locales

    pkt << [idx, 0].pack('vv') #db

    # ClientID (should be mac address)
    pkt << Rex::Text.rand_text(6)

    # NTLMSSP
    pkt << [idx, ntlmsspblob.length].pack('vv')
    idx += ntlmsspblob.length

    pkt << [idx, 0].pack('vv') # AtchDBFile

    pkt << cname
    pkt << aname
    pkt << sname
    pkt << aname
    pkt << ntlmsspblob

    # Total packet length
    pkt[0, 4] = [pkt.length].pack('V')

    pkt_hdr[2] = pkt.length + 8

    pkt = pkt_hdr.pack("CCnnCC") + pkt

    # Rem : One have to set check_status to false here because sql server sp0 (and maybe above)
    # has a strange behavior that differs from the specifications
    # upon receiving the ntlm_negociate request it send an ntlm_challenge but the status flag of the tds packet header
    # is set to STATUS_NORMAL and not STATUS_END_OF_MESSAGE, then internally it waits for the ntlm_authentification
    if tdsencryption == true
       proxy = TDSSSLProxy.new(sock)
       proxy.setup_ssl
       resp = proxy.send_recv(pkt, 15, false)
    else
       resp = mssql_send_recv(pkt, 15, false)
    end

    # Strip the TDS header
    resp = resp[3..-1]
    type3 = ntlm_client.init_context([resp].pack('m'))
    type3_blob = type3.serialize

    # Create an SSPIMessage
    idx = 0
    pkt = ''
    pkt_hdr = ''
    pkt_hdr = [
      TYPE_SSPI_MESSAGE, #type
      STATUS_END_OF_MESSAGE, #status
      0x0000, #length
      0x0000, # SPID
      0x01, # PacketID
      0x00 #Window
    ]

    pkt_hdr[2] = type3_blob.length + 8

    pkt = pkt_hdr.pack("CCnnCC") + type3_blob

    if self.tdsencryption == true
      resp = mssql_ssl_send_recv(pkt, proxy)
      proxy.cleanup
      proxy = nil
    else
      resp = mssql_send_recv(pkt)
    end

    #SQL Server Authentification
  else
    idx = 0
    pkt = ''
    pkt << [
        0x00000000,   # Dummy size

        0x71000001,   # TDS Version
        0x00000000,   # Size
        0x00000007,   # Version
        rand(1024+1), # PID
        0x00000000,   # ConnectionID
        0xe0,         # Option Flags 1
        0x03,         # Option Flags 2
        0x00,         # SQL Type Flags
        0x00,         # Reserved Flags
        0x00000000,   # Time Zone
        0x00000000    # Collation
    ].pack('VVVVVVCCCCVV')


    cname = Rex::Text.to_unicode( Rex::Text.rand_text_alpha(rand(8)+1) )
    uname = Rex::Text.to_unicode( user )
    pname = mssql_tds_encrypt( pass )
    aname = Rex::Text.to_unicode( Rex::Text.rand_text_alpha(rand(8)+1) )
    sname = Rex::Text.to_unicode( rhost )
    dname = Rex::Text.to_unicode( db )

    idx = pkt.size + 50 # lengths below

    pkt << [idx, cname.length / 2].pack('vv')
    idx += cname.length

    pkt << [idx, uname.length / 2].pack('vv')
    idx += uname.length

    pkt << [idx, pname.length / 2].pack('vv')
    idx += pname.length

    pkt << [idx, aname.length / 2].pack('vv')
    idx += aname.length

    pkt << [idx, sname.length / 2].pack('vv')
    idx += sname.length

    pkt << [0, 0].pack('vv')

    pkt << [idx, aname.length / 2].pack('vv')
    idx += aname.length

    pkt << [idx, 0].pack('vv')

    pkt << [idx, dname.length / 2].pack('vv')
    idx += dname.length

    # The total length has to be embedded twice more here
    pkt << [
        0,
        0,
        0x12345678,
        0x12345678
    ].pack('vVVV')

    pkt << cname
    pkt << uname
    pkt << pname
    pkt << aname
    pkt << sname
    pkt << aname
    pkt << dname

    # Total packet length
    pkt[0, 4] = [pkt.length].pack('V')

    # Embedded packet lengths
    pkt[pkt.index([0x12345678].pack('V')), 8] = [pkt.length].pack('V') * 2

    # Packet header and total length including header
    pkt = "\x10\x01" + [pkt.length + 8].pack('n') + [0].pack('n') + [1].pack('C') + "\x00" + pkt

    if self.tdsencryption == true
      proxy = TDSSSLProxy.new(sock)
      proxy.setup_ssl
      resp = mssql_ssl_send_recv(pkt, proxy)
      proxy.cleanup
      proxy = nil
    else
      resp = mssql_send_recv(pkt)
    end

  end

  info = {:errors => []}
  info = mssql_parse_reply(resp, info)

  disconnect

  return false if not info
  info[:login_ack] ? true : false
end

#mssql_parse_done(data, info) ⇒ Object

Parse a “done” TDS token


317
318
319
320
321
# File 'lib/metasploit/framework/mssql/client.rb', line 317

def mssql_parse_done(data, info)
  status, cmd, rows = data.slice!(0, 8).unpack('vvV')
  info[:done] = { :status => status, :cmd => cmd, :rows => rows }
  info
end

#mssql_parse_env(data, info) ⇒ Object

Parse an “environment change” TDS token


287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
# File 'lib/metasploit/framework/mssql/client.rb', line 287

def mssql_parse_env(data, info)
  len  = data.slice!(0, 2).unpack('v')[0]
  buff = data.slice!(0, len)
  type = buff.slice!(0, 1).unpack('C')[0]

  nval = ''
  nlen = buff.slice!(0, 1).unpack('C')[0] || 0
  nval = buff.slice!(0, nlen*2).gsub("\x00", '') if nlen > 0

  oval = ''
  olen = buff.slice!(0, 1).unpack('C')[0] || 0
  oval = buff.slice!(0, olen*2).gsub("\x00", '') if olen > 0

  info[:envs] ||= []
  info[:envs] << { :type => type, :old => oval, :new => nval }
  info
end

#mssql_parse_error(data, info) ⇒ Object

Parse an “error” TDS token


326
327
328
329
330
331
332
333
334
335
336
# File 'lib/metasploit/framework/mssql/client.rb', line 326

def mssql_parse_error(data, info)
  len  = data.slice!(0, 2).unpack('v')[0]
  buff = data.slice!(0, len)

  errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
  emsg = buff.slice!(0, elen * 2)
  emsg.gsub!("\x00", '')

  info[:errors] << "SQL Server Error ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
  info
end

#mssql_parse_info(data, info) ⇒ Object

Parse an “information” TDS token


341
342
343
344
345
346
347
348
349
350
351
352
# File 'lib/metasploit/framework/mssql/client.rb', line 341

def mssql_parse_info(data, info)
  len  = data.slice!(0, 2).unpack('v')[0]
  buff = data.slice!(0, len)

  errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
  emsg = buff.slice!(0, elen * 2)
  emsg.gsub!("\x00", '')

  info[:infos] ||= []
  info[:infos] << "SQL Server Info ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
  info
end

#mssql_parse_login_ack(data, info) ⇒ Object

Parse a “login ack” TDS token


357
358
359
360
361
# File 'lib/metasploit/framework/mssql/client.rb', line 357

def (data, info)
  len = data.slice!(0, 2).unpack('v')[0]
  _buff = data.slice!(0, len)
  info[:login_ack] = true
end

#mssql_parse_reply(data, info) ⇒ Object

Parse individual tokens from a TDS reply


366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
# File 'lib/metasploit/framework/mssql/client.rb', line 366

def mssql_parse_reply(data, info)
  info[:errors] = []
  return if not data
  until data.empty?
    token = data.slice!(0, 1).unpack('C')[0]
    case token
      when 0x81
        mssql_parse_tds_reply(data, info)
      when 0xd1
        mssql_parse_tds_row(data, info)
      when 0xe3
        mssql_parse_env(data, info)
      when 0x79
        mssql_parse_ret(data, info)
      when 0xfd, 0xfe, 0xff
        mssql_parse_done(data, info)
      when 0xad
        (data, info)
      when 0xab
        mssql_parse_info(data, info)
      when 0xaa
        mssql_parse_error(data, info)
      when nil
        break
      else
        info[:errors] << "unsupported token: #{token}"
    end
  end
  info
end

#mssql_parse_ret(data, info) ⇒ Object

Parse a “ret” TDS token


308
309
310
311
312
# File 'lib/metasploit/framework/mssql/client.rb', line 308

def mssql_parse_ret(data, info)
  ret = data.slice!(0, 4).unpack('N')[0]
  info[:ret] = ret
  info
end

#mssql_parse_tds_reply(data, info) ⇒ Object

Parse a raw TDS reply from the server


400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
# File 'lib/metasploit/framework/mssql/client.rb', line 400

def mssql_parse_tds_reply(data, info)
  info[:errors] ||= []
  info[:colinfos] ||= []
  info[:colnames] ||= []

  # Parse out the columns
  cols = data.slice!(0, 2).unpack('v')[0]
  0.upto(cols-1) do |col_idx|
    col = {}
    info[:colinfos][col_idx] = col

    col[:utype] = data.slice!(0, 2).unpack('v')[0]
    col[:flags] = data.slice!(0, 2).unpack('v')[0]
    col[:type]  = data.slice!(0, 1).unpack('C')[0]

    case col[:type]
      when 48
        col[:id] = :tinyint

      when 52
        col[:id] = :smallint

      when 56
        col[:id] = :rawint

      when 61
        col[:id] = :datetime

      when 34
        col[:id]            = :image
        col[:max_size]      = data.slice!(0, 4).unpack('V')[0]
        col[:value_length]  = data.slice!(0, 2).unpack('v')[0]
        col[:value]         = data.slice!(0, col[:value_length]  * 2).gsub("\x00", '')

      when 36
        col[:id] = :string

      when 38
        col[:id] = :int
        col[:int_size] = data.slice!(0, 1).unpack('C')[0]

      when 127
        col[:id] = :bigint

      when 165
        col[:id] = :hex
        col[:max_size] = data.slice!(0, 2).unpack('v')[0]

      when 173
        col[:id] = :hex # binary(2)
        col[:max_size] = data.slice!(0, 2).unpack('v')[0]

      when 231, 175, 167, 239
        col[:id] = :string
        col[:max_size] = data.slice!(0, 2).unpack('v')[0]
        col[:codepage] = data.slice!(0, 2).unpack('v')[0]
        col[:cflags] = data.slice!(0, 2).unpack('v')[0]
        col[:charset_id] =  data.slice!(0, 1).unpack('C')[0]

      else
        col[:id] = :unknown
    end

    col[:msg_len] = data.slice!(0, 1).unpack('C')[0]

    if(col[:msg_len] and col[:msg_len] > 0)
      col[:name] = data.slice!(0, col[:msg_len] * 2).gsub("\x00", '')
    end
    info[:colnames] << (col[:name] || 'NULL')
  end
end

#mssql_parse_tds_row(data, info) ⇒ Object

Parse a single row of a TDS reply


475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
# File 'lib/metasploit/framework/mssql/client.rb', line 475

def mssql_parse_tds_row(data, info)
  info[:rows] ||= []
  row = []

  info[:colinfos].each do |col|

    if(data.length == 0)
      row << "<EMPTY>"
      next
    end

    case col[:id]
      when :hex
        str = ""
        len = data.slice!(0, 2).unpack('v')[0]
        if(len > 0 and len < 65535)
          str << data.slice!(0, len)
        end
        row << str.unpack("H*")[0]

      when :string
        str = ""
        len = data.slice!(0, 2).unpack('v')[0]
        if(len > 0 and len < 65535)
          str << data.slice!(0, len)
        end
        row << str.gsub("\x00", '')

      when :datetime
        row << data.slice!(0, 8).unpack("H*")[0]

      when :rawint
        row << data.slice!(0, 4).unpack('V')[0]

      when :bigint
        row << data.slice!(0, 8).unpack("H*")[0]

      when :smallint
        row << data.slice!(0, 2).unpack("v")[0]

      when :smallint3
        row << [data.slice!(0, 3)].pack("Z4").unpack("V")[0]

      when :tinyint
        row << data.slice!(0, 1).unpack("C")[0]

      when :image
        str = ''
        len = data.slice!(0, 1).unpack('C')[0]
        str = data.slice!(0, len) if (len and len > 0)
        row << str.unpack("H*")[0]

      when :int
        len = data.slice!(0, 1).unpack("C")[0]
        raw = data.slice!(0, len) if (len and len > 0)

        case len
          when 0, 255
            row << ''
          when 1
            row << raw.unpack("C")[0]
          when 2
            row << raw.unpack('v')[0]
          when 4
            row << raw.unpack('V')[0]
          when 5
            row << raw.unpack('V')[0] # XXX: missing high byte
          when 8
            row << raw.unpack('VV')[0] # XXX: missing high dword
          else
            info[:errors] << "invalid integer size: #{len} #{data[0, 16].unpack("H*")[0]}"
        end
      else
        info[:errors] << "unknown column type: #{col.inspect}"
    end
  end

  info[:rows] << row
  info
end

#mssql_prelogin(enc_error = false) ⇒ Object

this method send a prelogin packet and check if encryption is off


559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
# File 'lib/metasploit/framework/mssql/client.rb', line 559

def mssql_prelogin(enc_error=false)

  pkt = ""
  pkt_hdr = ""
  pkt_data_token = ""
  pkt_data = ""


  pkt_hdr = [
      TYPE_PRE_LOGIN_MESSAGE, #type
      STATUS_END_OF_MESSAGE, #status
      0x0000, #length
      0x0000, # SPID
      0x00, # PacketID
      0x00 #Window
  ]

  version = [0x55010008, 0x0000].pack("Vv")

  # if manually set, we will honour
  if tdsencryption == true
    encryption = ENCRYPT_ON
  else
    encryption = ENCRYPT_NOT_SUP
  end

  instoptdata = "MSSQLServer\0"

  threadid = "\0\0" + Rex::Text.rand_text(2)

  idx = 21 # size of pkt_data_token
  pkt_data_token << [
      0x00, # Token 0 type Version
      idx , # VersionOffset
      version.length, # VersionLength

      0x01, # Token 1 type Encryption
      idx = idx + version.length, # EncryptionOffset
      0x01, # EncryptionLength

      0x02, # Token 2 type InstOpt
      idx = idx + 1, # InstOptOffset
      instoptdata.length, # InstOptLength

      0x03, # Token 3 type Threadid
      idx + instoptdata.length, # ThreadIdOffset
      0x04, # ThreadIdLength

      0xFF
  ].pack("CnnCnnCnnCnnC")

  pkt_data << pkt_data_token
  pkt_data << version
  pkt_data << encryption
  pkt_data << instoptdata
  pkt_data << threadid

  pkt_hdr[2] = pkt_data.length + 8

  pkt = pkt_hdr.pack("CCnnCC") + pkt_data

  resp = mssql_send_recv(pkt)

  idx = 0

  while resp && resp[0, 1] != "\xff" && resp.length > 5
    token = resp.slice!(0, 5)
    token = token.unpack("Cnn")
    idx -= 5
    if token[0] == 0x01

      idx += token[1]
      break
    end
  end
  if idx > 0
    encryption_mode = resp[idx, 1].unpack("C")[0]
  else
    framework_module.print_error("Unable to parse encryption req " \
      "during pre-login, this may not be a MSSQL server")
    encryption_mode = ENCRYPT_NOT_SUP
  end

  ##########################################################
  # Our initial prelogin pkt above said we didnt support
  # encryption (it's quicker and the default).
  #
  # Per the matrix on the following link, SQL Server will
  # terminate the connection if it does require TLS,
  # otherwise it will accept an unencrypted session. As
  # part of this initial response packet, it also returns
  # ENCRYPT_REQ.
  #
  # https://msdn.microsoft.com\
  #   /en-us/library/ee320519(v=sql.105).aspx
  #
  ##########################################################

  if encryption_mode == ENCRYPT_REQ
    # restart prelogin process except that we tell SQL Server
    # than we are now able to encrypt
    disconnect if self.sock
    connect

    # offset 35 is the flag - turn it on
    pkt[35] = [ENCRYPT_ON].pack('C')
    self.tdsencryption = true
    framework_module.print_status("TLS encryption has " \
      "been enabled based on server response.")

    resp = mssql_send_recv(pkt)

    idx = 0

    while resp && resp[0, 1] != "\xff" && resp.length > 5
      token = resp.slice!(0, 5)
      token = token.unpack("Cnn")
      idx -= 5
      if token[0] == 0x01
        idx += token[1]
        break
      end
    end
    if idx > 0
      encryption_mode = resp[idx, 1].unpack("C")[0]
    else
      framework_module.print_error("Unable to parse encryption req " \
        "during pre-login, this may not be a MSSQL server")
      encryption_mode = ENCRYPT_NOT_SUP
    end
  end
  encryption_mode
end

#mssql_send_recv(req, timeout = 15, check_status = true) ⇒ Object

Send and receive using TDS


696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
# File 'lib/metasploit/framework/mssql/client.rb', line 696

def mssql_send_recv(req, timeout=15, check_status = true)
  sock.put(req)

  # Read the 8 byte header to get the length and status
  # Read the length to get the data
  # If the status is 0, read another header and more data

  done = false
  resp = ""

  while(not done)
    head = sock.get_once(8, timeout)
    if !(head && head.length == 8)
      return false
    end

    # Is this the last buffer?
    if head[1, 1] == "\x01" || !check_status
      done = true
    end

    # Grab this block's length
    rlen = head[2, 2].unpack('n')[0] - 8

    while(rlen > 0)
      buff = sock.get_once(rlen, timeout)
      return if not buff
      resp << buff
      rlen -= buff.length
    end
  end

  resp
end

#mssql_ssl_send_recv(req, tdsproxy, timeout = 15, check_status = true) ⇒ Object


731
732
733
# File 'lib/metasploit/framework/mssql/client.rb', line 731

def mssql_ssl_send_recv(req, tdsproxy, timeout=15, check_status=true)
  tdsproxy.send_recv(req)
end

#mssql_tds_encrypt(pass) ⇒ Object

Encrypt a password according to the TDS protocol (encode)


738
739
740
741
# File 'lib/metasploit/framework/mssql/client.rb', line 738

def mssql_tds_encrypt(pass)
  # Convert to unicode, swap 4 bits both ways, xor with 0xa5
  Rex::Text.to_unicode(pass).unpack('C*').map {|c| (((c & 0x0f) << 4) + ((c & 0xf0) >> 4)) ^ 0xa5 }.pack("C*")
end

#send_lmObject (protected)

Raises:

  • (NotImplementedError)

757
758
759
# File 'lib/metasploit/framework/mssql/client.rb', line 757

def send_lm
  raise NotImplementedError
end

#send_ntlmObject (protected)

Raises:

  • (NotImplementedError)

761
762
763
# File 'lib/metasploit/framework/mssql/client.rb', line 761

def send_ntlm
  raise NotImplementedError
end

#send_spnObject (protected)

Raises:

  • (NotImplementedError)

765
766
767
# File 'lib/metasploit/framework/mssql/client.rb', line 765

def send_spn
  raise NotImplementedError
end

#use_ntlm2_sessionObject (protected)

Raises:

  • (NotImplementedError)

749
750
751
# File 'lib/metasploit/framework/mssql/client.rb', line 749

def use_ntlm2_session
  raise NotImplementedError
end

#use_ntlmv2Object (protected)

Raises:

  • (NotImplementedError)

753
754
755
# File 'lib/metasploit/framework/mssql/client.rb', line 753

def use_ntlmv2
  raise NotImplementedError
end

#windows_authenticationObject (protected)

Raises:

  • (NotImplementedError)

745
746
747
# File 'lib/metasploit/framework/mssql/client.rb', line 745

def windows_authentication
  raise NotImplementedError
end