Discovering Service Accounts without Using Privileges

Discovering Service Accounts without Using Privileges

Service Account Attack #1: LDAP Reconnaissance with PowerShell

In the introductory post, we outlined what a service account is and how these accounts relate to other privileged accounts within an Active Directory environment. There could be many reasons to discover where service accounts are and how they are being used. In this post, we will approach this discovery through the mindset of an attacker. Attackers will often target service accounts because they hold elevated privileges and do not have strict password reset policies. That allows these accounts to be compromised and leveraged for extended periods of time without detection or hindrance.

During the reconnaissance phase of the kill chain, an attacker will have little to no privileges within the domain. Therefore, any discovery performed must be possible without elevated privileges such as Domain Administrator or even local Administrator rights. Let’s look at some of the ways an attacker can find service accounts with no privileges at all.

Finding Privileged Accounts without Using Privileges

Active Directory offers many security and management benefits, but also can make things a little too easy for a curious attacker. Due to the architecture of Active Directory, once an attacker has infiltrated any domain-joined computer, they are able to query the directory and its objects. In some cases, this can even be done anonymously. Here are some of the ways an attacker can discover service accounts by querying the directory.

Service Principal Names (SPNs)

Service accounts leverage SPNs to support Kerberos authentication. While this provides improved security, it also leaves a trail of exactly where these accounts are used and what they are used for. This information can be easily exploited by an attacker. SPNs are commonly used to run services to support applications like Microsoft SQL Server and SharePoint. In a previous blog series, we explored how to use PowerUpSQL to perform a more advanced discovery based off of this principal. For our purposes, there are even simpler ways to get the information we need.

Using PowerShell, it is possible to find a list of all domain service accounts that have registered SPN values.

#Build LDAP Filter to look for users with SPN values registered for current domain
$ldapFilter = "(&(objectclass=user)(objectcategory=user)(servicePrincipalName=*))"
$domain = New-Object System.DirectoryServices.DirectoryEntry
$search = New-Object System.DirectoryServices.DirectorySearcher
$search.SearchRoot = $domain
$search.PageSize = 1000
$search.Filter = $ldapFilter
$search.SearchScope = "Subtree"
#Execute Search
$results = $search.FindAll()
#Display SPN values from the returned objects
foreach ($result in $results)
{
    $userEntry = $result.GetDirectoryEntry()
    Write-Host "User Name = " $userEntry.name
    foreach ($SPN in $userEntry.servicePrincipalName)
    {
        Write-Host "SPN = " $SPN       
    }
    Write-Host ""    
}

And you can see from the results the SPN value itself will show you where the account is registered and what service it is registered for on that system. Below is the SPN value for a SQL service account.

Using servicePrincipalName to find a SQL Service Account that has an SPN from MSSQLSvc

With this simple query an attacker can identify a list of service accounts as well as the computers, applications, and data they will provide access to.

Service Accounts Using Generic Object Attributes

While SPNs are very reliable and informative, they will not produce a comprehensive list of service accounts. Many accounts do not integrate with Kerberos through SPNs and will have no SPN values set. However, most organizations find other ways to make the discovery of service accounts achievable from the directory through use of naming and location conventions.

Most companies will establish naming conventions where all service accounts start with “SVC” or something similar. Also, service accounts are typically placed into their own organizational units (OUs) or groups. By exploiting these common conventions, attackers can again discover valuable service accounts with no domain rights.

Here is a PowerShell script to find all accounts that contain “svc” in the name. This can easily be modified to support other naming conventions. 

#Build LDAP Filter to look for users with service account naming conventions
$ldapFilter = "(&(objectclass=Person)(cn=*svc*))"
$domain = New-Object System.DirectoryServices.DirectoryEntry
$search = New-Object System.DirectoryServices.DirectorySearcher
$search.SearchRoot = $domain
$search.PageSize = 1000
$search.Filter = $ldapFilter
$search.SearchScope = "Subtree"

#Adds list of properties to search for
$objProperties = "name"
Foreach ($i in $objProperties){$search.PropertiesToLoad.Add($i)}

#Execute Search
$results = $search.FindAll()
#Display values from the returned objects
foreach ($result in $results)
{
    $userEntry = $result.GetDirectoryEntry()
    Write-Host "User Name = " $userEntry.name
    Write-Host ""    
}

If naming conventions for the objects are not used, often times it is valuable to search for where they are located within the directory structure. This LDAP filter can be replaced into the above script to find any OUs that contain “Service” or “svc” in the name:

