Class: RubySMB::Dcerpc::Client

Inherits:
Object
  • Object
show all
Includes:
Epm
Defined in:
lib/ruby_smb/dcerpc/client.rb

Overview

Represents DCERPC SMB client capable of talking to an RPC endpoint in stand-alone.

Constant Summary collapse

MAX_BUFFER_SIZE =

The default maximum size of a RPC message that the Client accepts (in bytes)

64512
READ_TIMEOUT =

The read timeout when receiving packets.

30
ENDPOINT_MAPPER_PORT =

The default Endpoint Mapper port

135

Constants included from Epm

Epm::EPT_MAP, Epm::UUID, Epm::VER_MAJOR, Epm::VER_MINOR

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Epm

#get_host_port_from_ept_mapper

Constructor Details

#initialize(host, endpoint, tcp_socket: nil, read_timeout: READ_TIMEOUT, username: '', password: '', domain: '.', local_workstation: 'WORKSTATION', ntlm_flags: NTLM::DEFAULT_CLIENT_FLAGS) ⇒ Client

Returns a new instance of Client.

Parameters:

  • host (String)

    The remote host

  • endpoint (Module)

    A module endpoint that defines UUID, VER_MAJOR and VER_MINOR constants (e.g. Drsr)

  • tcp_socket (TcpSocket) (defaults to: nil)

    The socket to use. If not provided, a new socket will be created when calling #connect

  • read_timeout (Integer) (defaults to: READ_TIMEOUT)

    The read timeout value to use

  • username (String) (defaults to: '')

    The username to authenticate with, if needed

  • password (String) (defaults to: '')

    The password to authenticate with, if needed. Note that a NTLM hash can be used instead of a password.

  • domain (String) (defaults to: '.')

    The domain to authenticate to, if needed

  • local_workstation (String) (defaults to: 'WORKSTATION')

    The workstation name to authenticate to, if needed

  • ntlm_flags (Integer) (defaults to: NTLM::DEFAULT_CLIENT_FLAGS)

    The flags to pass to the Net:NTLM client



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
# File 'lib/ruby_smb/dcerpc/client.rb', line 100

def initialize(host,
               endpoint,
               tcp_socket: nil,
               read_timeout: READ_TIMEOUT,
               username: '',
               password: '',
               domain: '.',
               local_workstation: 'WORKSTATION',
               ntlm_flags: NTLM::DEFAULT_CLIENT_FLAGS)

  @endpoint = endpoint
  extend @endpoint

  @host              = host
  @tcp_socket        = tcp_socket
  @read_timeout      = read_timeout
  @domain            = domain
  @local_workstation = local_workstation
  @username          = username.encode('utf-8')
  @password          = password.encode('utf-8')
  @max_buffer_size   = MAX_BUFFER_SIZE
  @call_id           = 1
  @ctx_id            = 0
  @auth_ctx_id_base  = rand(0xFFFFFFFF)

  unless username.empty? && password.empty?
    @ntlm_client = Net::NTLM::Client.new(
      @username,
      @password,
      workstation: @local_workstation,
      domain: @domain,
      flags: ntlm_flags
    )
  end
end

Instance Attribute Details

#default_domainString

Returns:

  • (String)


54
55
56
# File 'lib/ruby_smb/dcerpc/client.rb', line 54

def default_domain
  @default_domain
end

#default_nameString

Returns:

  • (String)


49
50
51
# File 'lib/ruby_smb/dcerpc/client.rb', line 49

def default_name
  @default_name
end

#dns_domain_nameString

Returns:

  • (String)


64
65
66
# File 'lib/ruby_smb/dcerpc/client.rb', line 64

def dns_domain_name
  @dns_domain_name
end

#dns_host_nameString

Returns:

  • (String)


59
60
61
# File 'lib/ruby_smb/dcerpc/client.rb', line 59

def dns_host_name
  @dns_host_name
end

#dns_tree_nameString

Returns:

  • (String)


