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

Closed
magnumripper opened this issue Oct 4, 2017 · 33 comments · Fixed by #5314
Closed

Support for Kerberos TGS etype 17/18 #2809

magnumripper opened this issue Oct 4, 2017 · 33 comments · Fixed by #5314
Assignees

Comments

@magnumripper
Copy link
Member

hashcat/hashcat#1384

@kholia
Copy link
Member

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 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.

@ihamburglar
Copy link

@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 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 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

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 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

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 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 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.

@ihamburglar
Copy link

@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 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 kholia added the RFC / discussion Help or comments wanted label Dec 26, 2017
@kholia
Copy link
Member

kholia commented Feb 28, 2018

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

@HarmJ0y
Copy link

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 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

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 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 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 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 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 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 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

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: fortra/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 commented Mar 14, 2019

Go for it @Fist0urs 👍

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

@nowhey2
Copy link

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

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

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

@kholia
Copy link
Member

kholia commented Oct 27, 2021

It seems that hashcat's 19700 module is broken and doesn't actually crack real hashes.

Sample hash: hashes.txt

Password is test@123.

Pcap for the same setup: W2019DC-hello-test@123-TGS-REP.pcapng.txt - hash may be different due to a different impacket "session".

$ ../run/john --test --format=krb5tgs_modern   
Will run 16 OpenMP threads
Benchmarking: krb5tgs_modern, Kerberos 5 TGS etype 17/18 [PBKDF2-HMAC-SHA1 + AES]... (16xOMP) DONE
Warning: "Many salts" test limited: 8/256
Many salts:	16062 c/s real, 1041 c/s virtual
Only one salt:	15906 c/s real, 1040 c/s virtual
$ ../run/john ~/hashes.txt -w=wordlist
Using default input encoding: UTF-8
Loaded 1 password hash (krb5tgs_modern, Kerberos 5 TGS etype 17/18 [PBKDF2-HMAC-SHA1 + AES])
Will run 16 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
Warning: Only 9 candidates left, minimum 16 needed for performance.
test@123         (?)     
1g 0:00:00:00 DONE (2021-10-27 17:25) 100.0g/s 900.0p/s 900.0c/s 900.0C/s openwall@123..test@123
Use the "--show" option to display all of the cracked passwords reliably
Session completed. 

Related: https://twitter.com/hashcat/status/1105909927825104896.

@solardiz
Copy link
Member

It seems that hashcat's 19700 module is broken and doesn't actually crack real hashes.

@kholia Perhaps you should open an issue in @hashcat GitHub, then? I guess @Fist0urs already saw your comment here and will check, though.

@kholia
Copy link
Member

kholia commented Oct 27, 2021

CC @Fist0urs and @jsteube - Context is #2809 (comment).

@PracaGrande
Copy link

PracaGrande commented Mar 3, 2022

Hello,
Is the code for this format already available on Bleeding-Jumbo?
I'm asking because I don't see the --format=krb5tgs_modern and if I try the test hash sample that @kholia with --format=krb5-18 it doesn't recognize it.
thanks

$ ./john John the Ripper 1.9.0-jumbo-1+bleeding-75667e2 2022-02-22 13:29:07 +0100 OMP [linux-gnu 64-bit x86_64 AVX2 AC]

$ ./john --format=krb
krb4 krb5-17 krb5-3 krb5asrep-aes-opencl krb5pa-md5-opencl krb5pa-sha1-opencl krb5 krb5-18 krb5asrep krb5pa-md5 krb5pa-sha1 krb5tgs

@magnumripper
Copy link
Member Author

Looks like @kholia had a working format but never created a PR, and now that branch is gone in his repo 😢

@PracaGrande
Copy link

Damm, was felling luck I could try cracking some Kerberos tickets with John ...

Meanwhile, I also have the following hash format Kerberos 5 TGS etype 18 with a 32 bits checksum instead of 24 like the sample from @kholia . This was captured from a Windows 2016 Server using Invoke-Kerberoast.ps1 from @HarmJ0y ... I know its not related to JtR but wondering if anyone in this thread knows if this is a different format? (also unable to load it into hashcat)

