Module: RubySMB::Client::Authentication
Overview
This module holds all the backend client methods for authentication.
Instance Method Summary collapse
-
#authenticate ⇒ WindowsError::NTStatus
Responsible for handling Authentication and Session Setup for the SMB Client.
-
#smb1_anonymous_auth ⇒ WindowsError::ErrorCode
Attempts an Anonymous logon to the remote server.
-
#smb1_anonymous_auth_request ⇒ Object
Creates a SessionSetupRequest for an anonymous access session.
- #smb1_anonymous_auth_response(raw_response) ⇒ Object
-
#smb1_authenticate ⇒ Object
Handles the SMB1 NTLMSSP 4-way handshake for Authentication and store information about the peer/server.
- #smb1_legacy_auth_request(lm_response, ntlm_response) ⇒ Object
- #smb1_legacy_auth_response(raw_response) ⇒ Object
-
#smb1_legacy_authenticate ⇒ Object
Handles SMB1 authentication against servers that negotiated non-extended (legacy) security — Windows 95/98/ME and old Samba builds.
-
#smb1_ntlmssp_auth_packet(type3_message, user_id) ⇒ RubySMB::SMB1::Packet::SessionSetupRequest
Generates the SMB1::Packet::SessionSetupRequest packet with the NTLM Type 3 (Auth) message in the security_blob field.
-
#smb1_ntlmssp_authenticate(type3_message, user_id) ⇒ String
Takes the NTLM Type 3 (authenticate) message and calls the routines to build the Auth packet, sends the packet and receives the raw response.
-
#smb1_ntlmssp_challenge_packet(raw_response) ⇒ Object
Takes the raw binary string and returns a SMB1::Packet::SessionSetupResponse.
-
#smb1_ntlmssp_final_packet(raw_response) ⇒ Object
Takes the raw binary string and returns a SMB1::Packet::SessionSetupResponse.
-
#smb1_ntlmssp_negotiate ⇒ String
Sends the SMB1::Packet::SessionSetupRequest packet and receives the response.
-
#smb1_ntlmssp_negotiate_packet ⇒ RubySMB::SMB1::Packet::SessionSetupRequest
Creates the SMB1::Packet::SessionSetupRequest packet for the first part of the NTLMSSP 4-way hnadshake.
-
#smb1_session_setup_response(raw_response) ⇒ Object
Takes the raw binary string and returns a SMB1::Packet::SessionSetupResponse.
-
#smb1_type2_message(response_packet) ⇒ String
Parses out the NTLM Type 2 Message from a SMB1::Packet::SessionSetupResponse.
-
#smb2_authenticate ⇒ Object
Handles the SMB2 NTLMSSP 4-way handshake for Authentication and store information about the peer/server.
-
#smb2_ntlmssp_auth_packet(type3_message, session_id) ⇒ RubySMB::SMB2::Packet::SessionSetupRequest
Generates the SMB2::Packet::SessionSetupRequest packet with the NTLM Type 3 (Auth) message in the security_blob field.
-
#smb2_ntlmssp_authenticate(type3_message, user_id) ⇒ String
Takes the NTLM Type 3 (authenticate) message and calls the routines to build the Auth packet, sends the packet and receives the raw response.
-
#smb2_ntlmssp_challenge_packet(raw_response) ⇒ Object
Takes the raw binary string and returns a SMB2::Packet::SessionSetupResponse.
-
#smb2_ntlmssp_final_packet(raw_response) ⇒ Object
Takes the raw binary string and returns a SMB2::Packet::SessionSetupResponse.
-
#smb2_ntlmssp_negotiate ⇒ String
Sends the SMB2::Packet::SessionSetupRequest packet and receives the response.
-
#smb2_ntlmssp_negotiate_packet ⇒ RubySMB::SMB2::Packet::SessionSetupRequest
Creates the SMB2::Packet::SessionSetupRequest packet for the first part of the NTLMSSP 4-way handshake.
-
#smb2_session_setup_response(raw_response) ⇒ Object
Takes the raw binary string and returns a SMB2::Packet::SessionSetupResponse.
-
#smb2_type2_message(response_packet) ⇒ String
Parses out the NTLM Type 2 Message from a SMB2::Packet::SessionSetupResponse.
Methods included from PeerInfo
#extract_os_version, #store_target_info
Instance Method Details
#authenticate ⇒ WindowsError::NTStatus
Responsible for handling Authentication and Session Setup for the SMB Client. It returns the final Status code from the authentication exchange.
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/ruby_smb/client/authentication.rb', line 14 def authenticate if smb1 if username.empty? && password.empty? smb1_anonymous_auth elsif @smb1_negotiate_challenge # Non-extended security negotiated (e.g. Windows 95/98). Use legacy # LM/NTLM challenge-response rather than NTLMSSP. smb1_legacy_authenticate else smb1_authenticate end else smb2_authenticate end end |
#smb1_anonymous_auth ⇒ WindowsError::ErrorCode
Attempts an Anonymous logon to the remote server.
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/ruby_smb/client/authentication.rb', line 37 def smb1_anonymous_auth @mech_type = :anonymous request = smb1_anonymous_auth_request raw_response = send_recv(request) response = smb1_anonymous_auth_response(raw_response) response_code = response.status_code if response_code == WindowsError::NTStatus::STATUS_SUCCESS self.user_id = response.smb_header.uid self.peer_native_os = response.data_block.native_os.to_s self.peer_native_lm = response.data_block.native_lan_man.to_s self.primary_domain = response.data_block.primary_domain.to_s end response_code end |
#smb1_anonymous_auth_request ⇒ Object
Creates a SessionSetupRequest for an anonymous access session.
56 57 58 59 60 61 62 63 |
# File 'lib/ruby_smb/client/authentication.rb', line 56 def smb1_anonymous_auth_request packet = RubySMB::SMB1::Packet::SessionSetupLegacyRequest.new packet.data_block.oem_password = "\x00" packet.parameter_block.max_buffer_size = self.max_buffer_size packet.parameter_block.max_mpx_count = 50 packet.parameter_block.capabilities.extended_security = 0 packet end |
#smb1_anonymous_auth_response(raw_response) ⇒ Object
65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/ruby_smb/client/authentication.rb', line 65 def smb1_anonymous_auth_response(raw_response) packet = RubySMB::SMB1::Packet::SessionSetupLegacyResponse.read(raw_response) unless packet.valid? raise RubySMB::Error::InvalidPacket.new( expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID, expected_cmd: RubySMB::SMB1::Packet::SessionSetupLegacyResponse::COMMAND, packet: packet ) end packet end |
#smb1_authenticate ⇒ Object
Handles the SMB1 NTLMSSP 4-way handshake for Authentication and store information about the peer/server.
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 |
# File 'lib/ruby_smb/client/authentication.rb', line 80 def smb1_authenticate @mech_type = :ntlm response = smb1_ntlmssp_negotiate challenge_packet = smb1_ntlmssp_challenge_packet(response) # Store the available OS information before going forward. @peer_native_os = challenge_packet.data_block.native_os.to_s @peer_native_lm = challenge_packet.data_block.native_lan_man.to_s user_id = challenge_packet.smb_header.uid = (challenge_packet) = @ntlm_client.init_context() @application_key = @session_key = @ntlm_client.session_key = @ntlm_client.session. store_target_info(.target_info) if .has_flag?(:TARGET_INFO) @os_version = extract_os_version(.os_version.to_s) unless .os_version.empty? raw = smb1_ntlmssp_authenticate(, user_id) response = smb1_ntlmssp_final_packet(raw) response_code = response.status_code # Use the UID from the final response (some servers, e.g. Samba, reassign it on success). @user_id = response.smb_header.uid if response_code == WindowsError::NTStatus::STATUS_SUCCESS response_code end |
#smb1_legacy_auth_request(lm_response, ntlm_response) ⇒ Object
234 235 236 237 238 239 240 241 242 243 |
# File 'lib/ruby_smb/client/authentication.rb', line 234 def smb1_legacy_auth_request(lm_response, ntlm_response) packet = RubySMB::SMB1::Packet::SessionSetupLegacyRequest.new packet.parameter_block.max_buffer_size = self.max_buffer_size packet.parameter_block.max_mpx_count = 50 packet.data_block.oem_password = lm_response packet.data_block.unicode_password = ntlm_response packet.data_block.account_name = @username.encode('ASCII', invalid: :replace, undef: :replace) packet.data_block.primary_domain = @domain.encode('ASCII', invalid: :replace, undef: :replace) packet end |
#smb1_legacy_auth_response(raw_response) ⇒ Object
245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/ruby_smb/client/authentication.rb', line 245 def smb1_legacy_auth_response(raw_response) packet = RubySMB::SMB1::Packet::SessionSetupLegacyResponse.read(raw_response) unless packet.valid? raise RubySMB::Error::InvalidPacket.new( expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID, expected_cmd: RubySMB::SMB1::Packet::SessionSetupLegacyResponse::COMMAND, packet: packet ) end packet end |
#smb1_legacy_authenticate ⇒ Object
Handles SMB1 authentication against servers that negotiated non-extended (legacy) security — Windows 95/98/ME and old Samba builds. These hosts provide a raw 8-byte challenge in the Negotiate response and expect LM + NTLM hash responses in SessionSetupLegacyRequest.
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/client/authentication.rb', line 212 def smb1_legacy_authenticate challenge = @smb1_negotiate_challenge lm_hash = Net::NTLM.lm_hash(@password) ntlm_hash = Net::NTLM.ntlm_hash(@password) lm_resp = Net::NTLM.lm_response(lm_hash: lm_hash, challenge: challenge) ntlm_resp = Net::NTLM.ntlm_response(ntlm_hash: ntlm_hash, challenge: challenge) packet = smb1_legacy_auth_request(lm_resp, ntlm_resp) raw_response = send_recv(packet) response = smb1_legacy_auth_response(raw_response) response_code = response.status_code if response_code == WindowsError::NTStatus::STATUS_SUCCESS self.user_id = response.smb_header.uid self.peer_native_os = response.data_block.native_os.to_s self.peer_native_lm = response.data_block.native_lan_man.to_s self.primary_domain = response.data_block.primary_domain.to_s end response_code end |
#smb1_ntlmssp_auth_packet(type3_message, user_id) ⇒ RubySMB::SMB1::Packet::SessionSetupRequest
Generates the SMB1::Packet::SessionSetupRequest packet with the NTLM Type 3 (Auth) message in the security_blob field.
134 135 136 137 138 139 140 141 142 |
# File 'lib/ruby_smb/client/authentication.rb', line 134 def smb1_ntlmssp_auth_packet(, user_id) packet = RubySMB::SMB1::Packet::SessionSetupRequest.new packet.smb_header.uid = user_id packet.set_type3_blob(.serialize) packet.parameter_block.max_buffer_size = self.max_buffer_size packet.parameter_block.max_mpx_count = 50 packet.smb_header.flags2.extended_security = 1 packet end |
#smb1_ntlmssp_authenticate(type3_message, user_id) ⇒ String
Takes the NTLM Type 3 (authenticate) message and calls the routines to build the Auth packet, sends the packet and receives the raw response.
123 124 125 126 |
# File 'lib/ruby_smb/client/authentication.rb', line 123 def smb1_ntlmssp_authenticate(, user_id) packet = smb1_ntlmssp_auth_packet(, user_id) send_recv(packet) end |
#smb1_ntlmssp_challenge_packet(raw_response) ⇒ Object
Takes the raw binary string and returns a SMB1::Packet::SessionSetupResponse
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/ruby_smb/client/authentication.rb', line 179 def smb1_ntlmssp_challenge_packet(raw_response) packet = RubySMB::SMB1::Packet::SessionSetupResponse.read(raw_response) unless packet.valid? raise RubySMB::Error::InvalidPacket.new( expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID, expected_cmd: RubySMB::SMB1::Packet::SessionSetupResponse::COMMAND, packet: packet ) end status_code = packet.status_code unless status_code.name == 'STATUS_MORE_PROCESSING_REQUIRED' raise RubySMB::Error::UnexpectedStatusCode, status_code end packet end |
#smb1_ntlmssp_final_packet(raw_response) ⇒ Object
Takes the raw binary string and returns a SMB1::Packet::SessionSetupResponse
174 175 176 |
# File 'lib/ruby_smb/client/authentication.rb', line 174 def smb1_ntlmssp_final_packet(raw_response) smb1_session_setup_response(raw_response) end |
#smb1_ntlmssp_negotiate ⇒ String
Sends the SMB1::Packet::SessionSetupRequest packet and receives the response.
112 113 114 115 |
# File 'lib/ruby_smb/client/authentication.rb', line 112 def smb1_ntlmssp_negotiate packet = smb1_ntlmssp_negotiate_packet send_recv(packet) end |
#smb1_ntlmssp_negotiate_packet ⇒ RubySMB::SMB1::Packet::SessionSetupRequest
Creates the SMB1::Packet::SessionSetupRequest packet for the first part of the NTLMSSP 4-way hnadshake. This packet initializes negotiations for the NTLMSSP authentication
149 150 151 152 153 154 155 156 157 |
# File 'lib/ruby_smb/client/authentication.rb', line 149 def smb1_ntlmssp_negotiate_packet = ntlm_client.init_context packet = RubySMB::SMB1::Packet::SessionSetupRequest.new packet.set_type1_blob(.serialize) packet.parameter_block.max_buffer_size = self.max_buffer_size packet.parameter_block.max_mpx_count = 50 packet.smb_header.flags2.extended_security = 1 packet end |
#smb1_session_setup_response(raw_response) ⇒ Object
Takes the raw binary string and returns a SMB1::Packet::SessionSetupResponse
160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/ruby_smb/client/authentication.rb', line 160 def smb1_session_setup_response(raw_response) packet = RubySMB::SMB1::Packet::SessionSetupResponse.read(raw_response) unless packet.valid? raise RubySMB::Error::InvalidPacket.new( expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID, expected_cmd: RubySMB::SMB1::Packet::SessionSetupResponse::COMMAND, packet: packet ) end packet end |
#smb1_type2_message(response_packet) ⇒ String
Parses out the NTLM Type 2 Message from a SMB1::Packet::SessionSetupResponse
201 202 203 204 205 206 |
# File 'lib/ruby_smb/client/authentication.rb', line 201 def (response_packet) sec_blob = response_packet.data_block.security_blob ntlmssp_offset = sec_blob.index('NTLMSSP') type2_blob = sec_blob.slice(ntlmssp_offset..-1) [type2_blob].pack('m') end |
#smb2_authenticate ⇒ Object
Handles the SMB2 NTLMSSP 4-way handshake for Authentication and store information about the peer/server.
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 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
# File 'lib/ruby_smb/client/authentication.rb', line 263 def smb2_authenticate @mech_type = :ntlm response = smb2_ntlmssp_negotiate challenge_packet = smb2_ntlmssp_challenge_packet(response) if @dialect == '0x0311' update_preauth_hash(challenge_packet) end @session_id = challenge_packet.smb2_header.session_id = (challenge_packet) = @ntlm_client.init_context() @application_key = @session_key = @ntlm_client.session_key = ntlm_client.session. store_target_info(.target_info) if .has_flag?(:TARGET_INFO) @os_version = extract_os_version(.os_version.to_s) unless .os_version.empty? raw = smb2_ntlmssp_authenticate(, @session_id) response = smb2_ntlmssp_final_packet(raw) @session_is_guest = response.session_flags.guest == 1 if @smb3 if response.session_flags.encrypt_data == 1 # if the server indicates that encryption is required, enable it @session_encrypt_data = true elsif (@session_is_guest && password != '') || (username == '' && password == '') # disable encryption when necessary @session_encrypt_data = false end # see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/7fd079ca-17e6-4f02-8449-46b606ea289c if @dialect == '0x0300' || @dialect == '0x0302' @application_key = RubySMB::Crypto::KDF.counter_mode( @session_key, "SMB2APP\x00", "SmbRpc\x00" ) else @application_key = RubySMB::Crypto::KDF.counter_mode( @session_key, "SMBAppKey\x00", @preauth_integrity_hash_value ) end # otherwise, leave encryption to the default value that it was initialized to end ###### # DEBUG #puts "Session ID = #{@session_id.to_binary_s.each_byte.map {|e| '%02x' % e}.join}" #puts "Session key = #{@session_key.each_byte.map {|e| '%02x' % e}.join}" #puts "PreAuthHash = #{@preauth_integrity_hash_value.each_byte.map {|e| '%02x' % e}.join}" if @preauth_integrity_hash_value ###### response.status_code end |
#smb2_ntlmssp_auth_packet(type3_message, session_id) ⇒ RubySMB::SMB2::Packet::SessionSetupRequest
Generates the SMB2::Packet::SessionSetupRequest packet with the NTLM Type 3 (Auth) message in the security_blob field.
413 414 415 416 417 418 419 |
# File 'lib/ruby_smb/client/authentication.rb', line 413 def smb2_ntlmssp_auth_packet(, session_id) packet = RubySMB::SMB2::Packet::SessionSetupRequest.new packet.smb2_header.session_id = session_id packet.set_type3_blob(.serialize) packet.security_mode.signing_enabled = 1 packet end |
#smb2_ntlmssp_authenticate(type3_message, user_id) ⇒ String
Takes the NTLM Type 3 (authenticate) message and calls the routines to build the Auth packet, sends the packet and receives the raw response.
398 399 400 401 402 403 404 405 |
# File 'lib/ruby_smb/client/authentication.rb', line 398 def smb2_ntlmssp_authenticate(, user_id) packet = smb2_ntlmssp_auth_packet(, user_id) response = send_recv(packet) if @dialect == '0x0311' update_preauth_hash(packet) end response end |
#smb2_ntlmssp_challenge_packet(raw_response) ⇒ Object
Takes the raw binary string and returns a SMB2::Packet::SessionSetupResponse
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 |
# File 'lib/ruby_smb/client/authentication.rb', line 338 def smb2_ntlmssp_challenge_packet(raw_response) packet = RubySMB::SMB2::Packet::SessionSetupResponse.read(raw_response) unless packet.valid? raise RubySMB::Error::InvalidPacket.new( expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID, expected_cmd: RubySMB::SMB2::Packet::SessionSetupResponse::COMMAND, packet: packet ) end status_code = packet.status_code unless status_code.name == 'STATUS_MORE_PROCESSING_REQUIRED' raise RubySMB::Error::UnexpectedStatusCode, status_code end packet end |
#smb2_ntlmssp_final_packet(raw_response) ⇒ Object
Takes the raw binary string and returns a SMB2::Packet::SessionSetupResponse
333 334 335 |
# File 'lib/ruby_smb/client/authentication.rb', line 333 def smb2_ntlmssp_final_packet(raw_response) smb2_session_setup_response(raw_response) end |
#smb2_ntlmssp_negotiate ⇒ String
Sends the SMB2::Packet::SessionSetupRequest packet and receives the response.
359 360 361 362 363 364 365 366 |
# File 'lib/ruby_smb/client/authentication.rb', line 359 def smb2_ntlmssp_negotiate packet = smb2_ntlmssp_negotiate_packet response = send_recv(packet) if @dialect == '0x0311' update_preauth_hash(packet) end response end |
#smb2_ntlmssp_negotiate_packet ⇒ RubySMB::SMB2::Packet::SessionSetupRequest
Creates the SMB2::Packet::SessionSetupRequest packet for the first part of the NTLMSSP 4-way handshake. This packet initializes negotiations for the NTLMSSP authentication
373 374 375 376 377 378 379 |
# File 'lib/ruby_smb/client/authentication.rb', line 373 def smb2_ntlmssp_negotiate_packet = ntlm_client.init_context packet = RubySMB::SMB2::Packet::SessionSetupRequest.new packet.set_type1_blob(.serialize) packet.security_mode.signing_enabled = 1 packet end |
#smb2_session_setup_response(raw_response) ⇒ Object
Takes the raw binary string and returns a SMB2::Packet::SessionSetupResponse
319 320 321 322 323 324 325 326 327 328 329 330 |
# File 'lib/ruby_smb/client/authentication.rb', line 319 def smb2_session_setup_response(raw_response) packet = RubySMB::SMB2::Packet::SessionSetupResponse.read(raw_response) unless packet.valid? raise RubySMB::Error::InvalidPacket.new( expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID, expected_cmd: RubySMB::SMB2::Packet::SessionSetupResponse::COMMAND, packet: packet ) end packet end |
#smb2_type2_message(response_packet) ⇒ String
Parses out the NTLM Type 2 Message from a SMB2::Packet::SessionSetupResponse
385 386 387 388 389 390 |
# File 'lib/ruby_smb/client/authentication.rb', line 385 def (response_packet) sec_blob = response_packet.buffer ntlmssp_offset = sec_blob.index('NTLMSSP') type2_blob = sec_blob.slice(ntlmssp_offset..-1) [type2_blob].pack('m') end |