69
70
71
# File 'lib/ruby_smb/dcerpc/client.rb', line 69

def dns_tree_name
  @dns_tree_name
end

#domainString

Returns:

  • (String)


24
25
26
# File 'lib/ruby_smb/dcerpc/client.rb', line 24

def domain
  @domain
end

#local_workstationString

Returns:

  • (String)


29
30
31
# File 'lib/ruby_smb/dcerpc/client.rb', line 29

def local_workstation
  @local_workstation
end

#max_buffer_sizeInteger

Returns:

  • (Integer)


80
81
82
# File 'lib/ruby_smb/dcerpc/client.rb', line 80

def max_buffer_size
  @max_buffer_size
end

#ntlm_clientString

Returns:

  • (String)


34
35
36
# File 'lib/ruby_smb/dcerpc/client.rb', line 34

def ntlm_client
  @ntlm_client
end

#os_versionString

Returns:

  • (String)


74
75
76
# File 'lib/ruby_smb/dcerpc/client.rb', line 74

def os_version
  @os_version
end

#passwordString

Returns:

  • (String)


44
45
46
# File 'lib/ruby_smb/dcerpc/client.rb', line 44

def password
  @password
end

#tcp_socketTcpSocket

Returns:

  • (TcpSocket)


85
86
87
# File 'lib/ruby_smb/dcerpc/client.rb', line 85

def tcp_socket
  @tcp_socket
end

#usernameString

Returns:

  • (String)


39
40
41
# File 'lib/ruby_smb/dcerpc/client.rb', line 39

def username
  @username
end

Instance Method Details

#add_auth_verifier(req, auth, auth_type, auth_level) ⇒ Object

Add the authentication verifier to the packet. This includes a sec trailer and the actual authentication data.

Parameters:

  • req (BinData::Record)

    the request to be updated

  • auth (String)

    the authentication data

  • auth_type (Integer)

    the authentication type

  • auth_level (Integer)

    the authentication level



182
183
184
185
186
187
188
189
190
191
192
# File 'lib/ruby_smb/dcerpc/client.rb', line 182

def add_auth_verifier(req, auth, auth_type, auth_level)
  req.sec_trailer = {
    auth_type: auth_type,
    auth_level: auth_level,
    auth_context_id: @ctx_id + @auth_ctx_id_base
  }
  req.auth_value = auth
  req.pdu_header.auth_length = auth.length

  nil
end

#bind(endpoint: @endpoint, auth_level: RPC_C_AUTHN_LEVEL_NONE, auth_type: nil) ⇒ BindAck

Bind to the remote server interface endpoint. It takes care of adding the necessary authentication verifier if :auth_level is set to anything different than RPC_C_AUTHN_LEVEL_NONE

Parameters:

  • endpoint (Module) (defaults to: @endpoint)

    the endpoint to bind to. This must be a Dcerpc class with UUID, VER_MAJOR and VER_MINOR constants defined.

  • auth_level (Integer) (defaults to: RPC_C_AUTHN_LEVEL_NONE)

    the authentication level

  • auth_type (Integer) (defaults to: nil)

    the authentication type

Returns:

  • (BindAck)

    the BindAck response packet

Raises:

  • (Error::InvalidPacket)

    if an invalid packet is received

  • (Error::BindError)

    if the response is not a BindAck packet or if the Bind result code is not ACCEPTANCE

  • (ArgumentError)

    if :auth_type is unknown

  • (NotImplementedError)

    if :auth_type is not implemented (yet)



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
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'lib/ruby_smb/dcerpc/client.rb', line 251

