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

Support for Kerberos TGS etype 17/18 #2809

Open
magnumripper opened this issue Oct 4, 2017 · 27 comments
Open

Support for Kerberos TGS etype 17/18 #2809

magnumripper opened this issue Oct 4, 2017 · 27 comments

Comments

@magnumripper
Copy link
Member

@magnumripper magnumripper commented Oct 4, 2017

hashcat/hashcat#1384

@kholia
Copy link
Member

@kholia kholia commented Oct 21, 2017

I haven't seen any proof (or proof-of-concept) that doing this is possible.

Also see my comments in PR #2822.

@kholia
Copy link
Member

@kholia kholia commented Oct 21, 2017

@elitest Do you have any proof (or proof-of-concept) that Kerberoasting of TGS-REP messages which use etype 17 and 18 is technically possible? Have you considered the possibility that it might not be possible to crack such TGS-REP messages at all? Also see my comments in PR #2822. In particular, note that I could only conduct Kerberoasting attacks against MS Active Directory and not against krb5 software.

@elitest
Copy link

@elitest elitest commented Oct 22, 2017

@kholia Great question. So it is possible to to generate the hashes against correctly configured accounts. To configure service accounts correctly set msDS-SupportedEncryptionTypes to 24 in the LDAP attributes of the account as discussed here. This is actually the way that AD administrators should be configuring accounts if they want the TGS-REPs encrypted more securely with AES. Once you have that setup you kerberoast the SPN that that account is registered with. Both GetUserSPNs.py and Invoke-Kerberoast now support generating and understanding AES hashes. See our talk at DerbyCon 7 for maximum detail. We are confident that we have implemented the hashes correctly as we used packet captures of the TGS-REPs on these AES accounts to validate that we were grabbing the correct data.

As to whether or not the hashes will crack. I don't have any PoC that cracks an AES kerberos ticket, however my understanding of the RFCs and MS-KILE lead me to believe that the TGS-REP is encrypted with the RC4 hash(NTLM in the case of AD) the same way that AES does with the respective keys(AES128 and AES256).

One other issue specific to john, is that I believe john's TGS hash format will need to be modified or something as it doesn't specify which type of crypto is used, whereas hashcat's format does.

Let me know if you have any other further questions or if I can help in any way.

@kholia
Copy link
Member

@kholia kholia commented Oct 23, 2017

One other issue specific to john, is that I believe john's TGS hash format will need to be modified or something as it doesn't specify which type of crypto is used, whereas hashcat's format does.

This particular problem is easy to solve.

@kholia
Copy link
Member

@kholia kholia commented Oct 27, 2017

Maybe @gentilkiwi, @PyroTek3, @Fist0urs, and @HarmJ0y have something to say on this topic (i.e. Kerberoasting of etype 17 and 18 "hashes" instead of etype 23).

It seems that solving this problem will require some amount of reversing / low-level debugging of Kerberos functionality on Windows platform.

@gentilkiwi
Copy link

@gentilkiwi gentilkiwi commented Oct 28, 2017

Low Level Debug ? If I remember well, type 17 or 18 are standards.
I made a little ugly C POC around it to get key from password: https://gist.github.com/gentilkiwi/612588b1d4d3a3039fa83802f0053290

@kholia
Copy link
Member

@kholia kholia commented Oct 28, 2017

@gentilkiwi Thanks for taking a look at this stuff! 👍

I have the AES key derivation part working as well [1]. The parts that I am missing are (1) how is this AES key used to decrypt the encrypted ticket data from TGS-REP message (2) how does the client verify that the decrypted data is correct (there is SHA1 checksum involved but I am missing the exact details). These details will make the Kerberoasting of etype 17/18 TGS-REP messages possible.

We need to figure out the HMAC key derivation part (which is involved in the SHA1 checksum calculation). This will also involve figuring out the correct value of usage[3]. I am assuming that this stuff is very similar to the code we have in krb5_asrep_fmt_plug.c file. I could be wrong though.

[1] https://github.com/kholia/JohnTheRipper/tree/TGS-ng (see crypt_all from the top commit, filename is krb5_tgs_fmt_plug.c).

@gentilkiwi
Copy link

@gentilkiwi gentilkiwi commented Oct 28, 2017

Did you take a look in: https://www.ietf.org/rfc/rfc3962.txt ?
As for RC4, the best way to check is to detect ASN1 header in first 16 bytes.

@kholia
Copy link
Member

@kholia kholia commented Oct 29, 2017

