Module: RubySMB::Dcerpc

Included in:
Client, SMB1::Pipe, SMB2::Pipe
Defined in:
lib/ruby_smb/dcerpc/error.rb,
lib/ruby_smb/dcerpc.rb,
lib/ruby_smb/dcerpc/epm.rb,
lib/ruby_smb/dcerpc/bind.rb,
lib/ruby_smb/dcerpc/drsr.rb,
lib/ruby_smb/dcerpc/icpr.rb,
lib/ruby_smb/dcerpc/samr.rb,
lib/ruby_smb/dcerpc/uuid.rb,
lib/ruby_smb/dcerpc/dfsnm.rb,
lib/ruby_smb/dcerpc/client.rb,
lib/ruby_smb/dcerpc/efsrpc.rb,
lib/ruby_smb/dcerpc/lsarpc.rb,
lib/ruby_smb/dcerpc/ptypes.rb,
lib/ruby_smb/dcerpc/srvsvc.rb,
lib/ruby_smb/dcerpc/svcctl.rb,
lib/ruby_smb/dcerpc/winreg.rb,
lib/ruby_smb/dcerpc/wkssvc.rb,
lib/ruby_smb/dcerpc/request.rb,
lib/ruby_smb/dcerpc/bind_ack.rb,
lib/ruby_smb/dcerpc/netlogon.rb,
lib/ruby_smb/dcerpc/response.rb,
lib/ruby_smb/dcerpc/rpc_auth3.rb,
lib/ruby_smb/dcerpc/p_result_t.rb,
lib/ruby_smb/dcerpc/pdu_header.rb,
lib/ruby_smb/dcerpc/port_any_t.rb,
lib/ruby_smb/dcerpc/sec_trailer.rb,
lib/ruby_smb/dcerpc/epm/epm_twrt.rb,
lib/ruby_smb/dcerpc/print_system.rb,
lib/ruby_smb/dcerpc/samr/rpc_sid.rb,
lib/ruby_smb/dcerpc/alter_context.rb,
lib/ruby_smb/dcerpc/p_cont_list_t.rb,
lib/ruby_smb/dcerpc/p_syntax_id_t.rb,
lib/ruby_smb/dcerpc/winreg/regsam.rb,
lib/ruby_smb/dcerpc/p_result_list_t.rb,
lib/ruby_smb/dcerpc/alter_context_resp.rb,
lib/ruby_smb/dcerpc/drsr/drs_extensions.rb,
lib/ruby_smb/dcerpc/drsr/drs_bind_request.rb,
lib/ruby_smb/dcerpc/svcctl/service_status.rb,
lib/ruby_smb/dcerpc/drsr/drs_bind_response.rb,
lib/ruby_smb/dcerpc/rrp_rpc_unicode_string.rb,
lib/ruby_smb/dcerpc/drsr/drs_unbind_request.rb,
lib/ruby_smb/dcerpc/epm/epm_ept_map_request.rb,
lib/ruby_smb/dcerpc/rpc_security_attributes.rb,
lib/ruby_smb/dcerpc/winreg/enum_key_request.rb,
lib/ruby_smb/dcerpc/winreg/open_key_request.rb,
lib/ruby_smb/dcerpc/winreg/save_key_request.rb,
lib/ruby_smb/dcerpc/drsr/drs_unbind_response.rb,
lib/ruby_smb/dcerpc/epm/epm_ept_map_response.rb,
lib/ruby_smb/dcerpc/winreg/close_key_request.rb,
lib/ruby_smb/dcerpc/winreg/enum_key_response.rb,
lib/ruby_smb/dcerpc/winreg/open_key_response.rb,
lib/ruby_smb/dcerpc/winreg/save_key_response.rb,
lib/ruby_smb/dcerpc/samr/samr_connect_request.rb,
lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb,
lib/ruby_smb/dcerpc/winreg/close_key_response.rb,
lib/ruby_smb/dcerpc/winreg/create_key_request.rb,
lib/ruby_smb/dcerpc/winreg/enum_value_request.rb,
lib/ruby_smb/dcerpc/samr/samr_connect_response.rb,
lib/ruby_smb/dcerpc/winreg/create_key_response.rb,
lib/ruby_smb/dcerpc/winreg/enum_value_response.rb,
lib/ruby_smb/dcerpc/winreg/query_value_request.rb,
lib/ruby_smb/dcerpc/samr/samr_open_user_request.rb,
lib/ruby_smb/dcerpc/winreg/query_value_response.rb,
lib/ruby_smb/dcerpc/drsr/drs_crack_names_request.rb,
lib/ruby_smb/dcerpc/samr/samr_open_group_request.rb,
lib/ruby_smb/dcerpc/samr/samr_open_user_response.rb,
lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_request.rb,
lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb,
lib/ruby_smb/dcerpc/drsr/drs_crack_names_response.rb,
lib/ruby_smb/dcerpc/samr/sampr_domain_info_buffer.rb,
lib/ruby_smb/dcerpc/samr/samr_delete_user_request.rb,
lib/ruby_smb/dcerpc/samr/samr_open_domain_request.rb,
lib/ruby_smb/dcerpc/samr/samr_open_group_response.rb,
lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_response.rb,
lib/ruby_smb/dcerpc/svcctl/delete_service_request.rb,
lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb,
lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb,
lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb,
lib/ruby_smb/dcerpc/samr/samr_close_handle_request.rb,
lib/ruby_smb/dcerpc/samr/samr_delete_user_response.rb,
lib/ruby_smb/dcerpc/samr/samr_open_domain_response.rb,
lib/ruby_smb/dcerpc/svcctl/control_service_request.rb,
lib/ruby_smb/dcerpc/svcctl/delete_service_response.rb,
lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb,
lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb,
lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb,
lib/ruby_smb/dcerpc/drsr/drs_get_nc_changes_request.rb,
lib/ruby_smb/dcerpc/lsarpc/lsar_lookup_sids_request.rb,
lib/ruby_smb/dcerpc/lsarpc/lsar_open_policy_request.rb,
lib/ruby_smb/dcerpc/samr/samr_close_handle_response.rb,
lib/ruby_smb/dcerpc/svcctl/control_service_response.rb,
lib/ruby_smb/dcerpc/svcctl/create_service_w_request.rb,
lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb,
lib/ruby_smb/dcerpc/winreg/get_key_security_request.rb,
lib/ruby_smb/dcerpc/winreg/set_key_security_request.rb,
lib/ruby_smb/dcerpc/drsr/drs_get_nc_changes_response.rb,
lib/ruby_smb/dcerpc/icpr/cert_server_request_request.rb,
lib/ruby_smb/dcerpc/lsarpc/lsar_close_handle_request.rb,
lib/ruby_smb/dcerpc/lsarpc/lsar_lookup_sids_response.rb,
lib/ruby_smb/dcerpc/lsarpc/lsar_open_policy2_request.rb,
lib/ruby_smb/dcerpc/lsarpc/lsar_open_policy_response.rb,
lib/ruby_smb/dcerpc/netlogon/domain_controller_infow.rb,
lib/ruby_smb/dcerpc/svcctl/create_service_w_response.rb,
lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb,
lib/ruby_smb/dcerpc/winreg/get_key_security_response.rb,
lib/ruby_smb/dcerpc/winreg/set_key_security_response.rb,
lib/ruby_smb/dcerpc/icpr/cert_server_request_response.rb,
lib/ruby_smb/dcerpc/lsarpc/lsar_close_handle_response.rb,
lib/ruby_smb/dcerpc/lsarpc/lsar_open_policy2_response.rb,
lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb,
lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_request.rb,
lib/ruby_smb/dcerpc/dfsnm/netr_dfs_add_std_root_request.rb,
lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb,
lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb,
lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_response.rb,
lib/ruby_smb/dcerpc/wkssvc/netr_wksta_user_enum_request.rb,
lib/ruby_smb/dcerpc/dfsnm/netr_dfs_add_std_root_response.rb,
lib/ruby_smb/dcerpc/efsrpc/efs_rpc_open_file_raw_request.rb,
lib/ruby_smb/dcerpc/netlogon/dsr_get_dc_name_ex2_request.rb,
lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb,
lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb,
lib/ruby_smb/dcerpc/wkssvc/netr_wksta_user_enum_response.rb,
lib/ruby_smb/dcerpc/efsrpc/efs_rpc_open_file_raw_response.rb,
lib/ruby_smb/dcerpc/netlogon/dsr_get_dc_name_ex2_response.rb,
lib/ruby_smb/dcerpc/samr/samr_get_groups_for_user_request.rb,
lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb,
lib/ruby_smb/dcerpc/dfsnm/netr_dfs_remove_std_root_request.rb,
lib/ruby_smb/dcerpc/samr/samr_get_alias_membership_request.rb,
lib/ruby_smb/dcerpc/samr/samr_get_groups_for_user_response.rb,
lib/ruby_smb/dcerpc/samr/samr_get_members_in_group_request.rb,
lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb,
lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb,
lib/ruby_smb/dcerpc/dfsnm/netr_dfs_remove_std_root_response.rb,
lib/ruby_smb/dcerpc/drsr/drs_domain_controller_info_request.rb,
lib/ruby_smb/dcerpc/efsrpc/efs_rpc_decrypt_file_srv_request.rb,
lib/ruby_smb/dcerpc/efsrpc/efs_rpc_encrypt_file_srv_request.rb,
lib/ruby_smb/dcerpc/samr/samr_get_alias_membership_response.rb,
lib/ruby_smb/dcerpc/samr/samr_get_members_in_group_response.rb,
lib/ruby_smb/dcerpc/samr/samr_set_information_user2_request.rb,
lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb,
lib/ruby_smb/dcerpc/drsr/drs_domain_controller_info_response.rb,
lib/ruby_smb/dcerpc/efsrpc/efs_rpc_decrypt_file_srv_response.rb,
lib/ruby_smb/dcerpc/efsrpc/efs_rpc_encrypt_file_srv_response.rb,
lib/ruby_smb/dcerpc/samr/samr_create_user2_in_domain_request.rb,
lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_request.rb,
lib/ruby_smb/dcerpc/samr/samr_set_information_user2_response.rb,
lib/ruby_smb/dcerpc/samr/samr_create_user2_in_domain_response.rb,
lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_response.rb,
lib/ruby_smb/dcerpc/efsrpc/efs_rpc_query_users_on_file_request.rb,
lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request.rb,
lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request.rb,
lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request.rb,
lib/ruby_smb/dcerpc/samr/samr_query_information_domain_request.rb,
lib/ruby_smb/dcerpc/efsrpc/efs_rpc_query_users_on_file_response.rb,
lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response.rb,
lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response.rb,
lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response.rb,
lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_request.rb,
lib/ruby_smb/dcerpc/samr/samr_query_information_domain_response.rb,
lib/ruby_smb/dcerpc/efsrpc/efs_rpc_query_recovery_agents_request.rb,
lib/ruby_smb/dcerpc/lsarpc/lsar_query_information_policy_request.rb,
lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response.rb,
lib/ruby_smb/dcerpc/efsrpc/efs_rpc_query_recovery_agents_response.rb,
lib/ruby_smb/dcerpc/lsarpc/lsar_query_information_policy2_request.rb,
lib/ruby_smb/dcerpc/lsarpc/lsar_query_information_policy_response.rb,
lib/ruby_smb/dcerpc/print_system/rpc_enum_printer_drivers_request.rb,
lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_request.rb,
lib/ruby_smb/dcerpc/lsarpc/lsar_query_information_policy2_response.rb,
lib/ruby_smb/dcerpc/print_system/rpc_add_printer_driver_ex_request.rb,
lib/ruby_smb/dcerpc/print_system/rpc_enum_printer_drivers_response.rb,
lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_response.rb,
lib/ruby_smb/dcerpc/print_system/rpc_add_printer_driver_ex_response.rb,
lib/ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_request.rb,
lib/ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_response.rb,
lib/ruby_smb/dcerpc/print_system/rpc_get_printer_driver_directory_request.rb,
lib/ruby_smb/dcerpc/print_system/rpc_get_printer_driver_directory_response.rb

