Skip to content

Commit

Permalink
Move the DNS lookup to #connect
Browse files Browse the repository at this point in the history
  • Loading branch information
zeroSteiner committed Oct 12, 2023
1 parent 7e2750e commit c855c56
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 35 deletions.
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,6 @@ group :test do
# Manipulate Time.now in specs
gem 'timecop'
end

# remove before https://github.com/rapid7/metasploit-framework/pull/18446 is landed
gem 'rex-socket', git: 'https://github.com/zeroSteiner/rex-socket', branch: 'feat/resolve/getresources'
11 changes: 9 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
GIT
remote: https://github.com/zeroSteiner/rex-socket
revision: 6b41c7cca3984665e696184eb282dff7089089bc
branch: feat/resolve/getresources
specs:
rex-socket (0.1.55)
rex-core

PATH
remote: .
specs:
Expand Down Expand Up @@ -418,8 +426,6 @@ GEM
metasm
rex-core
rex-text
rex-socket (0.1.54)
rex-core
rex-sslscan (0.1.10)
rex-core
rex-socket
Expand Down Expand Up @@ -561,6 +567,7 @@ DEPENDENCIES
pry-byebug
rake
redcarpet
rex-socket!
rspec-rails
rspec-rerun
rubocop
Expand Down
45 changes: 22 additions & 23 deletions lib/msf/core/exploit/remote/kerberos/service_authenticator/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,26 +124,6 @@ def initialize(
offered_etypes: nil,
pfx: nil
)
@framework = framework
@framework_module = framework_module

if host.nil?
vprint_status("Using DNS to lookup the KDC for #{realm}...")
host = ::Rex::Socket.getresources("_kerberos._tcp.#{realm}", :SRV)&.sample
if host.nil?
raise ::Rex::Proto::Kerberos::Model::Error::KerberosError.new("Failed to lookup the KDC")
end
print_status("Using KDC #{host} for realm #{realm}")
end
unless ::Rex::Socket.is_ip_addr?(host)
vprint_status("Using DNS to resolve the address for the #{host} KDC...")
begin
host = ::Rex::Socket.getaddress(host)
rescue SocketError
raise ::Rex::Proto::Kerberos::Model::Error::KerberosError.new("Failed to resolve the KDC address")
end
end

@realm = realm
@hostname = hostname
@host = host
Expand All @@ -153,6 +133,8 @@ def initialize(
@username = username
@password = password
@pfx = pfx
@framework = framework
@framework_module = framework_module
@mutual_auth = mutual_auth
@use_gss_checksum = use_gss_checksum
@mechanism = mechanism
Expand Down Expand Up @@ -202,6 +184,23 @@ def rport
port
end

def connect(options = {})
unless options[:rhost]
unless (host = @host)
vprint_status("Using DNS to lookup the KDC for #{realm}...")
host = ::Rex::Socket.getresources("_kerberos._tcp.#{realm}", :SRV)&.sample
if host.nil?
raise ::Rex::Proto::Kerberos::Model::Error::KerberosError.new("Failed to lookup the KDC")
end
print_status("Using KDC #{host} for realm #{realm}")
@host = host
end
options[:rhost] = host
end

super(options)
end

# @param [Hash] options
# @option options [String] :credential An explicit credential object to use for authentication.
# @option options [Rex::Proto::Kerberos::Model::PrincipalName] :sname The target service principal name.
Expand Down Expand Up @@ -232,7 +231,7 @@ def authenticate(options = {})
)
end
if options[:credential]
print_status("#{peer} - Using cached credential for #{options[:credential].server} #{options[:credential].client}")
print_status("Using cached credential for #{options[:credential].server} #{options[:credential].client}")
end
end
end
Expand Down Expand Up @@ -344,7 +343,7 @@ def request_tgt_only(options = {})
end

if credential
print_status("#{peer} - Using cached credential for #{credential.server} #{credential.client}")
print_status("Using cached credential for #{credential.server} #{credential.client}")
return credential
end

Expand All @@ -362,7 +361,7 @@ def request_tgt_only(options = {})
def request_tgs_only(credential, options = {})
# load a cached TGS
if (ccache = get_cached_credential(options))
print_status("#{peer} - Using cached credential for #{ccache.server} #{ccache.client}")
print_status("Using cached credential for #{ccache.server} #{ccache.client}")
return ccache
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,25 @@
described_class.new(**params)
end

describe '#initialize' do
describe '#connect' do
before(:each) do
allow(params[:framework_module]).to receive(:framework)
allow(params[:framework_module]).to receive(:print_status)
allow(params[:framework_module]).to receive(:vprint_status)
end

context 'when host is a hostname' do
it 'resolves it to an IP address' do
expect(::Rex::Socket).to receive(:getaddress).with('mock_host').and_return(params[:host])
described_class.new(**params.merge(host: 'mock_host'))
end
end

context 'when host is nil' do
it 'resolves it to a hostname' do
expect(::Rex::Socket).to receive(:getresources).with("_kerberos._tcp.#{params[:realm]}", :SRV).and_return(['mock_host'])
expect(::Rex::Socket).to receive(:getaddress).with('mock_host').and_return(params[:host])
described_class.new(**params)
instance = described_class.new(**params.merge(host: nil))
instance.connect
expect(instance.host).to eq('mock_host')
end

it 'raises a KerberosError on failure' do
expect(::Rex::Socket).to receive(:getresources).with("_kerberos._tcp.#{params[:realm]}", :SRV).and_return([])
instance = described_class.new(**params.merge(host: nil))
expect { instance.connect }.to raise_error(::Rex::Proto::Kerberos::Model::Error::KerberosError)
end
end
end
Expand Down

1 comment on commit c855c56

@sempervictus
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, having the bare object not do anything to on-net seems prudent

Please sign in to comment.