Did you take a look in: https://www.ietf.org/rfc/rfc3962.txt?

Yes, we have already implemented this entire RFC in the krb5pa-sha1_fmt_plug.c and krb5_asrep_fmt_plug.c files. These plugins crack the various AS-REP messages which are using etype 17/18 just fine. We are just missing support for cracking TGS-REP messages which are using etype 17/18.

As for RC4, the best way to check is to detect ASN1 header in first 16 bytes.

Yes, @Fist0urs implemented this technique in krb5_tgs_fmt_plug.c file.

@kholia
Copy link
Member

@kholia kholia commented Oct 31, 2017

Here are some rough ideas on how further progress can be made. Please note that I am not sure if this approach is even correct.

I suspect that Kerberos functionality is provided by lsasrv.dll on Windows. WinDbg can be attached to the LSASS process, and various functions present in lsasrv.dll can be traced. In particular, tracing of input + output data from LspRC4EncryptData, LspAES256EncryptData, rijndaelEncrypt128, rijndaelEncrypt256, LspAES256DecryptData and related functions needs to be done. Tracing LspRC4EncryptData will act as a verifier for this approach. We should see the NT hash coming in as the RC4 key while tracing the LspRC4EncryptData function. After that, I would like to see the actual AES key being used to encrypt the TGS stuff. The output of AES encryption needs to be compared to the data in the TGS-REP packet we see on the wire.

The runas /user:EXAMPLE\user "cmd" command can be used along with "Request Ticket(s)" method from https://github.com/nidem/kerberoast to trigger the invocation of the desired functions.

https://blogs.msdn.microsoft.com/spatdsg/2005/12/27/debugging-lsass-oh-what-fun-it-is-to-ride/ should be useful here.

For function tracing, ideas from https://labs.mwrinfosecurity.com/blog/heap-tracing-with-windbg-and-python/ can be used.

@elitest
Copy link

@elitest elitest commented Nov 2, 2017

@kholia What would happen if we just decrypted a bunch of TGS-REPs... shouldn't we get something formatted as ASN1 if the decryption worked?

@kholia
Copy link
Member

@kholia kholia commented Nov 3, 2017

@elitest Yes, that is correct.

https://adsecurity.org/?p=2293 says, "The TGS is encrypted using the target service accounts’ NTLM password hash and sent to the user (TGS-REP)". This is what makes Kerberoasting attacks possible. The code in krb5_tgs_fmt_plug.c decrypts the encrypted TGS, and checks that that decrypted data looks like valid ASN.1 data. So far, so good.

In case of etype 17/18, I have the AES key derivation part working. This matches the aes256_hmac data shown my mimikatz, and it also matches the output of echidna. However when I decrypt the encrypted TGS (which is using etype 17/18) with this AES key, I don't get valid ASN.1 data as the output. This makes me suspect that either (1) my code is broken (quite possible) (2) Kerberoasting of TGS-REP messages in case of etype 17/18 is not possible (MS fixed their implementation specific bugs) (3) we are missing some important "algorithm" details, which will require more reversing + debugging on Windows.

Current code -> https://github.com/kholia/JohnTheRipper/tree/TGS-ng (see crypt_all from the top commit, filename is krb5_tgs_fmt_plug.c)

@kholia kholia self-assigned this Nov 6, 2017
@kholia
Copy link
Member

@kholia kholia commented Feb 28, 2018

So far no one has been able to prove that this task/technique is possible.

@HarmJ0y
Copy link

@HarmJ0y HarmJ0y commented Feb 15, 2019

@kholia this is something I want to see if we can revisit - the code you at the Current code -> https://github.com/kholia/JohnTheRipper/tree/TGS-ng (see crypt_all from the top commit, filename is krb5_tgs_fmt_plug.c) comment - was that preserved at any point?

@kholia
Copy link
Member

@kholia kholia commented Feb 15, 2019

Thanks for looking into this stuff @HarmJ0y 👍

https://github.com/kholia/JohnTheRipper/tree/TGS-ng