Overview

Contains all the DCERPC specific Error classes.

Defined Under Namespace

Modules: Dfsnm, Drsr, Efsrpc, Epm, Error, Fault, Icpr, Lsarpc, Ndr, Netlogon, PTypes, PrintSystem, Samr, Srvsvc, Svcctl, Winreg, Wkssvc Classes: AlterContext, AlterContextResp, Bind, BindAck, Client, PContElemT, PContListT, PDUHeader, PResultListT, PResultT, PSyntaxIdT, PortAnyT, PrpcSecurityAttributes, PrpcUnicodeString, PrrpUnicodeString, Request, Response, RpcAuth3, RpcSecurityAttributes, RpcSecurityDescriptor, RpcUnicodeString, RpcUnicodeStringConfVarArray, RrpUnicodeString, SecTrailer, Uuid

Constant Summary collapse

MAX_XMIT_FRAG =
4280
MAX_RECV_FRAG =
4280
RPC_C_AUTHN_LEVEL_DEFAULT =
0
RPC_C_AUTHN_LEVEL_NONE =
1
RPC_C_AUTHN_LEVEL_CONNECT =
2
RPC_C_AUTHN_LEVEL_CALL =
3
RPC_C_AUTHN_LEVEL_PKT =
4
RPC_C_AUTHN_LEVEL_PKT_INTEGRITY =
5
RPC_C_AUTHN_LEVEL_PKT_PRIVACY =
6
RPC_C_AUTHN_NONE =
0x00
RPC_C_AUTHN_GSS_NEGOTIATE =
0x09
RPC_C_AUTHN_WINNT =
0x0A
RPC_C_AUTHN_GSS_SCHANNEL =
0x0E
RPC_C_AUTHN_GSS_KERBEROS =
0x10
RPC_C_AUTHN_NETLOGON =
0x44
RPC_C_AUTHN_DEFAULT =
0xFF
DCE_C_AUTHZ_NAME =
1
DCE_C_AUTHZ_DCE =
2

