How to Detect Pass-the-Ticket Attacks

How to Detect Pass-the-Ticket Attacks

In our first post of the series, we looked at some interesting ways to detect the pass-the-hash attack. Pass-the-hash is an effective approach for exploiting NTLM authentication within an Active Directory domain. Pass-the-ticket is an alternate approach which leverages Kerberos authentication to perform lateral movement. 

In this post we will dive into how this attack works and what you can do to detect it.

How Pass-the-Ticket Works

In a pass-the-ticket attack, an attacker is able to extract a Kerberos Ticket Granting Ticket (TGT) from LSASS memory on a system and then use this on another system to request Kerberos service tickets (TGS) to gain access to network resources. 

One primary difference between pass-the-hash and pass-the-ticket, is that Kerberos TGT tickets expire (10 hours by default) whereas NTLM hashes only change when the user changes their password. So a TGT ticket must be used within its lifetime, or it can be renewed for a longer period of time (7 days).  

Tools like Mimikatz can be used to perform this attack, but in this post, I wanted to show another security tool Rubeus. Rubeus is a C# toolset written by harmj0y that lets you perform Kerberos based attacks and is based on the Kekeo project by Benjamin Delpy, the author of Mimikatz.

Let’s see a pass-the-ticket attack in action…

Extracting the TGT

To perform a pass-the-ticket attack with Rubeus the first step is to obtain a TGT.  TGTs and NTLM hashes may or may not be stored on a system after a user logs off based on security settings. One of the fun/scary features of Rubeus is a feature called “monitor” which will look for 4624 logon events and dump the TGT data for any new logon sessions on a system. 

If I use this command Rubeus will start monitoring for logon sessions every 30 seconds:

Rubeus.exe monitor /interval:30

Now, if anybody logs onto this system I will obtain their TGT.  To simulate that, I will just run a command as a user.

Runas /user:[domain\username] cmd.exe

Within 30 seconds, Rubeus will detect this logon and obtain the TGT for this user, and output it as a base64 encoded string.

You can then copy this into a text editor like Sublime Text and use regular expression to remove line breaks and spaces (‘\n      ‘).

Passing the Ticket

Now that we have the ticket, let’s use it before it expires!  To use this we will stick with Rubeus but this time use the ptt command

Rubeus.exe ptt /ticket:[Base64 string goes here]

You can see I have a TGT for the compromised user loaded into my session, and I can now use this to request TGS service tickets to access network resources as this user.  Success!

With that, let’s talk about what you can do to detect pass-the-ticket in your environment.

Detecting Pass-the-Ticket at the Endpoint

In researching detection of pass-the-ticket I came across a very interesting approach posted by a researcher Eyal Neemany at Javelin Networks.  The concept of this approach is to do the following at any endpoint in your environment when you want to investigate for pass-the-ticket activity:

  1. Look at the current logon sessions on that system
  2. Use the klist command to inspect the Kerberos tickets associated with that session
  3. Look for Kerberos tickets that do not match the user associated with the session.  If found, that means those were injected into memory and a pass-the-ticket attack is afoot. 

That’s a really clever way to look for this activity, but let’s take a deeper look to see how the pieces fit together.

First, we need to output all of the logon sessions, and obtain the logon IDs (in hex format) so we can pass them to the klist command to inspect their Kerberos tickets.  I used this script adapted from the Get-LoggedOnUsers function I found on GitHub to do the trick. 

        $regexa = '.+Domain="(.+)",Name="(.+)"$'
        $regexd = '.+LogonId="(\d+)"$'
        $logon_users = @(Get-WmiObject win32_loggedonuser -ComputerName 'localhost')

        $session_user = @{}
        $logon_users |% {
            $_.antecedent -match $regexa > $nul
            $username = $matches[1] + "\" + $matches[2]
            $_.dependent -match $regexd > $nul
            $session = $matches[1]
            $sessionHex = ('0x{0:X}' -f [int]$session)
            $session_user[$sessionHex] += $username 
                      
        }
        $session_user 

This will output a list of sessions.  Then we can use the klist –li command and pass in a session ID to see the tickets associated with it. 

You can see by doing that here I can inspect a session for the user Michael, but see a Kerberos TGT for the user Gene. Pass-the-ticket detected! 

This worked reliably in my lab without false positives, but leave a comment if you know of any ways that this can be triggered by activity other than pass-the-ticket. 

Detecting Pass-the-Ticket at the Domain

Let’s say you didn’t want to run that logic on every endpoint, is there a way to look for pass-the-ticket behavior on your domain controllers?  There is!  It may not be quite as reliable, but it’s always good to have a detection you can get from your DC logs. 

To understand what to look for, let’s evaluate normal event log behavior you would see for Kerberos authentication on the network.

4768 – A Kerberos authentication ticket (TGT) was requested

The first event you should see is a 4768 event.  This is the TGT request and is the first thing that must happen for a user to leverage Kerberos to access a network resource.  You will get one of these for each user for every endpoint they access your domain from.  If a user account logs in from two separate workstations, they will request a TGT from each.

The most relevant information in this event is the user who requested the TGT and the computer they requested it from.

4769 – A Kerberos service ticket was requested

The next step in Kerberos is for the user to use that TGT and request a TGS service ticket to access a service on a computer, such as CIFS to get to a file share. This will also show up in the logs in event 4769 and you can see here the user who requested the ticket and the source computer.

4770 – A Kerberos service ticket was renewed

Renewing a TGT generates event 4770. By default, TGTs can be renewed for 7 days.  If you want to test this, Rubeus has a command “renew” to renew TGTs that have been extracted. You can see also in this ticket, you get the user who renewed and the source of the renewal. 

So to look for pass-the-ticket activity, what are you looking for that would stand out? Well if you assume the attacker will harvest TGTs and then use them on a different system, which is likely, then you can look for behavior that fits this pattern. 

That would be TGS requests or TGT renewals with a particular Account / Client pair that have no associated TGT request from that Account / Client pair. You would have to look at a TGS request or TGT renewal and then scan back the previous 10 hours to see if there was a TGT request that matches that user and computer. 

That is because in pass-the-ticket the attacker will never request a TGT, they will always steal it from LSASS. They may renew it, and they definitely may use it to request TGS service tickets. 

Now, that detection goes above and beyond event log filtering and to do this at scale likely requires the use of a SIEM or third-party product. If you’re looking for a way to detect this, check out StealthDEFEND and see how it can help with this and other Active Directory attacks. 

Interested in getting notifications for other blogs in this series? Sign up here.

Then, register for our upcoming webinar on AD lateral movement to get all the details!

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Start a Free StealthAUDIT® Trial!

No risk. No obligation.