Class: RubySMB::Client
- Inherits:
-
Object
- Object
- RubySMB::Client
- Includes:
- Authentication, Echo, Encryption, Negotiation, TreeConnect, Utils, Winreg, NTLM, Signing
- Defined in:
- lib/ruby_smb/client.rb,
lib/ruby_smb/client/echo.rb,
lib/ruby_smb/client/utils.rb,
lib/ruby_smb/client/winreg.rb,
lib/ruby_smb/client/encryption.rb,
lib/ruby_smb/client/negotiation.rb,
lib/ruby_smb/client/tree_connect.rb,
lib/ruby_smb/client/authentication.rb
Overview
This module holds all of the methods backing the #open_file method
Defined Under Namespace
Modules: Authentication, Echo, Encryption, Negotiation, TreeConnect, Utils, Winreg
Constant Summary collapse
- SMB1_DIALECT_SMB1_DEFAULT =
The Default SMB1 Dialect string used in an SMB1 Negotiate Request
'NT LM 0.12'.freeze
- SMB1_DIALECT_SMB2_DEFAULT =
The Default SMB2 Dialect string used in an SMB1 Negotiate Request
'SMB 2.002'.freeze
- SMB1_DIALECT_SMB2_WILDCARD =
The SMB2 wildcard revision number Dialect string used in an SMB1 Negotiate Request It indicates that the server implements SMB 2.1 or future dialect revisions Note that this must be used for SMB3
'SMB 2.???'.freeze
- SMB2_DIALECT_0202 =
'0x0202'.freeze
- SMB2_DIALECT_0210 =
'0x0210'.freeze
- SMB2_DIALECT_0300 =
'0x0300'.freeze
- SMB2_DIALECT_0302 =
'0x0302'.freeze
- SMB2_DIALECT_0311 =
'0x0311'.freeze
- SMB2_DIALECT_DEFAULT =
Dialect values for SMB2
[ SMB2_DIALECT_0202, SMB2_DIALECT_0210, ].freeze
- SMB3_DIALECT_DEFAULT =
Dialect values for SMB3
[ SMB2_DIALECT_0300, SMB2_DIALECT_0302, SMB2_DIALECT_0311 ].freeze
- MAX_BUFFER_SIZE =
The default maximum size of a SMB message that the Client accepts (in bytes)
64512
- SERVER_MAX_BUFFER_SIZE =
The default maximum size of a SMB message that the Server accepts (in bytes)
4356
Constants included from NTLM
NTLM::DEFAULT_CLIENT_FLAGS, NTLM::NEGOTIATE_FLAGS
Instance Attribute Summary collapse
- #application_key ⇒ String
- #client_encryption_key ⇒ String
- #default_domain ⇒ String
- #default_name ⇒ String
- #dialect ⇒ Integer
- #dispatcher ⇒ RubySMB::Dispatcher::Socket
- #dns_domain_name ⇒ String
- #dns_host_name ⇒ String
- #dns_tree_name ⇒ String
- #domain ⇒ String
- #encryption_algorithm ⇒ String
- #local_workstation ⇒ String
- #max_buffer_size ⇒ Integer
-
#negotiated_smb_version ⇒ Integer
The negotiated SMB version.
-
#negotiation_security_buffer ⇒ String
The raw security buffer bytes.
- #ntlm_client ⇒ String
- #os_version ⇒ String
- #password ⇒ String
- #peer_native_lm ⇒ String
- #peer_native_os ⇒ String
- #pid ⇒ Integer
- #preauth_integrity_hash_algorithm ⇒ String
- #preauth_integrity_hash_value ⇒ String
- #primary_domain ⇒ String
- #sequence_counter ⇒ Integer
-
#server_compression_algorithms ⇒ Array<Integer>
List of supported compression algorithms (constants defined in RubySMB::SMB2::CompressionCapabilities).
-
#server_encryption_algorithms ⇒ Array<Integer>
List of supported encryption algorithms (constants defined in RubySMB::SMB2::EncryptionCapabilities).
- #server_encryption_key ⇒ String
- #server_guid ⇒ String
-
#server_max_buffer_size ⇒ Object
The maximum size SMB message that the Server accepts (in bytes) The default value is small by default.
- #server_max_read_size ⇒ Integer
- #server_max_transact_size ⇒ Integer
- #server_max_write_size ⇒ Integer
-
#server_start_time ⇒ Time
The time that the server reports that it was started at.
-
#server_supports_multi_credit ⇒ Boolean
false otherwise.
-
#server_system_time ⇒ Time
The time that the server reports as current.
- #session_encrypt_data ⇒ Boolean
- #session_id ⇒ Integer
- #session_is_guest ⇒ Boolean
- #signing_enabled ⇒ Boolean
-
#signing_required ⇒ Object
Whether or not the Server requires signing.
- #smb1 ⇒ Boolean
- #smb2 ⇒ Boolean
- #smb2_message_id ⇒ Integer
- #smb3 ⇒ Boolean
- #user_id ⇒ Integer
- #username ⇒ String
Attributes included from Utils
#auth_user, #evasion_opts, #last_file_id, #native_lm, #native_os, #open_files, #send_lm, #send_ntlm, #spnopt, #tree_connects, #use_lanman_key, #use_ntlmv2, #usentlm2_session, #verify_signature
Attributes included from Signing
Instance Method Summary collapse
-
#can_be_encrypted?(packet) ⇒ Boolean
Check if the request packet can be encrypted.
-
#disconnect! ⇒ void
Logs off any currently open session on the server and closes the TCP socket connection.
-
#echo(count: 1, data: '') ⇒ WindowsError::ErrorCode
Sends an Echo request to the server and returns the NTStatus of the last response packet received.
-
#encryption_supported? ⇒ Boolean
Check if the current dialect supports encryption.
-
#increment_smb_message_id(packet) ⇒ RubySMB::GenericPacket
Sets the message id field in an SMB2 packet's header to the one tracked by the client.
-
#initialize(dispatcher, smb1: true, smb2: true, smb3: true, username:, password:, domain: '.', local_workstation: 'WORKSTATION', always_encrypt: true, ntlm_flags: NTLM::DEFAULT_CLIENT_FLAGS) ⇒ Client
constructor
A new instance of Client.
-
#is_status_pending?(smb2_header) ⇒ Boolean
Check if the response is an asynchronous operation with STATUS_PENDING status code.
-
#login(username: self.username, password: self.password, domain: self.domain, local_workstation: self.local_workstation, ntlm_flags: NTLM::DEFAULT_CLIENT_FLAGS) ⇒ Object
Performs protocol negotiation and session setup.
-
#logoff! ⇒ WindowsError::ErrorCode
Sends a LOGOFF command to the remote server to terminate the session.
-
#net_share_enum_all(host) ⇒ Array
Returns array of shares.
-
#recv_packet(encrypt: false) ⇒ String
Receives the raw response through the Dispatcher and decrypt the packet (if required).
-
#send_packet(packet, encrypt: false) ⇒ Object
Encrypt (if required) and send a packet.
-
#send_recv(packet, encrypt: false) ⇒ String
Sends a packet and receives the raw response through the Dispatcher.
-
#session_request(name = '*SMBSERVER') ⇒ TrueClass
Requests a NetBIOS Session Service using the provided name.
-
#session_request_packet(name = '*SMBSERVER') ⇒ RubySMB::Nbss::SessionRequest
Crafts the NetBIOS SessionRequest packet to be sent for session request operations.
- #session_setup(user, pass, domain, do_recv = true, local_workstation: self.local_workstation, ntlm_flags: NTLM::DEFAULT_CLIENT_FLAGS) ⇒ Object
-
#tree_connect(share) ⇒ RubySMB::SMB1::Tree, RubySMB::SMB2::Tree
Connects to the supplied share.
- #update_preauth_hash(data) ⇒ Object
-
#wipe_state! ⇒ void
Resets all of the session state on the client, setting it back to scratch.
Methods included from Encryption
Methods included from Winreg
#connect_to_winreg, #enum_registry_key, #enum_registry_values, #get_key_security_descriptor, #has_registry_key?, #read_registry_key_value, #set_key_security_descriptor
Methods included from Utils
#close, #create_pipe, #delete, #last_file, #last_tree, #last_tree_id, #open, #read, #tree_disconnect, #write
Methods included from Echo
Methods included from TreeConnect
#smb1_tree_connect, #smb1_tree_from_response, #smb2_tree_connect, #smb2_tree_from_response
Methods included from Authentication
#authenticate, #smb1_anonymous_auth, #smb1_anonymous_auth_request, #smb1_anonymous_auth_response, #smb1_authenticate, #smb1_ntlmssp_auth_packet, #smb1_ntlmssp_authenticate, #smb1_ntlmssp_challenge_packet, #smb1_ntlmssp_final_packet, #smb1_ntlmssp_negotiate, #smb1_ntlmssp_negotiate_packet, #smb1_session_setup_response, #smb1_type2_message, #smb2_authenticate, #smb2_ntlmssp_auth_packet, #smb2_ntlmssp_authenticate, #smb2_ntlmssp_challenge_packet, #smb2_ntlmssp_final_packet, #smb2_ntlmssp_negotiate, #smb2_ntlmssp_negotiate_packet, #smb2_session_setup_response, #smb2_type2_message
Methods included from PeerInfo
#extract_os_version, #store_target_info
Methods included from Negotiation
#add_smb3_to_negotiate_request, #negotiate, #negotiate_request, #negotiate_response, #parse_negotiate_response, #parse_smb3_capabilities, #smb1_negotiate_request, #smb2_3_negotiate_request
Methods included from NTLM
Methods included from Signing
#smb1_sign, smb1_sign, #smb2_sign, smb2_sign, #smb3_sign, smb3_sign
Constructor Details
#initialize(dispatcher, smb1: true, smb2: true, smb3: true, username:, password:, domain: '.', local_workstation: 'WORKSTATION', always_encrypt: true, ntlm_flags: NTLM::DEFAULT_CLIENT_FLAGS) ⇒ Client
Returns a new instance of Client.
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 |
# File 'lib/ruby_smb/client.rb', line 317 def initialize(dispatcher, smb1: true, smb2: true, smb3: true, username:, password:, domain: '.', local_workstation: 'WORKSTATION', always_encrypt: true, ntlm_flags: NTLM::DEFAULT_CLIENT_FLAGS) raise ArgumentError, 'No Dispatcher provided' unless dispatcher.is_a? RubySMB::Dispatcher::Base if smb1 == false && smb2 == false && smb3 == false raise ArgumentError, 'You must enable at least one Protocol' end @dispatcher = dispatcher @pid = rand(0xFFFF) @domain = domain @local_workstation = local_workstation @password = RubySMB::Utils.safe_encode((password||''), 'utf-8') @sequence_counter = 0 @session_id = 0x00 @session_key = '' @application_key = '' @session_is_guest = false @signing_required = false @smb1 = smb1 @smb2 = smb2 @smb3 = smb3 @username = RubySMB::Utils.safe_encode((username||''), 'utf-8') @max_buffer_size = MAX_BUFFER_SIZE # These sizes will be modified during negotiation @server_max_buffer_size = SERVER_MAX_BUFFER_SIZE @server_max_read_size = RubySMB::SMB2::File::MAX_PACKET_SIZE @server_max_write_size = RubySMB::SMB2::File::MAX_PACKET_SIZE @server_max_transact_size = RubySMB::SMB2::File::MAX_PACKET_SIZE @server_supports_multi_credit = false # SMB 3.x options # this merely initializes the default value for session encryption, it may be changed as necessary when a # session setup response is received @session_encrypt_data = always_encrypt @ntlm_client = RubySMB::NTLM::Client.new( @username, @password, workstation: @local_workstation, domain: @domain, flags: ntlm_flags ) @tree_connects = [] @open_files = {} @smb2_message_id = 0 end |
Instance Attribute Details
#application_key ⇒ String
64 65 66 |
# File 'lib/ruby_smb/client.rb', line 64 def application_key @application_key end |
#client_encryption_key ⇒ String
250 251 252 |
# File 'lib/ruby_smb/client.rb', line 250 def client_encryption_key @client_encryption_key end |
#default_domain ⇒ String
118 119 120 |
# File 'lib/ruby_smb/client.rb', line 118 def default_domain @default_domain end |
#default_name ⇒ String
113 114 115 |
# File 'lib/ruby_smb/client.rb', line 113 def default_name @default_name end |
#dialect ⇒ Integer
143 144 145 |
# File 'lib/ruby_smb/client.rb', line 143 def dialect @dialect end |
#dispatcher ⇒ RubySMB::Dispatcher::Socket
69 70 71 |
# File 'lib/ruby_smb/client.rb', line 69 def dispatcher @dispatcher end |
#dns_domain_name ⇒ String
128 129 130 |
# File 'lib/ruby_smb/client.rb', line 128 def dns_domain_name @dns_domain_name end |
#dns_host_name ⇒ String
123 124 125 |
# File 'lib/ruby_smb/client.rb', line 123 def dns_host_name @dns_host_name end |
#dns_tree_name ⇒ String
133 134 135 |
# File 'lib/ruby_smb/client.rb', line 133 def dns_tree_name @dns_tree_name end |
#domain ⇒ String
74 75 76 |
# File 'lib/ruby_smb/client.rb', line 74 def domain @domain end |
#encryption_algorithm ⇒ String
245 246 247 |
# File 'lib/ruby_smb/client.rb', line 245 def encryption_algorithm @encryption_algorithm end |
#local_workstation ⇒ String
79 80 81 |
# File 'lib/ruby_smb/client.rb', line 79 def local_workstation @local_workstation end |
#max_buffer_size ⇒ Integer
208 209 210 |
# File 'lib/ruby_smb/client.rb', line 208 def max_buffer_size @max_buffer_size end |
#negotiated_smb_version ⇒ Integer
Returns the negotiated SMB version.
297 298 299 |
# File 'lib/ruby_smb/client.rb', line 297 def negotiated_smb_version @negotiated_smb_version end |
#negotiation_security_buffer ⇒ String
Returns The raw security buffer bytes.
311 312 313 |
# File 'lib/ruby_smb/client.rb', line 311 def negotiation_security_buffer @negotiation_security_buffer end |
#ntlm_client ⇒ String
84 85 86 |
# File 'lib/ruby_smb/client.rb', line 84 def ntlm_client @ntlm_client end |
#os_version ⇒ String
138 139 140 |
# File 'lib/ruby_smb/client.rb', line 138 def os_version @os_version end |
#password ⇒ String
89 90 91 |
# File 'lib/ruby_smb/client.rb', line 89 def password @password end |
#peer_native_lm ⇒ String
101 102 103 |
# File 'lib/ruby_smb/client.rb', line 101 def peer_native_lm @peer_native_lm end |
#peer_native_os ⇒ String
95 96 97 |
# File 'lib/ruby_smb/client.rb', line 95 def peer_native_os @peer_native_os end |
#pid ⇒ Integer
202 203 204 |
# File 'lib/ruby_smb/client.rb', line 202 def pid @pid end |
#preauth_integrity_hash_algorithm ⇒ String
235 236 237 |
# File 'lib/ruby_smb/client.rb', line 235 def preauth_integrity_hash_algorithm @preauth_integrity_hash_algorithm end |
#preauth_integrity_hash_value ⇒ String
240 241 242 |
# File 'lib/ruby_smb/client.rb', line 240 def preauth_integrity_hash_value @preauth_integrity_hash_value end |
#primary_domain ⇒ String
108 109 110 |
# File 'lib/ruby_smb/client.rb', line 108 def primary_domain @primary_domain end |
#sequence_counter ⇒ Integer
150 151 152 |
# File 'lib/ruby_smb/client.rb', line 150 def sequence_counter @sequence_counter end |
#server_compression_algorithms ⇒ Array<Integer>
Returns list of supported compression algorithms (constants defined in RubySMB::SMB2::CompressionCapabilities).
272 273 274 |
# File 'lib/ruby_smb/client.rb', line 272 def server_compression_algorithms @server_compression_algorithms end |
#server_encryption_algorithms ⇒ Array<Integer>
Returns list of supported encryption algorithms (constants defined in RubySMB::SMB2::EncryptionCapabilities).
266 267 268 |
# File 'lib/ruby_smb/client.rb', line 266 def server_encryption_algorithms @server_encryption_algorithms end |
#server_encryption_key ⇒ String
255 256 257 |
# File 'lib/ruby_smb/client.rb', line 255 def server_encryption_key @server_encryption_key end |
#server_guid ⇒ String
277 278 279 |
# File 'lib/ruby_smb/client.rb', line 277 def server_guid @server_guid end |
#server_max_buffer_size ⇒ Object
The maximum size SMB message that the Server accepts (in bytes) The default value is small by default
214 215 216 |
# File 'lib/ruby_smb/client.rb', line 214 def server_max_buffer_size @server_max_buffer_size end |
#server_max_read_size ⇒ Integer
224 225 226 |
# File 'lib/ruby_smb/client.rb', line 224 def server_max_read_size @server_max_read_size end |
#server_max_transact_size ⇒ Integer
230 231 232 |
# File 'lib/ruby_smb/client.rb', line 230 def server_max_transact_size @server_max_transact_size end |
#server_max_write_size ⇒ Integer
219 220 221 |
# File 'lib/ruby_smb/client.rb', line 219 def server_max_write_size @server_max_write_size end |
#server_start_time ⇒ Time
Returns the time that the server reports that it was started at.
284 285 286 |
# File 'lib/ruby_smb/client.rb', line 284 def server_start_time @server_start_time end |
#server_supports_multi_credit ⇒ Boolean
false otherwise
305 306 307 |
# File 'lib/ruby_smb/client.rb', line 305 def server_supports_multi_credit @server_supports_multi_credit end |
#server_system_time ⇒ Time
Returns the time that the server reports as current.
291 292 293 |
# File 'lib/ruby_smb/client.rb', line 291 def server_system_time @server_system_time end |
#session_encrypt_data ⇒ Boolean
260 261 262 |
# File 'lib/ruby_smb/client.rb', line 260 def session_encrypt_data @session_encrypt_data end |
#session_id ⇒ Integer
155 156 157 |
# File 'lib/ruby_smb/client.rb', line 155 def session_id @session_id end |
#session_is_guest ⇒ Boolean
160 161 162 |
# File 'lib/ruby_smb/client.rb', line 160 def session_is_guest @session_is_guest end |
#signing_enabled ⇒ Boolean
165 |
# File 'lib/ruby_smb/client.rb', line 165 attr_accessor :signing_required |
#signing_required ⇒ Object
Whether or not the Server requires signing
165 166 167 |
# File 'lib/ruby_smb/client.rb', line 165 def signing_required @signing_required end |
#smb1 ⇒ Boolean
170 171 172 |
# File 'lib/ruby_smb/client.rb', line 170 def smb1 @smb1 end |
#smb2 ⇒ Boolean
175 176 177 |
# File 'lib/ruby_smb/client.rb', line 175 def smb2 @smb2 end |
#smb2_message_id ⇒ Integer
185 186 187 |
# File 'lib/ruby_smb/client.rb', line 185 def @smb2_message_id end |
#smb3 ⇒ Boolean
180 181 182 |
# File 'lib/ruby_smb/client.rb', line 180 def smb3 @smb3 end |
#user_id ⇒ Integer
195 196 197 |
# File 'lib/ruby_smb/client.rb', line 195 def user_id @user_id end |
#username ⇒ String
190 191 192 |
# File 'lib/ruby_smb/client.rb', line 190 def username @username end |
Instance Method Details
#can_be_encrypted?(packet) ⇒ Boolean
Check if the request packet can be encrypted. Per the SMB2 spec, SessionSetupRequest and NegotiateRequest must not be encrypted.
543 544 545 546 547 548 |
# File 'lib/ruby_smb/client.rb', line 543 def can_be_encrypted?(packet) return false if packet.packet_smb_version == 'SMB1' [RubySMB::SMB2::Packet::SessionSetupRequest, RubySMB::SMB2::Packet::NegotiateRequest].none? do |klass| packet.is_a?(klass) end end |
#disconnect! ⇒ void
This method returns an undefined value.
Logs off any currently open session on the server and closes the TCP socket connection.
369 370 371 372 373 374 375 376 |
# File 'lib/ruby_smb/client.rb', line 369 def disconnect! begin logoff! rescue wipe_state! end dispatcher.tcp_socket.close end |
#echo(count: 1, data: '') ⇒ WindowsError::ErrorCode
Sends an Echo request to the server and returns the NTStatus of the last response packet received.
384 385 386 387 388 389 390 391 |
# File 'lib/ruby_smb/client.rb', line 384 def echo(count: 1, data: '') response = if smb2 || smb3 smb2_echo else smb1_echo(count: count, data: data) end response.status_code end |
#encryption_supported? ⇒ Boolean
Check if the current dialect supports encryption.
553 554 555 |
# File 'lib/ruby_smb/client.rb', line 553 def encryption_supported? ['0x0300', '0x0302', '0x0311'].include?(@dialect) end |
#increment_smb_message_id(packet) ⇒ RubySMB::GenericPacket
Sets the message id field in an SMB2 packet's header to the one tracked by the client. It then increments the counter on the client.
399 400 401 402 403 |
# File 'lib/ruby_smb/client.rb', line 399 def (packet) packet.smb2_header. = self. self. += 1 packet end |
#is_status_pending?(smb2_header) ⇒ Boolean
Check if the response is an asynchronous operation with STATUS_PENDING status code.
531 532 533 534 535 536 |
# File 'lib/ruby_smb/client.rb', line 531 def is_status_pending?(smb2_header) value = smb2_header.nt_status.value status_code = WindowsError::NTStatus.find_by_retval(value).first status_code == WindowsError::NTStatus::STATUS_PENDING && smb2_header.flags.async_command == 1 end |
#login(username: self.username, password: self.password, domain: self.domain, local_workstation: self.local_workstation, ntlm_flags: NTLM::DEFAULT_CLIENT_FLAGS) ⇒ Object
Performs protocol negotiation and session setup. It defaults to using the credentials supplied during initialization, but can take a new set of credentials if needed.
407 408 409 410 411 412 413 414 |
# File 'lib/ruby_smb/client.rb', line 407 def login(username: self.username, password: self.password, domain: self.domain, local_workstation: self.local_workstation, ntlm_flags: NTLM::DEFAULT_CLIENT_FLAGS) negotiate session_setup(username, password, domain, local_workstation: local_workstation, ntlm_flags: ntlm_flags) end |
#logoff! ⇒ WindowsError::ErrorCode
Sends a LOGOFF command to the remote server to terminate the session
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 |
# File 'lib/ruby_smb/client.rb', line 438 def logoff! if smb2 || smb3 request = RubySMB::SMB2::Packet::LogoffRequest.new raw_response = send_recv(request) response = RubySMB::SMB2::Packet::LogoffResponse.read(raw_response) unless response.valid? raise RubySMB::Error::InvalidPacket.new( expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID, expected_cmd: RubySMB::SMB2::Packet::LogoffResponse::COMMAND, packet: response ) end else request = RubySMB::SMB1::Packet::LogoffRequest.new raw_response = send_recv(request) response = RubySMB::SMB1::Packet::LogoffResponse.read(raw_response) unless response.valid? raise RubySMB::Error::InvalidPacket.new( expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID, expected_cmd: RubySMB::SMB1::Packet::LogoffResponse::COMMAND, packet: response ) end end wipe_state! response.status_code end |
#net_share_enum_all(host) ⇒ Array
Returns array of shares
622 623 624 625 626 |
# File 'lib/ruby_smb/client.rb', line 622 def net_share_enum_all(host) tree = tree_connect("\\\\#{host}\\IPC$") named_pipe = tree.open_pipe(filename: "srvsvc", write: true, read: true) named_pipe.net_share_enum_all(host) end |
#recv_packet(encrypt: false) ⇒ String
Receives the raw response through the Dispatcher and decrypt the packet (if required).
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 |
# File 'lib/ruby_smb/client.rb', line 576 def recv_packet(encrypt: false) begin raw_response = dispatcher.recv_packet rescue RubySMB::Error::CommunicationError => e if encrypt raise e, "Communication error with the "\ "remote host: #{e.}. The server supports encryption and this error "\ "may have been caused by encryption issues, but not always." else raise e end end if encrypt begin transform_response = RubySMB::SMB2::Packet::TransformHeader.read(raw_response) rescue IOError raise RubySMB::Error::InvalidPacket, 'Not a SMB2 TransformHeader packet' end begin raw_response = smb3_decrypt(transform_response) rescue RubySMB::Error::RubySMBError => e raise RubySMB::Error::EncryptionError, "Error while decrypting #{transform_response.class.name} packet (SMB #@dialect}): #{e}" end end raw_response end |
#send_packet(packet, encrypt: false) ⇒ Object
Encrypt (if required) and send a packet.
561 562 563 564 565 566 567 568 569 570 |
# File 'lib/ruby_smb/client.rb', line 561 def send_packet(packet, encrypt: false) if encrypt begin packet = smb3_encrypt(packet.to_binary_s) rescue RubySMB::Error::RubySMBError => e raise RubySMB::Error::EncryptionError, "Error while encrypting #{packet.class.name} packet (SMB #{@dialect}): #{e}" end end dispatcher.send_packet(packet) end |
#send_recv(packet, encrypt: false) ⇒ String
Sends a packet and receives the raw response through the Dispatcher. It will also sign the packet if necessary.
474 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 |
# File 'lib/ruby_smb/client.rb', line 474 def send_recv(packet, encrypt: false) version = packet.packet_smb_version case version when 'SMB1' packet.smb_header.uid = self.user_id if self.user_id packet.smb_header.pid_low = self.pid if self.pid packet = smb1_sign(packet) if signing_required && !session_key.empty? when 'SMB2' packet = (packet) packet.smb2_header.session_id = session_id unless packet.is_a?(RubySMB::SMB2::Packet::SessionSetupRequest) || session_key.empty? if self.smb2 && signing_required packet = smb2_sign(packet) elsif self.smb3 # see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/652e0c14-5014-4470-999d-b174d7b2da87 if @dialect == '0x0311' && (signing_required || (!@session_is_guest && packet.is_a?(RubySMB::SMB2::Packet::TreeConnectRequest))) packet = smb3_sign(packet) elsif signing_required packet = smb3_sign(packet) end end end else packet = packet end encrypt_data = false if can_be_encrypted?(packet) && encryption_supported? && (@session_encrypt_data || encrypt) encrypt_data = true end send_packet(packet, encrypt: encrypt_data) raw_response = recv_packet(encrypt: encrypt_data) smb2_header = nil loop do smb2_header = RubySMB::SMB2::SMB2Header.read(raw_response) break unless is_status_pending?(smb2_header) sleep 1 raw_response = recv_packet(encrypt: encrypt_data) rescue IOError # We're expecting an SMB2 packet, but the server sent an SMB1 packet # instead. This behavior has been observed with older versions of Samba # when something goes wrong on the server side. So, we just ignore it # and expect the caller to handle this wrong response packet. break end unless version == 'SMB1' self.sequence_counter += 1 if signing_required && !session_key.empty? # update the SMB2 message ID according to the received Credit Charged self. += smb2_header.credit_charge - 1 if smb2_header && self.server_supports_multi_credit raw_response end |
#session_request(name = '*SMBSERVER') ⇒ TrueClass
Requests a NetBIOS Session Service using the provided name.
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 |
# File 'lib/ruby_smb/client.rb', line 652 def session_request(name = '*SMBSERVER') session_request = session_request_packet(name) dispatcher.send_packet(session_request, nbss_header: false) raw_response = dispatcher.recv_packet(full_response: true) begin session_header = RubySMB::Nbss::SessionHeader.read(raw_response) if session_header.session_packet_type == RubySMB::Nbss::NEGATIVE_SESSION_RESPONSE negative_session_response = RubySMB::Nbss::NegativeSessionResponse.read(raw_response) raise RubySMB::Error::NetBiosSessionService, "Session Request failed: #{negative_session_response.error_msg}" end rescue IOError raise RubySMB::Error::InvalidPacket, 'Not a NBSS packet' end return true end |
#session_request_packet(name = '*SMBSERVER') ⇒ RubySMB::Nbss::SessionRequest
Crafts the NetBIOS SessionRequest packet to be sent for session request operations.
673 674 675 676 677 678 679 680 681 682 683 684 |
# File 'lib/ruby_smb/client.rb', line 673 def session_request_packet(name = '*SMBSERVER') called_name = "#{name.upcase.ljust(15)}\x20" calling_name = "#{''.ljust(15)}\x00" session_request = RubySMB::Nbss::SessionRequest.new session_request.session_header.session_packet_type = RubySMB::Nbss::SESSION_REQUEST session_request.called_name = called_name session_request.calling_name = calling_name session_request.session_header.stream_protocol_length = session_request.num_bytes - session_request.session_header.num_bytes session_request end |
#session_setup(user, pass, domain, do_recv = true, local_workstation: self.local_workstation, ntlm_flags: NTLM::DEFAULT_CLIENT_FLAGS) ⇒ Object
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 |
# File 'lib/ruby_smb/client.rb', line 416 def session_setup(user, pass, domain, do_recv=true, local_workstation: self.local_workstation, ntlm_flags: NTLM::DEFAULT_CLIENT_FLAGS) @domain = domain @local_workstation = local_workstation @password = RubySMB::Utils.safe_encode((pass||''), 'utf-8') @username = RubySMB::Utils.safe_encode((user||''), 'utf-8') @ntlm_client = RubySMB::NTLM::Client.new( @username, @password, workstation: @local_workstation, domain: @domain, flags: ntlm_flags ) authenticate end |
#tree_connect(share) ⇒ RubySMB::SMB1::Tree, RubySMB::SMB2::Tree
Connects to the supplied share
608 609 610 611 612 613 614 615 616 |
# File 'lib/ruby_smb/client.rb', line 608 def tree_connect(share) connected_tree = if smb2 || smb3 smb2_tree_connect(share) else smb1_tree_connect(share) end @tree_connects << connected_tree connected_tree end |
#update_preauth_hash(data) ⇒ Object
686 687 688 689 690 691 692 693 694 695 696 |
# File 'lib/ruby_smb/client.rb', line 686 def update_preauth_hash(data) unless @preauth_integrity_hash_algorithm raise RubySMB::Error::EncryptionError.new( 'Cannot compute the Preauth Integrity Hash value: Preauth Integrity Hash Algorithm is nil' ) end @preauth_integrity_hash_value = OpenSSL::Digest.digest( @preauth_integrity_hash_algorithm, @preauth_integrity_hash_value + data.to_binary_s ) end |
#wipe_state! ⇒ void
This method returns an undefined value.
Resets all of the session state on the client, setting it back to scratch. Should only be called when a session is no longer valid.
633 634 635 636 637 638 639 640 641 642 643 644 |
# File 'lib/ruby_smb/client.rb', line 633 def wipe_state! self.session_id = 0x00 self.user_id = 0x00 self.application_key = '' self.session_key = '' self.session_is_guest = false self.sequence_counter = 0 self. = 0 self.client_encryption_key = nil self.server_encryption_key = nil self.server_supports_multi_credit = false end |