Instance Method Summary collapse

Instance Method Details

#add_auth_verifier(req, auth) ⇒ 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



354
355
356
357
358
359
360
361
362
363
364
# File 'lib/ruby_smb/dcerpc.rb', line 354

def add_auth_verifier(req, auth)
  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

#auth_provider_complete_handshake(response, options) ⇒ Object

Send a rpc_auth3 PDU that ends the authentication handshake. This function should be overriden for other providers (e.g. Kerberos, etc.)

Parameters:

  • response (BindAck)

    the BindAck response packet

  • options (Hash)

    Unused by the NTLM auth provider



157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/ruby_smb/dcerpc.rb', line 157

def auth_provider_complete_handshake(response, options)
  auth3 = process_ntlm_type2(response.auth_value)

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

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

  nil
end

#auth_provider_decrypt_and_verify(dcerpc_response) ⇒ Boolean

Decrypt the value in dcerpc_req.stub, and validate its signature. This function modifies the request object in-place, and returns whether the signature was valid. This function should be overriden for other providers (e.g. Kerberos, etc.)

Parameters:

  • dcerpc_response (Response)

    The Response packet to decrypt and verify in-place

Returns:

  • (Boolean)

    Is the packet's signature valid?

Raises:

  • ArgumentError If the auth type is not NTLM



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/ruby_smb/dcerpc.rb', line 117

def auth_provider_decrypt_and_verify(dcerpc_response)
  auth_type = dcerpc_response.sec_trailer.auth_type
  auth_level = dcerpc_response.sec_trailer.auth_level
  unless [RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT].include?(auth_type)
    raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
  end
  signature = dcerpc_response.auth_value
  if auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY
    encrypted_stub = get_response_full_stub(dcerpc_response)
    plaintext = @ntlm_client.session.unseal_message(encrypted_stub)
    set_decrypted_packet(dcerpc_response, plaintext)
  end
  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

  @ntlm_client.session.verify_signature(signature, data_to_check)
end

#auth_provider_encrypt_and_sign(dcerpc_req) ⇒ Object

Encrypt the value in dcerpc_req.stub, and add a valid signature to the request. This function modifies the request object in-place, and does not return anything. This function should be overriden for other providers (e.g. Kerberos, etc.)

Parameters:

  • dcerpc_req (Request)

    The Request object to be encrypted and signed in-place



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/ruby_smb/dcerpc.rb', line 80

def auth_provider_encrypt_and_sign(dcerpc_req)
  auth_type = dcerpc_req.sec_trailer.auth_type
  auth_level = dcerpc_req.sec_trailer.auth_level
  unless [RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT].include?(auth_type)
    raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
  end
  plaintext = dcerpc_req.stub.to_binary_s
  pad_length = get_auth_padding_length(plaintext.length)
  dcerpc_req.auth_pad = "\x00" * pad_length
  data_to_sign = plain_stub_with_padding = dcerpc_req.stub.to_binary_s + dcerpc_req.auth_pad.to_binary_s
  dcerpc_req.sec_trailer.auth_pad_length = pad_length
  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

  if auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY
    encrypted = @ntlm_client.session.seal_message(plain_stub_with_padding)
    set_encrypted_packet(dcerpc_req, encrypted, pad_length)
  end
  signature = @ntlm_client.session.sign_message(data_to_sign)

  set_signature_on_packet(dcerpc_req, signature)
