« Back to home

Kerberos AD Attacks - Kerberoasting

Recently I've been trying to make sure that my redteam knowledge is up to date, exploring many of the advancements in Active Directory Kerberos attacks... and there have been quite a few! I finally found some free time this week to roll up my sleeves and dig into the internals of some of these attacks, and hopefully document them for other people to learn.

This post is the first in a series aimed at explaining what is happening under the hood when you execute your favourite Powerview or Mimikatz command to attack Active Directory via Kerberos, and hopefully giving people some other methods or ways of thinking about attacks rather than just accepting that "Invoke-RedTeaml33t" gives you a DA account.

Lab Setup

Before we can start to experiment, it's important to have a lab environment that we are free to play around in. In my case, this consists of the following servers:

  • Windows Server 2016 - Domain Controller
  • Windows Server 2016 - Web Server
  • Windows Server 2016 - Attacking host

All 3 of these servers are deployed using VirtualBox. I did attempt a number of times to automate the creation of a lab environment using Vagrant using its support for WinRM, but after running into numerous bugs and many lost nights, I decided to just create a base Windows Server 2016 virtual machine image, and provision using the following Powershell commands:

Windows Server 2016 - Domain Controller

# Add our static IP address for this domain controller
New-NetIPAddress -InterfaceIndex 9 -IPAddress 172.16.14.1 -PrefixLength 24

# Add the domain controller role
Install-WindowsFeature AD-Domain-Services
Install-ADDSForest -DomainName lab.local -InstallDNS

# Restart our machine
Restart-Computer

# Create our IIS service account
New-ADUser -Name "IIS Service Account” `
    -SamAccountName iis_svc -UserPrincipalName iis_svc@lab.local `
    -ServicePrincipalNames "HTTP/iis.lab.local” `
    -AccountPassword (convertto-securestring "Passw0rd" -asplaintext -force) `
    -PasswordNeverExpires $True `
    -PassThru | Enable-ADAccount

Windows Server 2016 - Web Server

# Add our static IP address for this domain controller
New-NetIPAddress -InterfaceIndex 9 -IPAddress 172.16.14.2 -PrefixLength 24

# Point our DNS resolver to the DC
Set-DnsClientServerAddress -InterfaceIndex 2 -ServerAddresses 172.16.14.1

# Set our machine to be "iis.lab.local"
Rename-Computer -NewName “iis”

# Add our machine to the domain
Add-Computer -DomainName lab.local

# Restart to join the domain
Restart-Computer

# Set up our IIS server configuration
Import-Module WebAdministration

# Remove the default website
Remove-Item 'IIS:\Sites\Default Web Site' -Confirm:$false -Recurse

# Create our new app pool, and set to use our IIS service account
$appPool = New-WebAppPool -Name iis.lab.local_pool
$appPool.processModel.identityType = 3
$appPool.processModel.userName = “LAB\iis_svc”
$appPool.processModel.password = “Passw0rd”
$appPool | Set-Item

# Create our new website and enable Windows Authentication
$WebSite = New-Website -Name iis.lab.local -PhysicalPath “C:\InetPub\WWWRoot” -ApplicationPool ($appPool.Name) -HostHeader iis.lab.local

Set-WebConfigurationProperty -Filter /system.WebServer/security/authentication/anonymousAuthentication `
    -Name enabled -Value $false -Location $Fqdn

Set-WebConfigurationProperty -Filter /system.WebServer/security/authentication/windowsAuthentication `
    -Name enabled -Value $true -Location $Fqdn

