User hunting is the process of tracking down where users are logged in or have a session in the network. By locating their login or session, you might be able to gain access to that Machine, privesc (if required), and operate in the context of the new user. This is obviously most helpful with elevated user accounts.
Harmj0y has talked in-depth about user hunting in multiple blog posts and at several different conferences… you might wonder, why another post? While many people have paid attention and are plenty capable of running PowerView’s “Invoke-UserHunter” function, they might not fully understand how it works below the hood. This can prevent them from being successful in “Austere” networks (you know, where things get weird), or very very large enterprise networks. Also, as people begin to lock down and follow best practice in Windows Domains, I have noticed a new trend in how I am gaining access to elevated user accounts.
For some of the posts and presentations on user hunting, check out:
How User Hunting Works
Below the hood, the user hunting functions in PowerView are relatively straight forward and worth a read. For Invoke-UserHunter, the script will first query the members of the target group (“Domain Admins” by default). Next, the script will query the domain for all machines using Get-NetComputers. Finally, the script will perform a Get-NetSessions and Get-NetLoggedOn against every host in the list and look for the users previously queried. While this technique provides the most coverage, it has the possibility of being slow and noisy-ish depending on the network (though we rarely get caught with it).
Invoke-StealthUserHunter works differently. StealthUserHunter attempts to be quieter and faster by only querying systems in the domain that provide the most value. In a Windows domain, fileservers and domain controllers are the most fruitful targets for gathering a large number of user sessions. StealthUserHunter begins by querying for users of interest like the regular UserHunter. Next, it calls Get-NetFileServers, which extracts the computer names from the home directories, script paths, and profile paths of users in the domain. Then the script will call Get-NetDomainControllers and add these as well to the host list. Finally, it will perform a Get-NetSessions against all of the servers in the host list and compare it against the target user group.
Since only one Get-NetSessions call is issued against a handful of high-traffic servers, this will complete much faster than the regular UserHunter. It should also do a better job of flying under the radar as it sends out significantly less traffic. While StealthUserHunter’s coverage isn’t as accurate, it usually gives us a good mapping and is our default method of choice on most engagements.
*If you want the raw dump of where all of the users are logged in, you can add a -ShowAll flag to the user hunter scripts. I prefer this so we do not have to query multiple times!
Where this gets difficult: Delegated groups
More and more I have seen enterprises move to a system of heavily delegated groups and roles within Active Directory. In this case, the local administrators of your target might be domain groups that contain 10s or 100s of other users. Also, the groups will typically be functional and relate to the type of system being targeted. For example, servers might have the local admin group of “Server Admins” while most workstations might have “Workstation Admin”. Also, network operations personnel and security people often have a local administrator group specific to the SOC or their organization.
This system of heavily delegated local administrator roles increases the difficulty of tracking down users to gain access to a target system but greatly increases the successful chances of gaining that access. So how do we utilize a domain account to work forward and gain access to target machines in these complicated scenarios?
Derivative Local Admin
To answer this, I think it is worth explaining the concept that I refer to as derivative local admin. Imagine we have a target system named “WorkstationA” that has the domain group “Network Ops” as a member of its local administrators group. Inside of the “Network Ops” group there is a user “Fred”, who on his machine “WorkstationB” has the domain group “Workstation Admins” as a member of its local admins. If there is a user “Sally” who is in the “Workstation Admins” domain group, she is a Derivative Local Admin of the original “WorkstationA”.
A malicious attacker could gain access to Sally and compromise her credentials or token. Using this, the malicious user could gain access to “WorkstationB” and compromise Fred’s credentials or token. She could then use these credentials to become the local administrator on the original target, “WorkstationA”. As far as the red team is concerned, anybody in the “Workstation Admins” group would be a great target to gain access to the original system, because they could gain access to specific people in the Network Ops group. While it might add a hop in the workflow, it only mildly obfuscates the attack path.
To demonstrate this, the graphic below presents the scenario:
The Process of “Walking Back” the Local Admins
Now that you get the concept, let’s walk through a scenario with some actual PowerView functions. Basically, we will start on the same foothold system, and use “Get-NetLocalGroup” and “Invoke-StealthUserHunter -ShowAll” to work our way backwards. Same scenario as above!
We start out as normal:
- We Phish Sally and escalate our privileges on her system. We can use Mimikatz to extract her credentials, giving us the rights of the “Workstation Admins” group
- Invoke-StealthUserHunter -ShowAll finds a Domain Admin logged in on WorkstationA
- We do a Get-NetLocalGroup WorkstationA and see that there is a group “Network Ops” on it
- We use Get-NetGroup “Network Ops” to enumerate users we want to target next. We see “Fred” is a member of this domain group, and match this up with our previous user hunting data to see that he’s logged in to WorkstationB
- We run a Get-NetLocalGroup WorkstationB to find that there is a group “Workstation Admins”
- We use our credentials to gain access to WorkstationB with WMI or PSExec and the agent of your choice
- We use Invoke-Mimikatz to dump the credentials from WorkstationB and find Fred’s credentials
- We use Fred’s credentials to gain access to WorkstationA
- We use Invoke-Mimikatz to dump credentials and retrieve the Domain Admin creds!
A Little Bit of Analytics
If you are not in a constrained scenario, very large enterprise network, or worried about making a little noise, the Invoke-EnumerateLocalAdmins –OutFile <file.csv> function can be very helpful. This function will perform a Get-NetLocalGroup against every system in the domain and output the results in CSV format. With this, and some enrichment data from the domain (user hunt data, user/group info), you could paint a picture of how to get from one system to another using entirely derivative local admin abuse.
@Harmj0y and I with some help from others are working to try to build an offensive dashboard to take in the output from PowerView and develop or present useful analytics to the attacker. With this dashboard, the process of discovering derivative local admins could be automated.
Overall, these methods provide you another technique to gain elevated access in cases where you might have a harder time working through the more traditional elevation of access walking back domain groups.