end

#auth_provider_initObject

Initialize the auth provider using NTLM. This function should be overriden for other providers (e.g. Kerberos, etc.)

Returns:

  • Serialized message for initializing the auth provider (NTLM, unless this class is extended/overridden)

Raises:

  • ArgumentError If @ntlm_client isn't initialized with a username and password.



69
70
71
72
73
74
# File 'lib/ruby_smb/dcerpc.rb', line 69

def auth_provider_init
  raise ArgumentError, "NTLM Client not initialized. Username and password must be provided" unless @ntlm_client
  type1_message = @ntlm_client.init_context

  type1_message.serialize
end

#bind(options = {}) ⇒ 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:

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :endpoint (Module)

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

  • :auth_level (Integer)

    the authentication level

  • :auth_type (Integer)

    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)



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

def bind(options={})
  @call_id ||= 1
  bind_req = Bind.new(options)
  bind_req.pdu_header.call_id = @call_id
  auth_type = options.fetch(:auth_type) { RPC_C_AUTHN_WINNT }
  auth_level = options.fetch(:auth_level) { RPC_C_AUTHN_LEVEL_NONE }

  force_set_auth_params(auth_type, auth_level)

  if @auth_level != RPC_C_AUTHN_LEVEL_NONE
    @ctx_id            = 0
    @auth_ctx_id_base  = rand(0xFFFFFFFF)
    auth = auth_provider_init
    add_auth_verifier(bind_req, auth)
  end

  send_packet(bind_req)
  begin
    dcerpc_response = recv_struct(BindAck)
  rescue Error::InvalidPacket
    raise Error::BindError # raise the more context-specific BindError
  end
  # TODO: see if BindNack response should be handled too

  res_list = dcerpc_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
  self.max_buffer_size = dcerpc_response.max_xmit_frag
  @call_id = dcerpc_response.pdu_header.call_id

  if 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://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/d4097450-c62f-484b-872f-ddf59a7a0d36))
    auth_provider_complete_handshake(dcerpc_response, options)
  end

  dcerpc_response
end

#force_set_auth_params(auth_type, auth_level) ⇒ Object



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