$krb5tgs$18$user$realm$*spn*$DA56E256167275EA6D4FE490C554976E$CBF774183730E46CFFD08D6695F428ADDA06AF2B4EFAC951180CA0A333712988A760634414F8D5A6EF9D2A2C1C999CC1FF5DB21004E0763A1B0BD9F3435AB6FF71E9CCF53708579B33B11955C5A1CB7625A65DE1D3D04E69D80B99A6DE0ACE593CD2FEF9B6F1212E490637F765F83539629C3C8D3544B68B313D321DB4A7C2AF2928A17AE8F44CF2F5A7AFFEAC477803E858CA7D72E757A194397206F700DAFAFAFA2B49BB7B2CADFEE9756E1B06DD3435EEAC46E2A02D316D57BE9460E92ED9E7FCCC8654094216131EECAA73E702C4DFDAF3CD77AB13C2B201905628FF9FB526AE38238E1D0CDA5FE26F6FC38DEBB41A7038E233F57F6DDBE19271E71DE1789309E9EAA615FB3B008CA0BB3DB560922318BA270F2CA406A0A3127A71380467DE3898FF952A0C18DC009A438C1C0761CCB0E8CA53320C7633D529542ABBB330D370258C89F11B8B2F907FA0D801E937F5714489BE1F55C7E4625BCB6E3B73F056B8EE2A0465FA541FA6AD2F991E8965451FCFB56FEF95538EE9C28AA593FCD85F2600514DAE8A138E950C346F88BFD89823E5FF548C0C2133D7B3D6F231FD770467BD2C9AAB88B990DC296F9B6AD8315E0A0124495787D998DABDFE79DE6CF7F022C4C944988A590E5A955E9D1BFF9011B82CC12EC77501A60E943D7B9D97D2E0E9A7292ABDDAB1FC070969BE9FB81B4293038445F563592539B313F7EBF1113E95B0BBBE5A3CA2669CA00335DB16CC4EC1AAE8BB5993967666D2B394C571C5AAC0DB7E3860859F2B028E6AD346CA2D6EAD1B9452EB2E110FBF3131FB9410BA0853AB97855E89E7EBDDDA2003058D82761A46B17B0C4241A025E5A9AA7E2AC6396BFDA64DD0BF8EF2C1FF8EEAD9DE6010DD114DDDB911F8D603869D51B2FB17A125E47EF7FD1684F9358BD88ADE05B39A263ED63721DEB6EE2CED00C37CD8FDC96177AE1F0467C79F09CC1D8DACA2B6626F459FE5EE94E2E8C0E7ADC62A1E1D6A3B32337396102ED5D1BBEE5EE9AD2BDFC3BFEAAE6DFB8C7ED5C6FF931B6FFF10C1E36853832F0D8CFB6D68BCDC915F36DCEC8B75B0E1373D374D76608BF329B7ACA15600F2E760285D63B948AE0AE4A3C690A0FC7D3A3C90FDEC7D031F91FD3DFE56AE7AEA3C5471E47BC08F94FA1179598B9C36E706125CB9DB1E082160649AB47B07FB035E5366F36F5E42EE7E1EBC70F3EB55324B5A91DC7686C93334DEE482BD57DCE73E47589E767358398C1A78270D11ECDBDB954E7F6D684904631F2C649B11FB8FBFC9B687A0076D3A326AAD7251CC49A1AA437F0D903A6830DE82568FE7AB3FE688139F128488FB269B72BF37B63587325D68016DBFAF6904B3676031403B7A45B33229D27A00AD36BEAC798DEA9C1A62EFE4A2638E285D8FE66935C8D2EF4E68BFD5B472D724A6D79D85EC68F2C359C8B5D5B81C19CC2CEF934AD332820A00D3F44128AD7F074631E243BA65025D7EA34265F38C550C0DA07EB88694FBB5A7318E98AF1C2AD1FA4A9F81C9350D4B9BF216DC0CC50CCF3EABECA5618643FF90E01A23CF99FE82643232C7E255E396780BE85570A9688754EEE9AD036CAB9B070D91B3680817B08AC9B88404EBC91827CBB16EC3A475A7F01061D73D0496E834F8493CAC44F3AC87EAC4B5C53D193A938E14A5A91C5D20CF3CF0AE5B2D620F739D54F62A23EA112F2ED449864D67A3AE2A7620241A0CFB6FF3A291366514C3EC620FDBAC6CF9F33249EF5B20

magnumripper added a commit to magnumripper/john that referenced this issue May 16, 2023
Also known as aes-cts-hmac-sha1-96.  The existing krb5tgs formats are for
etype 23 (rc4-hmac) and too different from 17/18 that it would be relevant
to add this functionality to them.

Also add "cost" notion of etype for a few existing formats, and changed
their benchmark to etype 17 instead of some unknown mix of etypes.

Closes openwall#2809
magnumripper added a commit that referenced this issue May 16, 2023
Also known as aes-cts-hmac-sha1-96.  The existing krb5tgs formats are for
etype 23 (rc4-hmac) and too different from 17/18 that it would be relevant
to add this functionality to them.

Also add "cost" notion of etype for a few existing formats, and changed
their benchmark to etype 17 instead of some unknown mix of etypes.

Closes #2809
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants