@@ -157,8 +157,9 @@ def initialize(
157157 credential = nil
158158 if cache_file . present?
159159 # the cache file is only used for loading credentials, it is *not* written to
160- credential = load_credential_from_file ( cache_file , sname : nil , sname_hostname : @hostname )
161- serviceclass = build_spn . name_string . first
160+ load_sname_hostname_credential_result = load_credential_from_file ( cache_file , sname : nil , sname_hostname : @hostname )
161+ credential = load_sname_hostname_credential_result [ :credential ]
162+ serviceclass = build_spn &.name_string &.first
162163 if credential && credential . server . components [ 0 ] != serviceclass
163164 old_sname = credential . server . components . snapshot . join ( '/' )
164165 credential . server . components [ 0 ] = serviceclass
@@ -168,9 +169,18 @@ def initialize(
168169 ticket . sname . name_string [ 0 ] = serviceclass
169170 credential . ticket = ticket . encode
170171 elsif credential . nil? && hostname . present?
171- credential = load_credential_from_file ( cache_file , sname : "krbtgt/#{ hostname . split ( '.' , 2 ) . last } " )
172+ load_sname_krbtgt_hostname_credential_result = load_credential_from_file ( cache_file , sname : "krbtgt/#{ hostname . split ( '.' , 2 ) . last } " )
173+ credential = load_sname_krbtgt_hostname_credential_result [ :credential ]
172174 end
173175 if credential . nil?
176+ print_error ( "Failed to load a usable credential from ticket file: #{ cache_file } " )
177+ print_error ( "Attempt failed to find a valid credential in #{ cache_file } for #{ load_sname_hostname_credential_result [ :filter ] . map { |k , v | "#{ k } =#{ v . inspect } " } . join ( ', ' ) } :" )
178+ print_error ( load_sname_hostname_credential_result [ :filter_reasons ] . join ( "\n " ) . indent ( 2 ) )
179+
180+ if load_sname_krbtgt_hostname_credential_result
181+ print_error ( "Attempt failed to find a valid credential in #{ cache_file } for #{ load_sname_krbtgt_hostname_credential_result [ :filter ] . map { |k , v | "#{ k } =#{ v . inspect } " } . join ( ', ' ) } " )
182+ print_error ( load_sname_krbtgt_hostname_credential_result [ :filter_reasons ] . join ( "\n " ) . indent ( 2 ) )
183+ end
174184 raise ::Rex ::Proto ::Kerberos ::Model ::Error ::KerberosError . new ( "Failed to load a usable credential from ticket file: #{ cache_file } " )
175185 end
176186 print_status ( "Loaded a credential from ticket file: #{ cache_file } " )
@@ -362,7 +372,7 @@ def build_spn(options = {})
362372 # @return [Rex::Proto::Kerberos::CredentialCache::Krb5CcacheCredential] The ccache credential
363373 def request_tgt_only ( options = { } )
364374 if options [ :cache_file ]
365- credential = load_credential_from_file ( options [ :cache_file ] )
375+ credential = load_credential_from_file ( options [ :cache_file ] ) &. fetch ( :credential , nil )
366376 else
367377 credential = get_cached_credential (
368378 options . merge (
@@ -1058,64 +1068,72 @@ def get_cached_credential(options = {})
10581068 # Load a credential object from a file for authentication. Credentials in the file will be filtered by multiple
10591069 # attributes including their timestamps to ensure that the returned credential appears usable.
10601070 #
1061- # @param [String] file_path The file path to load a credential object from
1062- # @return [Rex::Proto::Kerberos::CredentialCache::Krb5CacheCredential] the credential object for authentication
1063- def load_credential_from_file ( file_path , options = { } )
1064- unless File . readable? ( file_path . to_s )
1065- wlog ( "Failed to load ticket file ' #{ file_path } ' (file not readable)" )
1071+ # @param [String] path The path to load a credential object from
1072+ # @return [Hash] :credential [ Rex::Proto::Kerberos::CredentialCache::Krb5CacheCredential] the credential object for authentication
1073+ # @return [Hash] :filter_reasons [Array<String>] the reasons for filtering tickets
1074+ def load_credential_from_file ( path , options = { } )
1075+ unless File . readable? ( path . to_s )
10661076 return nil
10671077 end
10681078
10691079 begin
1070- cache = Rex ::Proto ::Kerberos ::CredentialCache ::Krb5Ccache . read ( File . binread ( file_path ) )
1080+ cache = Rex ::Proto ::Kerberos ::CredentialCache ::Krb5Ccache . read ( File . binread ( path ) )
10711081 rescue StandardError => e
1072- elog ( "Failed to load ticket file '#{ file_path } ' (parsing failed)" , error : e )
1082+ elog ( "Failed to load ticket file '#{ path } ' (parsing failed)" , error : e )
10731083 return nil
10741084 end
10751085
10761086 sname = options . fetch ( :sname ) { build_spn &.to_s }
10771087 sname_hostname = options . fetch ( :sname_hostname , nil )
10781088 now = Time . now . utc
10791089
1090+ filter = {
1091+ realm : @realm ,
1092+ sname : sname ,
1093+ sname_hostname : sname_hostname
1094+ } . merge ( options )
1095+ filter_reasons = [ ]
1096+
10801097 cache . credentials . to_ary . each . with_index ( 1 ) do |credential , index |
10811098 tkt_start = credential . starttime == Time . at ( 0 ) . utc ? credential . authtime : credential . starttime
10821099 tkt_end = credential . endtime
1100+ filter_reason_prefix = "Filtered credential #{ path } ##{ index } reason: "
10831101
10841102 unless tkt_start < now
1085- wlog ( "Filtered credential #{ file_path } # #{ index } reason: Ticket start time is before now (start: #{ tkt_start } )")
1103+ filter_reasons << " #{ filter_reason_prefix } Ticket start time is before now (start: #{ tkt_start } )"
10861104 next
10871105 end
10881106
10891107 unless now < tkt_end
1090- wlog ( "Filtered credential #{ file_path } # #{ index } reason: Ticket is expired (expiration: #{ tkt_end } )")
1108+ filter_reasons << " #{ filter_reason_prefix } Ticket is expired (expiration: #{ tkt_end } )"
10911109 next
10921110 end
10931111
10941112 unless !@realm || @realm . casecmp? ( credential . server . realm . to_s )
1095- wlog ( "Filtered credential #{ file_path } # #{ index } reason: Realm (#{ @realm } ) does not match (realm: #{ credential . server . realm } )")
1113+ filter_reasons << " #{ filter_reason_prefix } Realm (#{ @realm } ) does not match (realm: #{ credential . server . realm } )"
10961114 next
10971115 end
10981116
10991117 unless !sname || sname . to_s . casecmp? ( credential . server . components . snapshot . join ( '/' ) )
1100- wlog ( "Filtered credential #{ file_path } # #{ index } reason: SPN (#{ sname } ) does not match (spn: #{ credential . server . components . snapshot . join ( '/' ) } )")
1118+ filter_reasons << " #{ filter_reason_prefix } SPN (#{ sname } ) does not match (spn: #{ credential . server . components . snapshot . join ( '/' ) } )"
11011119 next
11021120 end
11031121
11041122 unless !sname_hostname ||
1105- sname_hostname . to_s . downcase == credential . server . components [ 1 ] . downcase ||
1106- sname_hostname . to_s . downcase . ends_with? ( '.' + credential . server . components [ 1 ] . downcase )
1107- wlog ( "Filtered credential #{ file_path } # #{ index } reason: SPN (#{ sname_hostname } ) hostname does not match (spn: #{ credential . server . components . snapshot . join ( '/' ) } )")
1123+ sname_hostname . to_s . downcase == credential . server . components [ 1 ] . downcase ||
1124+ sname_hostname . to_s . downcase . ends_with? ( '.' + credential . server . components [ 1 ] . downcase )
1125+ filter_reasons << " #{ filter_reason_prefix } SPN (#{ sname_hostname } ) hostname does not match (spn: #{ credential . server . components . snapshot . join ( '/' ) } )"
11081126 next
11091127 end
11101128
11111129 unless !@username || @username . casecmp? ( credential . client . components . last . to_s )
1112- wlog ( "Filtered credential #{ file_path } ##{ index } reason: Username (#{ @username } ) does not match (username: #{ credential . client . components . last } )" )
1130+ filter_reasons << "Filtered credential #{ path } ##{ index } reason: Username (#{ @username } ) does not match (username: #{ credential . client . components . last } )"
11131131 next
11141132 end
11151133
1116- return credential
1134+ return { credential : credential , filter : filter , filter_reasons : filter_reasons }
11171135 end
11181136
1119- nil
1137+ { credential : nil , filter : filter , filter_reasons : filter_reasons }
11201138 end
11211139end
0 commit comments