Set-WebConfigurationProperty -Filter /system.webServer/security/authentication/windowsAuthentication `
    -Name useAppPoolCredentials -Value $true -Location $Fqdn

Windows Server 2016 - Attacking host

# Add our static IP address for this domain controller
New-NetIPAddress -InterfaceIndex 9 -IPAddress 172.16.14.3 -PrefixLength 24

# Point our DNS resolver to the DC
Set-DnsClientServerAddress -InterfaceIndex 2 -ServerAddresses 172.16.14.1

# Add our machine to the domain
Add-Computer -DomainName lab.local

# Restart to join the domain
Restart-Computer

The Virtualbox deployment is also configured to provide each virtual machine with a network interface attached to an internal "domain" network, so that once each machine has been set up, we have a simple network consisting of 3 IP addresses all joined to the "lab.local" domain.

Now that we have a place to practice some of our Kerberos based attacks, let's look at our first attack in the series... Kerberoasting.

What is Kerberoasting

Kerberoasting is a technique which exploits a weakness in the Kerberos protocol when requesting access to a service. Recently this method has been gaining notoriety, with actually another talk being given on the subject at this years Derbycon.

A number of tools have been created to simplify the process of completing a Kerberoasting attack on a Windows domain. My goto tool is the awesome "Invoke-Kerberoast", which is a Powershell commandlet available in PowerSploit and developed by HarmJ0y. If you haven't seen his blog post on this topic, please do so here, and subscribe to his blog while you are there!

Before digging into the internals of this method, let's see just how easy it is to perform this kind of attack with the right tools:

Now we have seen just how to attack Active Directory using this simple commandlet, the hacker in you should be screaming out for the details of how this vulnerability is actually exploited behind the scenes. First let's provide an overview of what what happens when a user is actually requesting access to a service:

  1. The user authenticates with the Key Distribution Centre (the Domain Controller in this case) using an AS-REQ packet.
  2. The KDC validates the user credentials and if valid, returns a Ticket Granting Ticket (TGT).
  3. When the user wants to authenticate to a service such as IIS, a request is made to the Ticket Granting Service (TGS) containing the TGT and the Service Principal Name (SPN) of the service to be accessed.
  4. If the TGT is valid and has not expired, a TGS creates a service ticket for the target service. The service ticket is encrypted with the credentials of the service account.
  5. A TGS response is sent to the user with the encrypted service ticket.
  6. The service ticket is finally forwarded to the service, which is decrypted by the using the service account credentials.

While this is a very simple account of how this process works, the important part to note is that the service ticket is encrypted with the hash of the service account, which allows any authenticated user on a Windows domain with the ability to request a service ticket from the TGS to perform an offline bruteforce attack.

Before we move on, it is probably worth exploring SPN's a little more, as this will be an important part of hunting accounts on a domain network.

Service Principal Names

Microsoft describes a Service Principal Name as:

A unique identifier of a service instance. SPNs are used by Kerberos authentication to associate a service instance with a service logon account.

What this means that essentially, a SPN is a unique identifier which is used to associate a domain account with a service and host. A SPN in a Windows Domain environment has the following format:

SERVICE/host.name

For example, our IIS instance in our above created lab environment is:

HTTP/iis.lab.local

This SPN is associated with the user account in which the service will be operating, again in our case this is the "LAB\iis_svc" user. This binding is actually done in LDAP, by setting the "servicePrincipalName" attribute to the SPN value:

It is also worth mentioning that computer accounts in Active Directory are also essentially service accounts, with SPN's associated in LDAP. This makes sense, as services running as LOCAL SYSTEM will often be requested via Kerberos, such as SMB or remote registry etc. Unfortunately for us as an attacker, computer account passwords are long, complex, and rotated every 30 days, meaning that bruteforcing these credentials is not possible.

Now we understand just how an account is associated with a Kerberos service, let's continue to look at just how the internals of a Kerberoasting attack work.

Kerberoasting "behind the scenes"

Let's run a packet capture during a request to our IIS website in our lab setup to see the packets sent across the network. To generate our network traffic, we use the following command which authenticates to the IIS service with Kerberos:

Invoke-WebRequest http://iis.lab.local -UseDefaultCredentials -UseBasicParsing

Once completed, we see the following packets in Wireshark:

The first 2 packets, AS-REQ and AS-REP are, as explained above, the way in which a user authenticates with the KDC and retrieves a TGT. The important part for Kerberoasting are the TGS-REQ and TGS-REP packets.

First we will look at the TGS-REQ packet contents:

Here we can see that the request is being made for the HTTP/iis.lab.local SPN within the LAB.LOCAL domain, pretty straight forward as we know we are authenticating with the IIS instance. We can actually take the time to use the SetSPN.exe tool which is available in Windows to verify exactly which account is providing this SPN , by using the following parameters:

setspn.exe /Q HTTP/iis.lab.local

This of course returns our earlier "IIS Service Account" user which we set up in our lab.

Next, looking at the TGS-REP packet we find a service ticket which is encrypted (in the below example using RC4) using the service account password of LAB\iis_svc:

It is this data that allows us to bruteforce the service password offline, as we know that key to decrypt the service ticket data is just the service account password.

And this is essentially all there is to it. So to confirm the steps taken in a Kerberoasting attack:

  1. The attacker searches for accounts within Active Directory with a servicePrincipalName attribute assigned.
  2. The attacker makes a request to the Domain Controller for a service ticket for the service.
  3. The service ticket is then taken and bruteforced offline to reveal the service account password.

All that is left to do is to pass the data over to a password cracking tool such as JTR. If we look at the format of the hash used by JTR, we find the following is expected:

$krb5tgs$<ENCRYPTION_TYPE>$*<USERNAME>$<REALM>$<SPN>*$<FIRST_16_BYTES_TICKET>$<REMAINING_TICKET_BYTES>

To finish off, let's manually construct this hash format from our Wireshark capture above by filling in the fields above, which gives us the following:

$krb5tgs$23$*iis_svc$LAB.LOCAL$HTTP/iis.lab.local*$0F6FC474DB169AA8CE9B5E626DAACC9D$1A346CE3F66C52976F53831AA24A1B217CDF0D68A0EB87FEE00CFD32F544BF83EBB6416732522B12232DD6935EAC076B439F56E6CB7FA6C37D984D132E2D2CB65CA399CD5E44EB2EB41F12C40F9044B40E3EA914278C8A3098BABACF49AB46E776D1413EF63ABCDF6418D2DB9241B2FDD9309346EC59AF20A82FD6DAEA9510C1DFD1A9E8D99C59FF72E985057BA0D18394B0A7CB1BD74F8D436A3DD780175A0C6BCAD9E46570A476AB9913B561EE481AD8C33A3C81CED055E959F08A52EBA7A342F53183E1531BE8EC2D28C7ECFA32F98DBC7FF87B4E5C79824F3868D38CE09010960726D58CFBFC88C9D34AB199169F39010AA4AAB92B6EA40F875963D518311B3F079D97B65FE9768C9A4EE50F7C16D525FDC081CE359A0B0FE5FB18D8D8690D8F88B010BEF4F28DC151A4137272AE9EACA9053406C0DDEAE453196E3B6C28B8359724BFC089B772CBAE093BF88ABC070D12B0FF2E721D7B8B10B822BFB514091EFFAF3F5FA8C286A9E45BF76BA171E6CABEB3DDADC297185C51A295855B8CFA8062BD6770093355C32690FD184D6EAE2B66EA1F553CBC7679681DB5089FDB23329EFE59DE807E657A98CCC0C2D95EAAC9F363D5B8C9B8A23AAB680C328B019AE99440A5D8795014BE22F6739A4F77874E94196F010C012F9A4A587570C38874AD7F8B9EC554FB865752A5F3DD4F785C9AF54031100CE580DFADF4C70FF11839647FC288FCE8D00BBCB680E02A46230ECB0530BA1771FB8485BA17F5218852C5CDFC769B89D77B37802CC6D22E6BA944F6E4B565D8D04418C44BF10E06294FD58913CA6D206BB6E46F15B3ABFC09695F5FBAB81D2E743AC19B24716D9D6CB6BAE65674F5CDF1935D1413A4BE6D96EAFAF65CFA361DECC0AB1E12998B5C26B6AD38C8077FD149CDEDA227C4C68F19FBF22B23E7E84581A64A413C1C983E01B56C2000656B4AAD8C67260FC0142EECCD96D624FA284B619D11E797AF2D730A5998D9E6D9F4FEF58A847D7D9B804BE2925BEAE627A0A9F335072F97F214A24DB58CF5E2E74F0EEFF1A43F1EC1B88C0110F3C2ABAAC0D3E954A42B550C37CF84BABE6E85EC4E0885EB8309A4C5E2A1BB473B332FF5C31C0B4C32DB507C1ECA5B7AE607D2423EE1E7F07361229E0AB2678CFBD07AFFFC5E989C5AB1821AC2F524083258D3F0CA7E7F8250BE3F7CC72CF636B098A3C9B3F4E289FD81A9B3C33BFA63ED8813BBC12205134ADD9FB8548312B734C921A2CF8A1687AF7EE022B0F57BBF0F8D8F17952614CB288B95DF3FE4F03D20B83227328603DAFB264537EB0CACDA18DE21AA99E07600030424EDB41FC3C8161238971BF62AF99DB8E2D438AF06F9D8FEEFF3EDB6A4D4F0A6FB5DFDBE99B1ED454D6FF3DC508C45ED430923212A088E6200B2076DA509888EDD32FCA946A215C8934DB7A3B5AC6BED10E4A114F2F132608DBE236CBA73CBCFFC024FB500E96C3D766CA7F4083DED3666C2B7DCD290F65F7E80FF70FA575777A845FBF7AF05B38DFB1CCD7ACCC0398F8DBF532E28DC6BC0EC49D18F2753CAEC5912693A0B6050F2BFCE72F5160847DCFC78D580609007DDBDF1F338C61C13E7B62FCEC6E51D1C0CD1EC0167E40042`

Passing this to JTR, we see that this is cracked and our password is revealed:

So hopefully by stepping through this process manually, you have some insight into this attack method. Next up we will be looking at some similar attack methods, the so-called AS-REP Roasting attack which mirrors a Kerberoasting attack quite closely, and just how this operates under the hood.

As always, if you have any feedback, please feel free to reach out in the usual places.