Module: RubySMB::Server::ServerClient::Negotiation
- Included in:
- RubySMB::Server::ServerClient
- Defined in:
- lib/ruby_smb/server/server_client/negotiation.rb
Instance Method Summary collapse
- #do_negotiate_smb1(request) ⇒ Object
- #do_negotiate_smb2(request) ⇒ Object
-
#handle_negotiate(raw_request) ⇒ Object
Handle an SMB negotiation request.
Instance Method Details
#do_negotiate_smb1(request) ⇒ Object
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/ruby_smb/server/server_client/negotiation.rb', line 32 def do_negotiate_smb1(request) client_dialects = request.dialects.map(&:dialect_string).map(&:value) if client_dialects.include?(Client::SMB1_DIALECT_SMB2_WILDCARD) && \ @server.dialects.any? { |dialect| Dialect[dialect].order == Dialect::ORDER_SMB2 } response = SMB2::Packet::NegotiateResponse.new response.smb2_header.credits = 1 response.security_mode.signing_enabled = 1 response.dialect_revision = SMB2::SMB2_WILDCARD_REVISION response.server_guid = @server.guid response.max_transact_size = 0x800000 response.max_read_size = 0x800000 response.max_write_size = 0x800000 response.system_time.set(Time.now) response.security_buffer_offset = response.security_buffer.abs_offset response.security_buffer = process_gss.buffer return response end server_dialects = @server.dialects.select { |dialect| Dialect[dialect].order == Dialect::ORDER_SMB1 } dialect = (server_dialects & client_dialects).first if dialect.nil? # 'NT LM 0.12' is currently the only supported dialect # see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/80850595-e301-4464-9745-58e4945eb99b response = SMB1::Packet::NegotiateResponse.new response.parameter_block.word_count = 1 response.parameter_block.dialect_index = 0xffff response.data_block.byte_count = 0 return response end response = SMB1::Packet::NegotiateResponseExtended.new response.parameter_block.dialect_index = client_dialects.index(dialect) response.parameter_block.max_mpx_count = 50 response.parameter_block.max_number_vcs = 1 response.parameter_block.max_buffer_size = 16644 response.parameter_block.max_raw_size = 65536 server_time = Time.now response.parameter_block.system_time.set(server_time) response.parameter_block.server_time_zone = server_time.utc_offset response.data_block.server_guid = @server.guid response.data_block.security_blob = process_gss.buffer @dialect = dialect response end |
#do_negotiate_smb2(request) ⇒ Object
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 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/ruby_smb/server/server_client/negotiation.rb', line 80 def do_negotiate_smb2(request) client_dialects = request.dialects.map { |d| "0x%04x" % d } server_dialects = @server.dialects.select { |dialect| Dialect[dialect].order == Dialect::ORDER_SMB2 } dialect = (server_dialects & client_dialects).first response = SMB2::Packet::NegotiateResponse.new response.smb2_header.credits = 1 response.smb2_header. = request.smb2_header. response.security_mode.signing_enabled = 1 response.server_guid = @server.guid response.max_transact_size = 0x800000 response.max_read_size = 0x800000 response.max_write_size = 0x800000 response.system_time.set(Time.now) if dialect.nil? # see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/b39f253e-4963-40df-8dff-2f9040ebbeb1 # > If a common dialect is not found, the server MUST fail the request with STATUS_NOT_SUPPORTED. response.smb2_header.nt_status = WindowsError::NTStatus::STATUS_NOT_SUPPORTED.value return response end contexts = [] hash_algorithm = hash_value = nil if dialect == '0x0311' # see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/b39f253e-4963-40df-8dff-2f9040ebbeb1 nc = request.find_negotiate_context(SMB2::NegotiateContext::SMB2_PREAUTH_INTEGRITY_CAPABILITIES) hash_algorithm = SMB2::PreauthIntegrityCapabilities::HASH_ALGORITM_MAP[nc&.data&.hash_algorithms&.first] hash_value = "\x00" * 64 unless hash_algorithm response.smb2_header.nt_status = WindowsError::NTStatus::STATUS_INVALID_PARAMETER.value return response end contexts << SMB2::NegotiateContext.new( context_type: SMB2::NegotiateContext::SMB2_PREAUTH_INTEGRITY_CAPABILITIES, data: { hash_algorithms: [ SMB2::PreauthIntegrityCapabilities::SHA_512 ], salt: SecureRandom.random_bytes(32) } ) nc = request.find_negotiate_context(SMB2::NegotiateContext::SMB2_ENCRYPTION_CAPABILITIES) ciphers = nc&.data&.ciphers if ciphers cipher = ciphers.find { |cipher| SMB2::EncryptionCapabilities::ENCRYPTION_ALGORITHM_MAP.include?(cipher) } @cipher_id = cipher unless cipher.nil? end contexts << SMB2::NegotiateContext.new( context_type: SMB2::NegotiateContext::SMB2_ENCRYPTION_CAPABILITIES, data: { ciphers: [ @cipher_id ] } ) elsif dialect == '0x0300' || dialect == '0x0302' if request.capabilities.encryption == 1 response.capabilities.encryption = 1 @cipher_id = SMB2::EncryptionCapabilities::AES_128_CCM else response.capabilities = 0 end end # the order in which the response is built is important to ensure it is valid response.dialect_revision = dialect.to_i(16) response.security_buffer_offset = response.security_buffer.abs_offset response.security_buffer = process_gss.buffer if dialect == '0x0311' response.negotiate_context_offset = response.negotiate_context_list.abs_offset contexts.each { |nc| response.add_negotiate_context(nc) } end @preauth_integrity_hash_algorithm = hash_algorithm @preauth_integrity_hash_value = hash_value if dialect == '0x0311' update_preauth_hash(request) update_preauth_hash(response) end @dialect = dialect response end |
#handle_negotiate(raw_request) ⇒ Object
Handle an SMB negotiation request. Once negotiation is complete, the state will be updated to :session_setup. At this point the @dialect will have been set along with other dialect-specific values.
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/ruby_smb/server/server_client/negotiation.rb', line 12 def handle_negotiate(raw_request) response = nil case raw_request[0...4].unpack1('L>') when RubySMB::SMB1::SMB_PROTOCOL_ID request = SMB1::Packet::NegotiateRequest.read(raw_request) response = do_negotiate_smb1(request) if request.is_a?(SMB1::Packet::NegotiateRequest) when RubySMB::SMB2::SMB2_PROTOCOL_ID request = SMB2::Packet::NegotiateRequest.read(raw_request) response = do_negotiate_smb2(request) if request.is_a?(SMB2::Packet::NegotiateRequest) end if response.nil? disconnect! else send_packet(response) end nil end |