def force_set_auth_params(auth_type, auth_level)
  @auth_type = auth_type
  @auth_level = auth_level
end

#get_auth_padding_length(plaintext_len) ⇒ Object



264
265
266
# File 'lib/ruby_smb/dcerpc.rb', line 264

def get_auth_padding_length(plaintext_len)
  (16 - (plaintext_len % 16)) % 16
end

#get_response_full_stub(dcerpc_response) ⇒ String

Get the response's full stub value (which will include the auth-pad)

Parameters:

  • dcerpc_response (Response)

    The Response object to extract from

Returns:

  • (String)

    The full stub, including auth_pad



107
108
109
# File 'lib/ruby_smb/dcerpc.rb', line 107

def get_response_full_stub(dcerpc_response)
  dcerpc_response.stub.to_binary_s + dcerpc_response.auth_pad.to_binary_s
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 authentication 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



330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
# File 'lib/ruby_smb/dcerpc.rb', line 330

def handle_integrity_privacy(dcerpc_response, auth_level:, auth_type:, raise_signature_error: false)
  unless [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(auth_level)
    raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
  end
  signature_valid = auth_provider_decrypt_and_verify(dcerpc_response)

  unless signature_valid
    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

#max_buffer_size=(value) ⇒ Object



234
235
236
# File 'lib/ruby_smb/dcerpc.rb', line 234

def max_buffer_size=(value)
  @tree.client.max_buffer_size = value
end

#process_ntlm_type2(type2_message) ⇒ String

Completes local initialisation of @ntlm_client using the server's response

Parameters:

  • type2_message (String)

    NTLM type 2 message sent from server

Returns:

  • (String)

    Type 3 message to be sent to the server to complete the NTLM handshake



141
142
143
144
145
146
147
148
149
150
# File 'lib/ruby_smb/dcerpc.rb', line 141

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
  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



241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/ruby_smb/dcerpc.rb', line 241

def recv_struct(struct)
  raw_response = read
  begin
    response = struct.read(raw_response)
  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
end

#send_packet(packet) ⇒ Object

Send a packet to the remote host

Parameters:

  • packet (BinData::Record)

    the packet to send

Raises:



259
260
261
262
# File 'lib/ruby_smb/dcerpc.rb', line 259

def send_packet(packet)
  write(data: packet.to_binary_s)
  nil
end

#set_decrypted_packet(dcerpc_response, decrypted_stub) ⇒ Object



308
309
310
311
312
313
314
# File 'lib/ruby_smb/dcerpc.rb', line 308

def set_decrypted_packet(dcerpc_response, decrypted_stub)
  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)..-1]
  end
end

#set_encrypted_packet(dcerpc_req, encrypted_stub, pad_length) ⇒ Object



298
299
300
301
302
303
304
305
306
# File 'lib/ruby_smb/dcerpc.rb', line 298

def set_encrypted_packet(dcerpc_req, encrypted_stub, pad_length)
  unless encrypted_stub.empty?
    dcerpc_req.enable_encrypted_stub
    dcerpc_req.stub = encrypted_stub[0..-(pad_length+1)]
    if pad_length != 0
      dcerpc_req.auth_pad = encrypted_stub[-(pad_length)..-1]
    end
  end
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 authentication options: :auth_type and :auth_level

Raises:

  • (NotImplementedError)

    if :auth_type is not implemented (yet)

  • (ArgumentError)

    if :auth_type is unknown



277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/ruby_smb/dcerpc.rb', line 277

def set_integrity_privacy(dcerpc_req, auth_level:, auth_type:)
  unless [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(auth_level)
    raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
  end

  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

  auth_provider_encrypt_and_sign(dcerpc_req)
end

#set_signature_on_packet(dcerpc_req, signature) ⇒ Object



293
294
295
296
# File 'lib/ruby_smb/dcerpc.rb', line 293

def set_signature_on_packet(dcerpc_req, signature)
  dcerpc_req.auth_value = signature
  dcerpc_req.pdu_header.auth_length = signature.size
end