Skip to content

Commit dcf7b5c

Browse files
committed
Land rapid7#6086, @jvazquez-r7's Fix Kerberos Client mixin Namespace
* If something breaks, blame @jvazquez-r7. Hopefully this is safe :)
2 parents bf9530d + 8057b3e commit dcf7b5c

26 files changed

+1000
-971
lines changed

lib/msf/core.rb

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,6 @@ module Msf
7272
require 'msf/http/typo3'
7373
require 'msf/http/jboss'
7474

75-
# Kerberos Support
76-
require 'msf/kerberos/client'
77-
7875
# Drivers
7976
require 'msf/core/exploit_driver'
8077

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# -*- coding: binary -*-
2+
require 'rex/proto/kerberos'
3+
4+
module Msf
5+
class Exploit
6+
class Remote
7+
module Kerberos
8+
module Client
9+
require 'msf/core/exploit/kerberos/client/base'
10+
require 'msf/core/exploit/kerberos/client/as_request'
11+
require 'msf/core/exploit/kerberos/client/as_response'
12+
require 'msf/core/exploit/kerberos/client/tgs_request'
13+
require 'msf/core/exploit/kerberos/client/tgs_response'
14+
require 'msf/core/exploit/kerberos/client/pac'
15+
require 'msf/core/exploit/kerberos/client/cache_credential'
16+
17+
include Msf::Exploit::Remote::Kerberos::Client::Base
18+
include Msf::Exploit::Remote::Kerberos::Client::AsRequest
19+
include Msf::Exploit::Remote::Kerberos::Client::AsResponse
20+
include Msf::Exploit::Remote::Kerberos::Client::TgsRequest
21+
include Msf::Exploit::Remote::Kerberos::Client::TgsResponse
22+
include Msf::Exploit::Remote::Kerberos::Client::Pac
23+
include Msf::Exploit::Remote::Kerberos::Client::CacheCredential
24+
25+
# @!attribute client
26+
# @return [Rex::Proto::Kerberos::Client] The kerberos client
27+
attr_accessor :client
28+
29+
def initialize(info = {})
30+
super
31+
32+
register_options(
33+
[
34+
Opt::RHOST,
35+
Opt::RPORT(88),
36+
OptInt.new('Timeout', [true, 'The TCP timeout to establish connection and read data', 10])
37+
], self.class
38+
)
39+
end
40+
41+
# Returns the target host
42+
#
43+
# @return [String]
44+
def rhost
45+
datastore['RHOST']
46+
end
47+
48+
# Returns the remote port
49+
#
50+
# @return [Fixnum]
51+
def rport
52+
datastore['RPORT']
53+
end
54+
55+
# Returns the TCP timeout
56+
#
57+
# @return [Fixnum]
58+
def timeout
59+
datastore['Timeout']
60+
end
61+
62+
# Returns the kdc peer
63+
#
64+
# @return [String]
65+
def peer
66+
"#{rhost}:#{rport}"
67+
end
68+
69+
# Creates a kerberos connection
70+
#
71+
# @param opts [Hash{Symbol => <String, Fixnum>}]
72+
# @option opts [String] :rhost
73+
# @option opts [<String, Fixnum>] :rport
74+
# @return [Rex::Proto::Kerberos::Client]
75+
def connect(opts={})
76+
kerb_client = Rex::Proto::Kerberos::Client.new(
77+
host: opts[:rhost] || rhost,
78+
port: (opts[:rport] || rport).to_i,
79+
timeout: (opts[:timeout] || timeout).to_i,
80+
context:
81+
{
82+
'Msf' => framework,
83+
'MsfExploit' => self,
84+
},
85+
protocol: 'tcp'
86+
)
87+
88+
disconnect if client
89+
self.client = kerb_client
90+
91+
kerb_client
92+
end
93+
94+
# Disconnects the Kerberos client
95+
#
96+
# @param kerb_client [Rex::Proto::Kerberos::Client] the client to disconnect
97+
def disconnect(kerb_client = client)
98+
kerb_client.close if kerb_client
99+
100+
if kerb_client == client
101+
self.client = nil
102+
end
103+
end
104+
105+
# Performs cleanup as necessary, disconnecting the Kerberos client
106+
# if it's still established.
107+
def cleanup
108+
super
109+
disconnect
110+
end
111+
112+
# Sends a kerberos AS request and reads the response
113+
#
114+
# @param opts [Hash]
115+
# @return [Rex::Proto::Kerberos::Model::KdcResponse]
116+
# @see Msf::Kerberos::Client::AsRequest#build_as_request
117+
# @see Rex::Proto::Kerberos::Model::KdcResponse
118+
def send_request_as(opts = {})
119+
connect(opts)
120+
req = build_as_request(opts)
121+
res = client.send_recv(req)
122+
disconnect
123+
res
124+
end
125+
126+
# Sends a kerberos AS request and reads the response
127+
#
128+
# @param opts [Hash]
129+
# @return [Rex::Proto::Kerberos::Model::KdcResponse]
130+
# @see Msf::Kerberos::Client::TgsRequest#build_tgs_request
131+
# @see Rex::Proto::Kerberos::Model::KdcResponse
132+
def send_request_tgs(opts = {})
133+
connect(opts)
134+
req = build_tgs_request(opts)
135+
res = client.send_recv(req)
136+
disconnect
137+
res
138+
end
139+
end
140+
end
141+
end
142+
end
143+
end
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# -*- coding: binary -*-
2+
require 'rex/proto/kerberos'
3+
4+
module Msf
5+
class Exploit
6+
class Remote
7+
module Kerberos
8+
module Client
9+
module AsRequest
10+
# Builds a kerberos AS request
11+
#
12+
# @param opts [Hash{Symbol => <Array<Rex::Proto::Kerberos::Model::PreAuthData>, Rex::Proto::Kerberos::Model::KdcRequestBody>}]
13+
# @option opts [Array<Rex::Proto::Kerberos::Model::PreAuthData>] :pa_data
14+
# @option opts [Rex::Proto::Kerberos::Model::KdcRequestBody] :body
15+
# @return [Rex::Proto::Kerberos::Model::KdcRequest]
16+
# @see [Rex::Proto::Kerberos::Model::KdcRequest]
17+
# @see #build_as_pa_time_stamp
18+
# @see #build_as_request_body
19+
def build_as_request(opts = {})
20+
pa_data = opts[:pa_data] || build_as_pa_time_stamp(opts)
21+
body = opts[:body] || build_as_request_body(opts)
22+
23+
request = Rex::Proto::Kerberos::Model::KdcRequest.new(
24+
pvno: 5,
25+
msg_type: Rex::Proto::Kerberos::Model::AS_REQ,
26+
pa_data: pa_data,
27+
req_body: body
28+
)
29+
30+
request
31+
end
32+
33+
# Builds a kerberos PA-ENC-TIMESTAMP pre authenticated structure
34+
#
35+
# @param opts [Hash{Symbol => <Time, Fixnum, String>}]
36+
# @option opts [Time] :time_stamp
37+
# @option opts [Fixnum] :pausec
38+
# @option opts [Fixnum] :etype
39+
# @option opts [String] :key
40+
# @return [Rex::Proto::Kerberos::Model::PreAuthData]
41+
# @see Rex::Proto::Kerberos::Model::PreAuthEncTimeStamp
42+
# @see Rex::Proto::Kerberos::Model::EncryptedData
43+
# @see Rex::Proto::Kerberos::Model::PreAuthData
44+
def build_as_pa_time_stamp(opts = {})
45+
time_stamp = opts[:time_stamp] || Time.now
46+
pausec = opts[:pausec] || 0
47+
etype = opts[:etype] || Rex::Proto::Kerberos::Crypto::RC4_HMAC
48+
key = opts[:key] || ''
49+
50+
pa_time_stamp = Rex::Proto::Kerberos::Model::PreAuthEncTimeStamp.new(
51+
pa_time_stamp: time_stamp,
52+
pausec: pausec
53+
)
54+
55+
enc_time_stamp = Rex::Proto::Kerberos::Model::EncryptedData.new(
56+
etype: etype,
57+
cipher: pa_time_stamp.encrypt(etype, key)
58+
)
59+
60+
pa_enc_time_stamp = Rex::Proto::Kerberos::Model::PreAuthData.new(
61+
type: Rex::Proto::Kerberos::Model::PA_ENC_TIMESTAMP,
62+
value: enc_time_stamp.encode
63+
)
64+
65+
pa_enc_time_stamp
66+
end
67+
68+
# Builds a kerberos AS request body
69+
#
70+
# @param opts [Hash{Symbol => <Fixnum, Time, String, Rex::Proto::Kerberos::Model::PrincipalName>}]
71+
# @option opts [Fixnum] :options
72+
# @option opts [Time] :from
73+
# @option opts [Time] :till
74+
# @option opts [Time] :rtime
75+
# @option opts [Fixnum] :nonce
76+
# @option opts [Fixnum] :etype
77+
# @option opts [Rex::Proto::Kerberos::Model::PrincipalName] :cname
78+
# @option opts [String] :realm
79+
# @option opts [Rex::Proto::Kerberos::Model::PrincipalName] :sname
80+
# @return [Rex::Proto::Kerberos::Model::KdcRequestBody]
81+
# @see #build_client_name
82+
# @see #build_server_name
83+
# @see Rex::Proto::Kerberos::Model::KdcRequestBody
84+
def build_as_request_body(opts = {})
85+
options = opts[:options] || 0x50800000 # Forwardable, Proxiable, Renewable
86+
from = opts[:from] || Time.utc('1970-01-01-01 00:00:00')
87+
till = opts[:till] || Time.utc('1970-01-01-01 00:00:00')
88+
rtime = opts[:rtime] || Time.utc('1970-01-01-01 00:00:00')
89+
nonce = opts[:nonce] || Rex::Text.rand_text_numeric(6).to_i
90+
etype = opts[:etype] || [Rex::Proto::Kerberos::Crypto::RC4_HMAC]
91+
cname = opts[:cname] || build_client_name(opts)
92+
realm = opts[:realm] || ''
93+
sname = opts[:sname] || build_server_name(opts)
94+
95+
body = Rex::Proto::Kerberos::Model::KdcRequestBody.new(
96+
options: options,
97+
cname: cname,
98+
realm: realm,
99+
sname: sname,
100+
from: from,
101+
till: till,
102+
rtime: rtime,
103+
nonce: nonce,
104+
etype: etype
105+
)
106+
107+
body
108+
end
109+
end
110+
end
111+
end
112+
end
113+
end
114+
end
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# -*- coding: binary -*-
2+
require 'rex/proto/kerberos'
3+
4+
module Msf
5+
class Exploit
6+
class Remote
7+
module Kerberos
8+
module Client
9+
module AsResponse
10+
# Extracts the session key from a Kerberos AS Response
11+
#
12+
# @param res [Rex::Proto::Kerberos::Model::KdcResponse]
13+
# @param key [String]
14+
# @return [Rex::Proto::Kerberos::Model::EncryptionKey]
15+
# @see Rex::Proto::Kerberos::Model::KdcResponse
16+
# @see Rex::Proto::Kerberos::Model::EncryptedData.decrypt
17+
# @see Rex::Proto::Kerberos::Model::EncKdcResponse
18+
# @see Rex::Proto::Kerberos::Model::EncKdcResponse.decode
19+
# @see Rex::Proto::Kerberos::Model::EncryptionKey
20+
def extract_session_key(res, key)
21+
decrypt_res = res.enc_part.decrypt(key, Rex::Proto::Kerberos::Crypto::ENC_AS_RESPONSE)
22+
enc_kdc_res = Rex::Proto::Kerberos::Model::EncKdcResponse.decode(decrypt_res)
23+
24+
enc_kdc_res.key
25+
end
26+
27+
# Extracts the logon time from a Kerberos AS Response
28+
#
29+
# @param res [Rex::Proto::Kerberos::Model::KdcResponse]
30+
# @param key [String]
31+
# @return [Fixnum]
32+
# @see Rex::Proto::Kerberos::Model::KdcResponse
33+
# @see Rex::Proto::Kerberos::Model::EncryptedData.decrypt
34+
# @see Rex::Proto::Kerberos::Model::EncKdcResponse
35+
# @see Rex::Proto::Kerberos::Model::EncKdcResponse.decode
36+
def extract_logon_time(res, key)
37+
decrypt_res = res.enc_part.decrypt(key, Rex::Proto::Kerberos::Crypto::ENC_AS_RESPONSE)
38+
enc_kdc_res = Rex::Proto::Kerberos::Model::EncKdcResponse.decode(decrypt_res)
39+
40+
auth_time = enc_kdc_res.auth_time
41+
42+
auth_time.to_i
43+
end
44+
end
45+
end
46+
end
47+
end
48+
end
49+
end
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# -*- coding: binary -*-
2+
3+
module Msf
4+
class Exploit
5+
class Remote
6+
module Kerberos
7+
module Client
8+
module Base
9+
10+
# Builds a kerberos Client Name Principal
11+
#
12+
# @param opts [Hash{Symbol => <String, Fixnum>}]
13+
# @option opts [String] :client_name the client's name
14+
# @option opts [Fixnum] :client_type the client's name type
15+
# @return [Rex::Proto::Kerberos::Model::PrincipalName]
16+
# @see Rex::Proto::Kerberos::Model::PrincipalName
17+
def build_client_name(opts = {})
18+
name = opts[:client_name] || ''
19+
name_type = opts[:client_type] || Rex::Proto::Kerberos::Model::NT_PRINCIPAL
20+
21+
Rex::Proto::Kerberos::Model::PrincipalName.new(
22+
name_type: name_type,
23+
name_string: name.split('/')
24+
)
25+
end
26+
27+
# Builds a kerberos Server Name Principal
28+
#
29+
# @param opts [Hash{Symbol => <String, Fixnum>}]
30+
# @option opts [String] :server_name the server's name
31+
# @option opts [Fixnum] :server_type the server's name type
32+
# @return [Rex::Proto::Kerberos::Model::PrincipalName]
33+
# @see Rex::Proto::Kerberos::Model::PrincipalName
34+
def build_server_name(opts = {})
35+
name = opts[:server_name] || ''
36+
name_type = opts[:server_type] || Rex::Proto::Kerberos::Model::NT_PRINCIPAL
37+
38+
Rex::Proto::Kerberos::Model::PrincipalName.new(
39+
name_type: name_type,
40+
name_string: name.split('/')
41+
)
42+
end
43+
end
44+
end
45+
end
46+
end
47+
end
48+
end

0 commit comments

Comments
 (0)