Skip to content

Commit 7fdb1e0

Browse files
committed
Tie in Kerberos authentication for HTTP modules
1 parent c843e36 commit 7fdb1e0

File tree

3 files changed

+50
-4
lines changed

3 files changed

+50
-4
lines changed

lib/msf/core/exploit/remote/http_client.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ module Exploit::Remote::HttpClient
1515

1616
include Msf::Auxiliary::Report
1717
include Msf::Auxiliary::LoginScanner
18+
include Msf::Exploit::Remote::Kerberos::Ticket::Storage
1819

1920
#
2021
# Initializes an exploit module that exploits a vulnerability in an HTTP
@@ -155,6 +156,25 @@ def connect(opts={})
155156

156157
http_logger_subscriber = Rex::Proto::Http::HttpLoggerSubscriber.new(logger: self)
157158

159+
if datastore['HTTP::Auth'] == Msf::Exploit::Remote::AuthOption::KERBEROS
160+
kerberos_authenticator = Msf::Exploit::Remote::Kerberos::ServiceAuthenticator::HTTP.new(
161+
host: datastore['DomainControllerRhost'],
162+
hostname: datastore['HTTP::Rhostname'],
163+
proxies: datastore['Proxies'],
164+
realm: datastore['DOMAIN'],
165+
username: datastore['HttpUsername'],
166+
password: datastore['HttpPassword'],
167+
timeout: 20, # datastore['timeout']
168+
framework: framework,
169+
framework_module: self,
170+
cache_file: datastore['HTTP::Krb5Ccname'].blank? ? nil : datastore['HTTP::Krb5Ccname'],
171+
mutual_auth: true,
172+
use_gss_checksum: true,
173+
ticket_storage: kerberos_ticket_storage,
174+
offered_etypes: Msf::Exploit::Remote::AuthOption.as_default_offered_etypes(datastore['HTTP::KrbOfferedEncryptionTypes'])
175+
)
176+
end
177+
158178
nclient = Rex::Proto::Http::Client.new(
159179
opts['rhost'] || rhost,
160180
(opts['rport'] || rport).to_i,
@@ -167,6 +187,7 @@ def connect(opts={})
167187
proxies,
168188
client_username,
169189
client_password,
190+
kerberos_authenticator: kerberos_authenticator,
170191
comm: opts['comm'],
171192
subscriber: http_logger_subscriber,
172193
sslkeylogfile: sslkeylogfile
@@ -375,6 +396,22 @@ def send_request_raw(opts = {}, timeout = 20, disconnect = false)
375396
actual_timeout = opts[:timeout] || timeout
376397
end
377398

399+
unless opts.key?('preferred_auth')
400+
case datastore['HTTP::Auth']
401+
when Msf::Exploit::Remote::AuthOption::AUTO
402+
opts['preferred_auth'] = nil
403+
when Msf::Exploit::Remote::AuthOption::KERBEROS
404+
opts['preferred_auth'] = 'Kerberos'
405+
when Msf::Exploit::Remote::AuthOption::NTLM
406+
opts['preferred_auth'] = 'NTLM'
407+
when Msf::Exploit::Remote::AuthOption::PLAINTEXT
408+
# Basic auth might as well be plaintext right?
409+
opts['preferred_auth'] = 'Basic'
410+
when Msf::Exploit::Remote::AuthOption::NONE
411+
opts['preferred_auth'] = 'None'
412+
end
413+
end
414+
378415
c = opts['client'] || connect(opts)
379416
r = opts['cgi'] ? c.request_cgi(opts) : c.request_raw(opts)
380417

lib/rex/proto/http/client.rb

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ def send_auth(res, opts, t, persist)
323323
return res
324324
elsif supported_auths.include?('Negotiate') && (preferred_auth.nil? || preferred_auth == 'Kerberos')
325325
opts['provider'] = 'Negotiate'
326-
temp_response = kerberos_auth(opts)
326+
temp_response = kerberos_auth(opts, mechanism: Rex::Proto::Gss::Mechanism::SPNEGO)
327327
if temp_response.is_a? Rex::Proto::Http::Response
328328
res = temp_response
329329
end
@@ -411,16 +411,21 @@ def digest_auth(opts = {})
411411
end
412412
end
413413

414-
def kerberos_auth(opts = {})
414+
def kerberos_auth(opts = {}, mechanism: Rex::Proto::Gss::Mechanism::KERBEROS)
415415
to = opts['timeout'] || 20
416-
auth_result = kerberos_authenticator.authenticate(mechanism: Rex::Proto::Gss::Mechanism::KERBEROS)
416+
auth_result = kerberos_authenticator.authenticate(mechanism: mechanism)
417417
gss_data = auth_result[:security_blob]
418418
gss_data_b64 = Rex::Text.encode_base64(gss_data)
419419

420420
# Separate options for the auth requests
421421
auth_opts = opts.clone
422422
auth_opts['headers'] = opts['headers'].clone
423-
auth_opts['headers']['Authorization'] = "Kerberos #{gss_data_b64}"
423+
case mechanism
424+
when Rex::Proto::Gss::Mechanism::KERBEROS
425+
auth_opts['headers']['Authorization'] = "Kerberos #{gss_data_b64}"
426+
when Rex::Proto::Gss::Mechanism::SPNEGO
427+
auth_opts['headers']['Authorization'] = "Negotiate #{gss_data_b64}"
428+
end
424429

425430
if auth_opts['no_body_for_auth']
426431
auth_opts.delete('data')

modules/auxiliary/scanner/http/title.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ class MetasploitModule < Msf::Auxiliary
88
include Msf::Exploit::Remote::HttpClient
99
# Scanner mixin should be near last
1010
include Msf::Auxiliary::Scanner
11+
include Msf::Exploit::Remote::Kerberos::Ticket::Storage
12+
include Msf::Exploit::Remote::Kerberos::ServiceAuthenticator::Options
1113

1214
def initialize
1315
super(
@@ -31,6 +33,8 @@ def initialize
3133

3234
register_advanced_options(
3335
[
36+
*kerberos_storage_options(protocol: 'HTTP'),
37+
*kerberos_auth_options(protocol: 'HTTP', auth_methods: Msf::Exploit::Remote::AuthOption::HTTP_OPTIONS),
3438
OptString.new('HttpQueryString', [ false, 'The HTTP query string', nil ]),
3539
OptBool.new('FollowRedirect', [ false, 'Follow a HTTP redirect', false ]),
3640
OptInt.new('FollowRedirectDepth', [false, 'Follow HTTP redirect depth', 1]),

0 commit comments

Comments
 (0)