Using an LDAP filter in the PowerShell script to do an LDAP OU search and PowerShell OU search to find OUs that contain service accounts

Once you know those locations, you can search those OUs for all user objects to find your service accounts. This script is updated to focus on one OU with Service in the name:

Once you know those locations, you can search those OUs for all user objects to find your service accounts. This script is updated to focus on one OU with Service in the name:

Search members of an OU with PowerShell to find service accounts

Service Accounts Discovery via User Account Control

Another sneaky way to search Active Directory for service accounts is to investigate the values of an object’s user account control settings. Often, service accounts will have settings in place that regular user accounts will not. The best example of this is the “password never expires” setting. Service accounts may have passwords set to never expire because the act of resetting them can be tedious and result in application or service outages.

Analyze user account control settings like password never expires to find service accounts

With PowerShell it is possible to query all accounts with this value enabled, using a slightly more complicated LDAP filter.

Using the LDAP Filter for password never expires within PowerShell to find service accounts

Privileged Discovery

While this post focused solely on ways to find service accounts without leveraging any privileges, if an attacker does find an account that has privileges on one or more systems within the network, there are many other effective ways to discover service accounts. Some of those ways include:

  • Enumerating services on endpoints and extracting the startname account
  • Searching for connection strings within web.config, scripts, and other locations where service accounts may be hard-coded
  • Exploring the local policy for users granted Log on as a Service
  • Extracting event logs for non-interactive logon types
  • Finding application pool and other web application service accounts

Exploiting the Discovered Accounts

Now that we have built a list of valuable service accounts, the next step is to exploit these accounts. We will explore techniques to do so in the upcoming blog posts:

Service Account Attack #2 – Extracting Service Account Passwords with Kerberoasting Read Now
Service Account Attack #3 – Targeted Service Account Exploitation with Silver Tickets Read Now
Service Account Attack #4 – Exploiting the KRBTGT service account for Golden Tickets Read Now

To watch the Service Account Attacks webinar, please click here.

Don’t miss a post! Subscribe to The Insider Threat Security Blog here:

8 thoughts on “Discovering Service Accounts without Using Privileges

  1. Screenshots? Seriously?

    That makes the article a lot less useful by preventing copying and pasting the article’s code into the user’s ISE…

  2. Hello Jeff. I’m finding this article very useful. I’m not knowledgeable with PS, and tried to research and tried a few code inserts but couldn’t get it to work, but I was wondering how you could write the output of the first script in this article (Service Principal Names (SPNs)), out to a file in my local directory, instead of to the screen?

    1. Hello, glad you are finding this useful! With a few minor changes to the script you can easily store the values in a string and output it to a file rather than print it to a screen. Here is the same script which will write to a file c:\Temp\SPN.txt:


      #Build LDAP Filter to look for users with SPN values registered for current domain
      $ldapFilter = "(&(objectclass=user)(objectcategory=user)(servicePrincipalName=*))"
      $domain = New-Object System.DirectoryServices.DirectoryEntry
      $search = New-Object System.DirectoryServices.DirectorySearcher
      $search.SearchRoot = $domain
      $search.PageSize = 1000
      $search.Filter = $ldapFilter
      $search.SearchScope = "Subtree"
      #Execute Search
      $results = $search.FindAll()
      #Display SPN values from the returned objects
      $resultOutput = @()
      foreach ($result in $results)
      {
      $userEntry = $result.GetDirectoryEntry()
      $resultOutput += "User Name = " + $userEntry.name
      #Write-Host "User Name = " $userEntry.name
      foreach ($SPN in $userEntry.servicePrincipalName)
      {
      $resultOutput += "SPN = " + $SPN
      #Write-Host "SPN = " $SPN
      }
      #Write-Host ""

      }

      Out-File -FilePath C:\temp\SPN.txt -InputObject $resultOutput

  3. Hello Jeff.
    Is there a way to use ‘Service Accounts Discovery via User Account Control’, to find e.g. svc accounts with a ‘blank’ password? Cheers, John.

    1. Jeff. I continued researching this, and I don’t belive what I asked is possible. What I did find is that you can use ‘User Account Control’ to find AD accounts that have the ‘Password Required’ set to ‘No’, which could use a ‘blank’ password. This basically overrides the group policy/password controls:
      $ldapFilter = “(&(objectclass=user)(objectcategory=user)(useraccountcontrol:1.2.840.113556.1.4.803:=32))”

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.

Privacy Preference Center

      Necessary

      Advertising

      Analytics

      Other