I have restored this branch now (I don't know how/why it was gone earlier).

@Fist0urs
Copy link
Contributor

@Fist0urs Fist0urs commented Feb 17, 2019

Hi guys,

I've been discussing with @skelsec at offensivecon. I planned to reverse stuff to implement it (as I did for the RC4 part) but he told me that he already made a script that implements the algorithm. I guess he can share it here so that it will be implemented? As @kholia has already started the jtr part maybe I could stick to the hashcat part? So that we'll have it both jtr and hashcat implementations 👍

Cheers!

@kholia
Copy link
Member

@kholia kholia commented Feb 18, 2019

Sharing the code here would be great.

Thanks @Fist0urs and @skelsec for this great news.

@kholia kholia reopened this Feb 18, 2019
@skelsec
Copy link

@skelsec skelsec commented Feb 21, 2019

I put together a poc script alongside with some test cases of TGS ticket decryption for etype17/18.
it runs on python3 (tested with 3.7). Paths are windows paths for the test-case files, so you may need to modfy them.
The logging is turned to debug, it shows most functions input-output parameters if you wish to cross-check it with your code.
Test cases ran by tgs_dec_poc.py
In the meantime I found a tgs ticket in your sourcecode, so I made another file decrypting just that one tgs_dec.py
Hope it helps.

Note: most of the encryption-decryption part was originally coming from impacket, I just ported it to py3 and dissected the AES it into a single file and added some comments.

kerb_poc.zip

@Fist0urs
Copy link
Contributor

@Fist0urs Fist0urs commented Mar 2, 2019

@kholia, the input hash formats accepted for the 23 enctype are as follows:

https://github.com/magnumripper/JohnTheRipper/blob/111527672ad0740e330eacf1be8bff23e2f92fa3/src/krb5_tgs_fmt_plug.c#L61-L67

Unfortunately 17/18 require the user + realm in order to create a salt, so we must include them in the input hash.

I suggest to adopt these input formats:

$krb5tgs$17$*user*realm*$checksum$edata2
$krb5tgs$17$*user*realm*spn*$checksum$edata2

Are you okay with that?

@kholia
Copy link
Member

@kholia kholia commented Mar 2, 2019

@Fist0urs Sure. It would be nice to update the associated helpers tools (like run/krb2john.py?), if required. This can happen in a different, future PR (if required).

Thanks for handling this 👍

Update: Hopefully, I will be back in action in some weeks :)

@Fist0urs
Copy link
Contributor

@Fist0urs Fist0urs commented Mar 2, 2019

I'll update the associated helpers tools yes!
Actually I was thinking about removing my tool "kerberom" from the repo as it is pretty deprecated. Now impacket does the job really better (and implements the 17/18 stuff) so this would be a better option imho. If you are ok with this removal, I'll create a KerberosTGS HOWTO in the docs that explain how things work.

Take your time for the code, I'll have to dive into hashcat code first to remember it so this is not urgent 😄

@kholia
Copy link
Member

@kholia kholia commented Mar 2, 2019

Actually I was thinking about removing my tool "kerberom" from the repo as it is pretty deprecated.

Sure. Please go for it. Create a small PR and I will review it asap.

I'll create a KerberosTGS HOWTO in the docs that explain how things work.

This would be awesome, thanks! I don't remember most of this Kerberos stuff these days!

@Fist0urs
Copy link
Contributor

@Fist0urs Fist0urs commented Mar 14, 2019

Ok, I've implemented it in hashcat (hashcat/hashcat#1955)

Next step is implementing here.

Regarding the input format I adopted this:

$krb5tgs$17$user$realm$checksum$edata2
$krb5tgs$17$user$realm$*spn*$checksum$edata2

$krb5tgs$18$user$realm$checksum$edata2
$krb5tgs$18$user$realm$*spn*$checksum$edata2

I enclosed user and realm within '$' and spn within '*' as user and realm are mandatory and spn is optionnal (not taken into account while computing the hash). PR to adapt the hash format (+ correction) was accepted in impacket: SecureAuthCorp/impacket#584

I'll also commit a "HOWTO" regarding Kerberos in jtr.

I tried to comment a lot the hashcat code so that it would be easier to implement these hash formats within john, if I'm not the one who implements it.

@kholia
Copy link
Member

@kholia kholia commented Mar 14, 2019

Go for it @Fist0urs 👍

It might be a while before I am back in action.

@nowhey2
Copy link

@nowhey2 nowhey2 commented Dec 17, 2019

Any chance this could get a bump? Ran into this exact thing and see that hashcat now supports 19700.

@solardiz
Copy link
Member

@solardiz solardiz commented Dec 17, 2019

I've just added this to a milestone, but I didn't look into the actual issue and I expect that only @Fist0urs might contribute anything in this area soon.

@Fist0urs
Copy link
Contributor

@Fist0urs Fist0urs commented Dec 18, 2019

Hi there! Sorry I've been really busy lately... I'll try to take a look in the upcoming month :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
9 participants