def bind(endpoint: @endpoint, auth_level: RPC_C_AUTHN_LEVEL_NONE, auth_type: nil)
  bind_req = Bind.new(endpoint: endpoint)
  bind_req.pdu_header.call_id = @call_id
  # TODO: evasion: generate random UUIDs for bogus binds

  if auth_level && auth_level != RPC_C_AUTHN_LEVEL_NONE
    case auth_type
    when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
      raise ArgumentError, "NTLM Client not initialized. Username and password must be provided" unless @ntlm_client
      type1_message = @ntlm_client.init_context
      auth = type1_message.serialize
    when RPC_C_AUTHN_GSS_KERBEROS, RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE
    when RPC_C_AUTHN_GSS_KERBEROS, RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL
      # TODO
      raise NotImplementedError
    else
      raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
    end
    add_auth_verifier(bind_req, auth, auth_type, auth_level)
  end

  send_packet(bind_req)
  bindack_response = recv_struct(BindAck)
  # TODO: see if BindNack response should be handled too

  res_list = bindack_response.p_result_list
  if res_list.n_results == 0 ||
     res_list.p_results[0].result != BindAck::ACCEPTANCE
    raise Error::BindError,
      "Bind Failed (Result: #{res_list.p_results[0].result}, Reason: #{res_list.p_results[0].reason})"
  end

  @max_buffer_size = bindack_response.max_xmit_frag
  @call_id = bindack_response.pdu_header.call_id

  if auth_level && auth_level != RPC_C_AUTHN_LEVEL_NONE
     # The number of legs needed to build the security context is defined
     # by the security provider
     # (see [2.2.1.1.7 Security Providers](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/d4097450-c62f-484b-872f-ddf59a7a0d36))
    case auth_type
    when RPC_C_AUTHN_WINNT
      send_auth3(bindack_response, auth_type, auth_level)
    when RPC_C_AUTHN_GSS_KERBEROS, RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE
      # TODO
      raise NotImplementedError
    end
  end

  nil
end

#closeObject

Close the TCP Socket



171
172
173
# File 'lib/ruby_smb/dcerpc/client.rb', line 171

def close
  @tcp_socket.close if @tcp_socket && !@tcp_socket.closed?
end

#connect(port: nil) ⇒ TcpSocket

Connect to the RPC endpoint. If a TCP socket was not provided, it takes care of asking the Enpoint Mapper Interface the port used by the given endpoint provided in #initialize and connect a TCP socket

Parameters:

  • port (Integer) (defaults to: nil)

    An optional port number to connect to. If provided, it will not ask the Enpoint Mapper Interface for a port number.

Returns:

  • (TcpSocket)

    The connected TCP socket



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
# File 'lib/ruby_smb/dcerpc/client.rb', line 144

def connect(port: nil)
  return if @tcp_socket
  unless port
    @tcp_socket = TCPSocket.new(@host, ENDPOINT_MAPPER_PORT)
    bind(endpoint: Epm)
    begin
      host_port = get_host_port_from_ept_mapper(
        uuid: @endpoint::UUID,
        maj_ver: @endpoint::VER_MAJOR,
        min_ver: @endpoint::VER_MINOR
      )
    rescue RubySMB::Dcerpc::Error::DcerpcError => e
      e.message.prepend(
        "Cannot resolve the remote port number for endpoint #{@endpoint::UUID}. "\
        "Set @tcp_socket parameter to specify the service port number and bypass "\
        "EPM port resolution. Error: "
      )
      raise e
    end
    port = host_port[:port]
    @tcp_socket.close
    @tcp_socket = nil
  end
  @tcp_socket = TCPSocket.new(@host, port)
end

#dcerpc_request(stub_packet, auth_level: nil, auth_type: nil) ⇒ Object

Send a DCERPC request with the provided stub packet.

Parameters:

  • stub_packet (BinData::Record)

    the stub packet to be sent as part of a Request packet

  • opts (Hash)

    the authenticaiton options: :auth_type and :auth_level

Raises:



393
394
395
396
397
398
399
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
# File 'lib/ruby_smb/dcerpc/client.rb', line 393

