Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[describeTicket.py] New example script: ticket describer and decrypter #1201

Merged
merged 37 commits into from
Oct 4, 2023

Conversation

ShutdownRepo
Copy link
Contributor

This new example script takes a .ccache file as input and parses it.

  • For each credential found in the file (usually 1), the content of the ticket is parsed and printed.
  • If the appropriate credentials are supplied, the encrypted-part of the ticket (i.e. PAC) will be decrypted and printed as well.
  • If the appropriate credentials are supplied, the PAC Credentials structure contained in the PAC will be decrypted and printed as well.

The appropriate credentials for PAC decryption refer to the credentials of the service account who owns the SPN the ticket was issued for (krbtgt for TGTs, service accounts for service tickets). The following information can be supplied to describeTicket

  • salt and password: -s/--salt and -hp/--hex-pass
  • salt and hex password: -s/--salt and -hp/--hex-pass
  • domain and username and password: -d/--domain and -u/--user and -hp/--hex-pass
  • domain and username and hex password: -d/--domain and -u/--user and -hp/--hex-pass
  • Kerberos keys: --rc4 and --aes

The appropriate credentials for PAC Credentials decryption refer to the AS-REP key sent by KDC when obtaining a TGT. After a PKINIT pre-authentication, that structure will contain the LM and NT hashes of the user who asked for the TGT. This key can be supplied with the --asrep-key argument.

The following screenshot shows the usage.

Screenshot from 2021-11-01 16-18-50

The following screenshot shows a TGT being parsed, the PAC being decrypted and parsed.

Screenshot from 2021-11-01 15-30-07

If the proper key is not supplied, here's what's shown.

Screenshot from 2021-11-01 15-32-15

Here is an example with a Service Ticket. The kerberoast hash is printed for the service account, owner of the SPN the ticket was issued for.

Screenshot from 2021-11-01 15-41-26

Nota-bene: there is an ugly code right now that I'll probably refactor but it doesn't prevent the script from working at the moment. A number of spaces is hardcoded in the parsed PAC Credentials in order to print information in a pretty manner. This could be done in a better way honestly.

                parsed_credential_data['  Credential Count'] = credential_data['CredentialCount']
                parsed_tuPAC.append({"  Credential Data": parsed_credential_data})
                # Parsing (one or many) 2.6.3 SECPKG_SUPPLEMENTAL_CRED
                for credential in credential_data['Credentials']:
                    parsed_secpkg_supplemental_cred = {}
                    parsed_secpkg_supplemental_cred['      Package Name'] = credential['PackageName']
                    parsed_secpkg_supplemental_cred['      Credential Size'] = credential['CredentialSize']
                    parsed_tuPAC.append({"      SecPkg Credentials": parsed_secpkg_supplemental_cred})
                    # Parsing 2.6.4 NTLM_SUPPLEMENTAL_CREDENTIAL
                    ntlm_supplemental_cred = pac.NTLM_SUPPLEMENTAL_CREDENTIAL(b''.join(credential['Credentials']))
                    parsed_ntlm_supplemental_cred = {}
                    parsed_ntlm_supplemental_cred['        Version'] = ntlm_supplemental_cred['Version']
                    parsed_ntlm_supplemental_cred['        Flags'] = ntlm_supplemental_cred['Flags']
                    parsed_ntlm_supplemental_cred['        LmPasword'] = hexlify(ntlm_supplemental_cred['LmPassword']).decode('utf-8')
                    parsed_ntlm_supplemental_cred['        NtPasword'] = hexlify(ntlm_supplemental_cred['NtPassword']).decode('utf-8')
                    parsed_tuPAC.append({"        NTLM Credentials": parsed_ntlm_supplemental_cred})

@ShutdownRepo
Copy link
Contributor Author

The script can now decrypt the encoded ticket in the credential object. This allows to detect any potential discrepancy between the sname/realm in the credential vs. in the ticket

image

@0xdeaddood 0xdeaddood added in review This issue or pull request is being analyzed low Low priority item labels Feb 23, 2023
@ShutdownRepo ShutdownRepo changed the title New example script: ticket describer and decrypter [describeTicket.py] New example script: ticket describer and decrypter Aug 23, 2023
@anadrianmanrique anadrianmanrique added medium Medium priority item and removed low Low priority item labels Sep 7, 2023
@ShutdownRepo
Copy link
Contributor Author

@0xdeaddood any news here?

@anadrianmanrique anadrianmanrique self-assigned this Sep 14, 2023
@anadrianmanrique
Copy link
Contributor

As for the time being, the PR should be rebased due to pac.py being in conflict. Maybe changes in this file are no longer necessary as PAC_ATTRIBUTE_INFO and PAC_REQUESTOR were integrated in the context of #1545.
Once we have that I'll begin to test it. This one looks like a good candidate to integrate as a new example.
Once again, thanks for the great work :)

@ShutdownRepo
Copy link
Contributor Author

Done ✅

@anadrianmanrique anadrianmanrique merged commit 57a3e09 into fortra:master Oct 4, 2023
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in review This issue or pull request is being analyzed medium Medium priority item
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants