From e492eef494213b6079b3491e862916c26e93cb42 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Fri, 13 Sep 2024 11:06:45 -0400 Subject: [PATCH] Finish removing code from old work arounds --- lib/ruby_smb.rb | 1 - lib/ruby_smb/ntlm.rb | 37 --------- lib/ruby_smb/ntlm/client.rb | 77 +------------------ lib/ruby_smb/ntlm/custom/string_encoder.rb | 22 ------ ruby_smb.gemspec | 13 +++- spec/lib/ruby_smb/ntlm/client/session_spec.rb | 2 +- 6 files changed, 14 insertions(+), 138 deletions(-) delete mode 100644 lib/ruby_smb/ntlm/custom/string_encoder.rb diff --git a/lib/ruby_smb.rb b/lib/ruby_smb.rb index bfc0871cf..173f5bda4 100644 --- a/lib/ruby_smb.rb +++ b/lib/ruby_smb.rb @@ -6,7 +6,6 @@ require 'openssl/cmac' require 'windows_error' require 'windows_error/nt_status' -require 'ruby_smb/ntlm/custom/string_encoder' # A packet parsing and manipulation library for the SMB1 and SMB2 protocols # # [[MS-SMB] Server Message Block (SMB) Protocol Version 1](https://msdn.microsoft.com/en-us/library/cc246482.aspx) diff --git a/lib/ruby_smb/ntlm.rb b/lib/ruby_smb/ntlm.rb index c642de5aa..2f60dece1 100644 --- a/lib/ruby_smb/ntlm.rb +++ b/lib/ruby_smb/ntlm.rb @@ -1,5 +1,3 @@ -require 'ruby_smb/ntlm/custom/string_encoder' - module RubySMB module NTLM # [[MS-NLMP] 2.2.2.5](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/99d90ff4-957f-4c8a-80e4-5bfe5a9a9832) @@ -58,41 +56,6 @@ def to_s "Version #{major}.#{minor} (Build #{build}); NTLM Current Revision #{ntlm_revision}" end end - - class << self - - # Generate a NTLMv2 Hash - # @param [String] user The username - # @param [String] password The password - # @param [String] target The domain or workstation to authenticate to - # @option opt :unicode (false) Unicode encode the domain - def ntlmv2_hash(user, password, target, opt={}) - if Net::NTLM.is_ntlm_hash? password - decoded_password = Net::NTLM::EncodeUtil.decode_utf16le(password) - ntlmhash = [decoded_password.upcase[33,65]].pack('H32') - else - ntlmhash = Net::NTLM.ntlm_hash(password, opt) - end - - if opt[:unicode] - # Uppercase operation on username containing non-ASCII characters - # after being unicode encoded with `EncodeUtil.encode_utf16le` - # doesn't play well. Upcase should be done before encoding. - user_upcase = Net::NTLM::EncodeUtil.decode_utf16le(user).upcase - user_upcase = Net::NTLM::EncodeUtil.encode_utf16le(user_upcase) - else - user_upcase = user.upcase - end - userdomain = user_upcase + target - - unless opt[:unicode] - userdomain = Net::NTLM::EncodeUtil.encode_utf16le(userdomain) - end - OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmhash, userdomain) - end - - end - end end diff --git a/lib/ruby_smb/ntlm/client.rb b/lib/ruby_smb/ntlm/client.rb index 9210459a9..6e9865fe2 100644 --- a/lib/ruby_smb/ntlm/client.rb +++ b/lib/ruby_smb/ntlm/client.rb @@ -1,78 +1,7 @@ module RubySMB::NTLM - module Message - def deflag - security_buffers.inject(head_size) do |cur, a| - a[1].offset = cur - cur += a[1].data_size - has_flag?(:UNICODE) ? cur + cur % 2 : cur - end - end - - def serialize - deflag - @alist.map { |n, f| f.serialize }.join + security_buffers.map { |n, f| f.value + (has_flag?(:UNICODE) ? "\x00".b * (f.value.length % 2) : '') }.join - end - end - class Client < Net::NTLM::Client - class Session < Net::NTLM::Client::Session - def authenticate! - calculate_user_session_key! - type3_opts = { - :lm_response => is_anonymous? ? "\x00".b : lmv2_resp, - :ntlm_response => is_anonymous? ? '' : ntlmv2_resp, - :domain => domain, - :user => username, - :workstation => workstation, - :flag => (challenge_message.flag & client.flags) - } - t3 = Net::NTLM::Message::Type3.create type3_opts - t3.extend(Message) - if negotiate_key_exchange? - t3.enable(:session_key) - rc4 = OpenSSL::Cipher.new("rc4") - rc4.encrypt - rc4.key = user_session_key - sk = rc4.update exported_session_key - sk << rc4.final - t3.session_key = sk - end - t3 - end - - def is_anonymous? - username == '' && password == '' - end - - private - - def use_oem_strings? - # @see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/99d90ff4-957f-4c8a-80e4-5bfe5a9a9832 - !challenge_message.has_flag?(:UNICODE) && challenge_message.has_flag?(:OEM) - end - - def ntlmv2_hash - @ntlmv2_hash ||= RubySMB::NTLM.ntlmv2_hash(username, password, domain, {:client_challenge => client_challenge, :unicode => !use_oem_strings?}) - end - - def calculate_user_session_key! - if is_anonymous? - # see MS-NLMP section 3.4 - @user_session_key = "\x00".b * 16 - else - @user_session_key = OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmv2_hash, nt_proof_str) - end - end - end - - def init_context(resp = nil, channel_binding = nil) - if resp.nil? - @session = nil - type1_message - else - @session = Client::Session.new(self, Net::NTLM::Message.decode64(resp), channel_binding) - @session.authenticate! - end - end + # There was a bunch of code in here that was necessary in versions up to and including rubyntlm version 0.6.3. + # The class is kept because there are references to it that should be kept in place in case future alterations to + # rubyntlm are required. end end diff --git a/lib/ruby_smb/ntlm/custom/string_encoder.rb b/lib/ruby_smb/ntlm/custom/string_encoder.rb deleted file mode 100644 index 45e1ddce5..000000000 --- a/lib/ruby_smb/ntlm/custom/string_encoder.rb +++ /dev/null @@ -1,22 +0,0 @@ -require 'net/ntlm' - -module RubySMB - module NTLM - module Custom - module StringEncoder - - def self.prepended(base) - base.singleton_class.send(:prepend, ClassMethods) - end - - module ClassMethods - def encode_utf16le(str) - str.dup.force_encoding('UTF-8').encode(Encoding::UTF_16LE, Encoding::UTF_8).force_encoding('ASCII-8BIT') - end - end - end - end - end -end - -Net::NTLM::EncodeUtil.send(:prepend, RubySMB::NTLM::Custom::StringEncoder) diff --git a/ruby_smb.gemspec b/ruby_smb.gemspec index ea91464eb..4b9b28265 100644 --- a/ruby_smb.gemspec +++ b/ruby_smb.gemspec @@ -6,11 +6,18 @@ require 'ruby_smb/version' Gem::Specification.new do |spec| spec.name = 'ruby_smb' spec.version = RubySMB::VERSION - spec.authors = ['Metasploit Hackers', 'David Maloney', 'James Lee', 'Dev Mohanty', 'Christophe De La Fuente'] + spec.authors = [ + 'Metasploit Hackers', + 'David Maloney', + 'James Lee', + 'Dev Mohanty', + 'Christophe De La Fuente', + 'Spencer McIntyre' + ] spec.email = ['msfdev@metasploit.com'] spec.summary = 'A pure Ruby implementation of the SMB Protocol Family' spec.description = '' - spec.homepage = 'https://github.com/rapid7/ruby_smb' + spec.homepage = 'https://github.com/rapid7/ruby_smb' spec.license = 'BSD-3-clause' spec.files = `git ls-files -z`.split("\x0") @@ -33,7 +40,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'rake' spec.add_development_dependency 'yard' - spec.add_runtime_dependency 'rubyntlm' + spec.add_runtime_dependency 'rubyntlm', '>= 0.6.5' spec.add_runtime_dependency 'windows_error', '>= 0.1.4' spec.add_runtime_dependency 'bindata', '2.4.15' spec.add_runtime_dependency 'openssl-ccm' diff --git a/spec/lib/ruby_smb/ntlm/client/session_spec.rb b/spec/lib/ruby_smb/ntlm/client/session_spec.rb index c675a10d1..53a80423c 100644 --- a/spec/lib/ruby_smb/ntlm/client/session_spec.rb +++ b/spec/lib/ruby_smb/ntlm/client/session_spec.rb @@ -24,7 +24,7 @@ it 'returns a Type3 message' do expect(session.authenticate!).to be_a Net::NTLM::Message::Type3 - expect(session.authenticate!).to be_a RubySMB::NTLM::Message + expect(session.authenticate!).to be_a Net::NTLM::Message end context 'when it is anonymous' do