def dcerpc_request(stub_packet, auth_level: nil, auth_type: nil)
  stub_class = stub_packet.class.name.split('::')
  #opts.merge!(endpoint: stub_class[-2])
  values = {
    opnum: stub_packet.opnum,
    p_cont_id: @ctx_id
  }
  dcerpc_req = Request.new(values, { endpoint: stub_class[-2] })
  dcerpc_req.pdu_header.call_id = @call_id
  dcerpc_req.stub.read(stub_packet.to_binary_s)
  # TODO: handle fragmentation
  # We should fragment PDUs if:
  # 1) Payload exceeds max_xmit_frag (@max_buffer_size) received during BIND response
  # 2) We'e explicitly fragmenting packets with lower values

  if auth_level &&
     [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(auth_level)
    set_integrity_privacy(dcerpc_req, auth_level: auth_level, auth_type: auth_type)
  end

  send_packet(dcerpc_req)

  dcerpc_res = recv_struct(Response)
  unless dcerpc_res.pdu_header.pfc_flags.first_frag == 1
    raise Error::InvalidPacket, "Not the first fragment"
  end

  if auth_level &&
     [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(auth_level)
    handle_integrity_privacy(dcerpc_res, auth_level: auth_level, auth_type: auth_type)
  end

  raw_stub = dcerpc_res.stub.to_binary_s
  loop do
    break if dcerpc_res.pdu_header.pfc_flags.last_frag == 1
    dcerpc_res = recv_struct(Response)

    if auth_level &&
       [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(auth_level)
      handle_integrity_privacy(dcerpc_res, auth_level: auth_level, auth_type: auth_type)
    end

    raw_stub << dcerpc_res.stub.to_binary_s
  end

  raw_stub
end

#extract_os_version(version) ⇒ String

Extract the peer/server version number from the NTLM Type 2 (challenge) Version field.

Parameters:

  • version (String)

    the version number as a binary string

Returns:

  • (String)

    the formated version number (..)



328
329
330
331
332
333
334
335
336
# File 'lib/ruby_smb/dcerpc/client.rb', line 328

def extract_os_version(version)
  #version.unpack('CCS').join('.')
  begin
    os_version = NTLM::OSVersion.read(version)
  rescue IOError
    return ''
  end
  return "#{os_version.major}.#{os_version.minor}.#{os_version.build}"
end

#handle_integrity_privacy(dcerpc_response, auth_level:, auth_type:, raise_signature_error: false) ⇒ Object

Process the security context received in a response. It decrypts the encrypted stub if :auth_level is set to anything different than RPC_C_AUTHN_LEVEL_PKT_PRIVACY. It also checks the packet signature and raises an InvalidPacket error if it fails. Note that the exception is disabled by default and can be enabled with the :raise_signature_error option

Parameters:

  • dcerpc_response (Response)

    the Response packet containing the security context to process

  • opts (Hash)

    the authenticaiton options: :auth_type and :auth_level. To enable errors when signature check fails, set the :raise_signature_error option to true

Raises:

  • (NotImplementedError)

    if :auth_type is not implemented (yet)

  • (Error::CommunicationError)

    if socket-related error occurs



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
# File 'lib/ruby_smb/dcerpc/client.rb', line 499

def handle_integrity_privacy(dcerpc_response, auth_level:, auth_type:, raise_signature_error: false)
  decrypted_stub = ''
  if auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY
    encrypted_stub = dcerpc_response.stub.to_binary_s + dcerpc_response.auth_pad.to_binary_s
    case auth_type
    when RPC_C_AUTHN_NONE
    when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
      decrypted_stub = @ntlm_client.session.unseal_message(encrypted_stub)
    when RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL, RPC_C_AUTHN_GSS_KERBEROS
      # TODO
      raise NotImplementedError
    else
      raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
    end
  end

  unless decrypted_stub.empty?
    pad_length = dcerpc_response.sec_trailer.auth_pad_length.to_i
    dcerpc_response.stub = decrypted_stub[0..-(pad_length + 1)]
    dcerpc_response.auth_pad = decrypted_stub[-(pad_length)..-1]
  end

  signature = dcerpc_response.auth_value
  data_to_check = dcerpc_response.stub.to_binary_s
  if @ntlm_client.flags & NTLM::NEGOTIATE_FLAGS[:EXTENDED_SECURITY] != 0
    data_to_check = dcerpc_response.to_binary_s[0..-(dcerpc_response.pdu_header.auth_length + 1)]
  end
  unless @ntlm_client.session.verify_signature(signature, data_to_check)
    if raise_signature_error
      raise Error::InvalidPacket.new(
        "Wrong packet signature received (set `raise_signature_error` to false to ignore)"
      )
    end
  end

  @call_id += 1

  nil
end

#process_ntlm_type2(type2_message) ⇒ Object



194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/ruby_smb/dcerpc/client.rb', line 194

def process_ntlm_type2(type2_message)
  ntlmssp_offset = type2_message.index('NTLMSSP')
  type2_blob = type2_message.slice(ntlmssp_offset..-1)
  type2_b64_message = [type2_blob].pack('m')
  type3_message = @ntlm_client.init_context(type2_b64_message)
  auth3 = type3_message.serialize

  @session_key = @ntlm_client.session_key
  challenge_message = @ntlm_client.session.challenge_message
  store_target_info(challenge_message.target_info) if challenge_message.has_flag?(:TARGET_INFO)
  @os_version = extract_os_version(challenge_message.os_version.to_s) unless challenge_message.os_version.empty?
  auth3
end

#recv_struct(struct) ⇒ Object

Receive a packet from the remote host and parse it according to struct

Parameters:

  • struct (Class)

    the structure class to parse the response with

Raises:



465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
# File 'lib/ruby_smb/dcerpc/client.rb', line 465

def recv_struct(struct)
  raise Error::CommunicationError, 'Connection has already been closed' if @tcp_socket.closed?
  if IO.select([@tcp_socket], nil, nil, @read_timeout).nil?
    raise Error::CommunicationError, "Read timeout expired when reading from the Socket (timeout=#{@read_timeout})"
  end

  begin
    response = struct.read(@tcp_socket)
  rescue IOError
    raise Error::InvalidPacket, "Error reading the #{struct} response"
  end
  unless response.pdu_header.ptype == struct::PTYPE
    raise Error::InvalidPacket, "Not a #{struct} packet"
  end

  response
rescue Errno::EINVAL, Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE => e
  raise Error::CommunicationError, "An error occurred reading from the Socket: #{e.message}"
end

#send_auth3(response, auth_type, auth_level) ⇒ Object

Send a rpc_auth3 PDU that ends the authentication handshake.

Parameters:

  • response (BindAck)

    the BindAck response packet

  • auth_type (Integer)

    the authentication type

  • auth_level (Integer)

    the authentication level

Raises:

  • (ArgumentError)

    if :auth_type is unknown

  • (NotImplementedError)

    if :auth_type is not implemented (yet)



215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/ruby_smb/dcerpc/client.rb', line 215

def send_auth3(response, auth_type, auth_level)
  case auth_type
  when RPC_C_AUTHN_NONE
  when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
    auth3 = process_ntlm_type2(response.auth_value)
  when RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL, RPC_C_AUTHN_GSS_KERBEROS
    # TODO
    raise NotImplementedError
  else
    raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
  end

  rpc_auth3 = RpcAuth3.new
  add_auth_verifier(rpc_auth3, auth3, auth_type, auth_level)
  rpc_auth3.pdu_header.call_id = @call_id

  # The server should not respond
  send_packet(rpc_auth3)
  @call_id += 1

  nil
end

#send_packet(packet) ⇒ Object

Send a packet to the remote host

Parameters:

  • packet (BinData::Record)

    the packet to send

Raises:



445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
# File 'lib/ruby_smb/dcerpc/client.rb', line 445

def send_packet(packet)
  data = packet.to_binary_s
  bytes_written = 0
  begin
    loop do
      break unless bytes_written < data.size
      retval = @tcp_socket.write(data[bytes_written..-1])
      bytes_written += retval
    end

  rescue IOError, Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE => e
    raise Error::CommunicationError, "An error occurred writing to the Socket: #{e.message}"
  end
  nil
end

#set_integrity_privacy(dcerpc_req, auth_level:, auth_type:) ⇒ Object

Add the authentication verifier to a Request packet. This includes a sec trailer and the signature of the packet. This also encrypts the Request stub if privacy is required (:auth_level option is RPC_C_AUTHN_LEVEL_PKT_PRIVACY).

Parameters:

  • dcerpc_req (Request)

    the Request packet to be updated

  • opts (Hash)

    the authenticaiton options: :auth_type and :auth_level

Raises:

  • (NotImplementedError)

    if :auth_type is not implemented (yet)

  • (ArgumentError)

    if :auth_type is unknown



347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
# File 'lib/ruby_smb/dcerpc/client.rb', line 347

def set_integrity_privacy(dcerpc_req, auth_level:, auth_type:)
  dcerpc_req.sec_trailer = {
    auth_type: auth_type,
    auth_level: auth_level,
    auth_context_id: @ctx_id + @auth_ctx_id_base
  }
  dcerpc_req.auth_value = ' ' * 16
  dcerpc_req.pdu_header.auth_length = 16

  data_to_sign = plain_stub = dcerpc_req.stub.to_binary_s + dcerpc_req.auth_pad.to_binary_s
  if @ntlm_client.flags & NTLM::NEGOTIATE_FLAGS[:EXTENDED_SECURITY] != 0
    data_to_sign = dcerpc_req.to_binary_s[0..-(dcerpc_req.pdu_header.auth_length + 1)]
  end

  encrypted_stub = ''
  if auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY
    case auth_type
    when RPC_C_AUTHN_NONE
    when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
      encrypted_stub = @ntlm_client.session.seal_message(plain_stub)
    when RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL, RPC_C_AUTHN_GSS_KERBEROS
      # TODO
      raise NotImplementedError
    else
      raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
    end
  end

  signature = @ntlm_client.session.sign_message(data_to_sign)

  unless encrypted_stub.empty?
    pad_length = dcerpc_req.sec_trailer.auth_pad_length.to_i
    dcerpc_req.enable_encrypted_stub
    dcerpc_req.stub = encrypted_stub[0..-(pad_length + 1)]
    dcerpc_req.auth_pad = encrypted_stub[-(pad_length)..-1]
  end
  dcerpc_req.auth_value = signature
  dcerpc_req.pdu_header.auth_length = signature.size
end

#store_target_info(target_info_str) ⇒ Object

Extract and store useful information about the peer/server from the NTLM Type 2 (challenge) TargetInfo fields.

Parameters:

  • target_info_str (String)

    the Target Info string



306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
# File 'lib/ruby_smb/dcerpc/client.rb', line 306

def store_target_info(target_info_str)
  target_info = Net::NTLM::TargetInfo.new(target_info_str)
  {
    Net::NTLM::TargetInfo::MSV_AV_NB_COMPUTER_NAME  => :@default_name,
    Net::NTLM::TargetInfo::MSV_AV_NB_DOMAIN_NAME    => :@default_domain,
    Net::NTLM::TargetInfo::MSV_AV_DNS_COMPUTER_NAME => :@dns_host_name,
    Net::NTLM::TargetInfo::MSV_AV_DNS_DOMAIN_NAME   => :@dns_domain_name,
    Net::NTLM::TargetInfo::MSV_AV_DNS_TREE_NAME     => :@dns_tree_name
  }.each do |constant, attribute|
    if target_info.av_pairs[constant]
      value = target_info.av_pairs[constant].dup
      value.force_encoding('UTF-16LE')
      instance_variable_set(attribute, value.encode('UTF-8'))
    end
  end
end