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 |
# 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 @user_id = user_id if response_code == WindowsError::NTStatus::STATUS_SUCCESS response_code end |
#smb1_legacy_auth_request(lm_response, ntlm_response) ⇒ Object
233 234 235 236 237 238 239 240 241 242 |
# File 'lib/ruby_smb/client/authentication.rb', line 233 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
244 245 246 247 248 249 250 251 252 253 254 |
# File 'lib/ruby_smb/client/authentication.rb', line 244 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.
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
# File 'lib/ruby_smb/client/authentication.rb', line 211 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.
133 134 135 136 137 138 139 140 141 |
# File 'lib/ruby_smb/client/authentication.rb', line 133 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.
122 123 124 125 |
# File 'lib/ruby_smb/client/authentication.rb', line 122 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
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/ruby_smb/client/authentication.rb', line 178 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
173 174 175 |
# File 'lib/ruby_smb/client/authentication.rb', line 173 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.
111 112 113 114 |
# File 'lib/ruby_smb/client/authentication.rb', line 111 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
148 149 150 151 152 153 154 155 156 |
# File 'lib/ruby_smb/client/authentication.rb', line 148 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
159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/ruby_smb/client/authentication.rb', line 159 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
200 201 202 203 204 205 |
# File 'lib/ruby_smb/client/authentication.rb', line 200 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.
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 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/ruby_smb/client/authentication.rb', line 262 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.
412 413 414 415 416 417 418 |
# File 'lib/ruby_smb/client/authentication.rb', line 412 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.
397 398 399 400 401 402 403 404 |
# File 'lib/ruby_smb/client/authentication.rb', line 397 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
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 |
# File 'lib/ruby_smb/client/authentication.rb', line 337 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
332 333 334 |
# File 'lib/ruby_smb/client/authentication.rb', line 332 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.
358 359 360 361 362 363 364 365 |
# File 'lib/ruby_smb/client/authentication.rb', line 358 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
372 373 374 375 376 377 378 |
# File 'lib/ruby_smb/client/authentication.rb', line 372 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
318 319 320 321 322 323 324 325 326 327 328 329 |
# File 'lib/ruby_smb/client/authentication.rb', line 318 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
384 385 386 387 388 389 |
# File 'lib/ruby_smb/client/authentication.rb', line 384 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 |