In our purple team service, we try to take a depth and quality approach and run many different functionally diverse test cases for a given technique. In this blog, I will describe our process of defining and implementing test cases for our purple team runbooks. The goal of this blog post is to provide the community with a bit more information about how we implement test cases for logon session enumeration, what preventative controls might be, and how this process can be applied to other techniques.
We wanted to develop a logical numbering system to separate test cases for each technique. After a couple of iterations of our purple team service, we started to deliberately select test cases and run variations based on three distinct categories:
Defining test cases in this manner allows us to triangulate a technique’s coverage estimation rather than treat the techniques in the MITRE ATT&CK matrix as a bingo card where we run net session and net1 session, fill in the box for this technique, and move on to the next one. After running each test case during the purple team assessment, we look for whether the test case was prevented, detected, or observed (telemetry) by any security controls the organization may have.
Let’s dive into logon session enumeration by deconstructing the functional differences between three distinct procedures. If you want to learn more (or want to apply this methodology yourself), you can find out more about the process we use to examine the function call stack of tools in Nathan’s Beyond Procedures: Digging into the Function Call Stack and Jared’s On Detection: Tactical to Functional series.
We can start by examining the three distinct procedures that SharpHound implements. Rohan blogged about the three different methods SharpHound uses. SharpHound can attempt to use all three depending on the context it’s running under and what arguments are passed to it. The implementation of each procedure can be found here: NetSessionEnum, NetWkstaEnum, and GetSubKeyNames in the SharpHoundCommon library. Matt also talks about this in his BOFHound: Session Integration blog.
Here is a breakdown of each of the three unique procedures implemented in SharpHound for remote session enumeration:
Distinct Procedure #1: Network Session Enumeration (NetSessionEnum)
NetSessionEnum is a Win32 API implemented in netapi32.dll. The image below shows where each tool is implemented in the function call stack:
This Win32 API returns a list of active remote or network logon sessions. These two blogs (Netwrix and Compass Security) go into detail about which operating systems allow “Authenticated Users” to query logon sessions and how to check and restrict access to this API remotely by altering the security descriptor in the HKLM/SYSTEM/CurrentControlSet/Services/LanmanServer/DefaultSecurity/SrvsvcSessionInfo registry key. If we read Microsoft’s documentation on the RPC server, we see the MS-SRVS RPC server is only implemented via the \PIPE\srvsvc named pipe (RPC servers can also be commonly implemented via TCP as well). As Microsoft’s documentation states, named pipes communicate over CIFS\SMB via port 445.
In our purple team service, we usually target the organization’s most active file server for two reasons. First, port 445 (SMB) will generally be open from everywhere on the internal network for this server. Second, this server has the most value to an attacker since it could contain hundreds or even thousands of user-to-machine mappings an attacker could use for “user hunting.”
Distinct Procedure #2: Interactive, Service, and Batch Logon Session Enumeration (NetWkstaUserEnum)
NetWkstaUserEnum is also a Win32 API implemented in netapi32.dll. Below is the breakdown of the function call stack and where each tool is implemented:
As Microsoft documentation says: “This list includes interactive, service, and batch logons” and “Members of the Administrators, and the Server, System, and Print Operator local groups can also view information.” This API call has different permission requirements and returns a different set of information than the NetSessionEnum API call; however, just like NetSessionEnum, the RPC server is implemented only via the \PIPE\wkssvc named pipe. Again, this blog from Compass Security goes into more detail about the requirements.
Since this, by default, requires administrator or other privileged rights on the target machine, we will again attempt to target file servers and usually get an access denied response when running this procedure. As a detection engineer, if someone attempts to enumerate sessions, do we have the telemetry even if they are unsuccessful? Next, we will attempt to target a workstation on which we have administrator rights to enumerate sessions using this minor variation in a different test case.
Distinct Procedure #3: Interactive Session Enumeration (RegEnumKeyExW)
Note: I’m only showing the function call stack of RegEnumKeyExW, SharpHound calls OpenRemoteBaseKey to get a handle to the remote key before calling RegEnumKeyExW. I also left out calls to API sets in this graph.
RegEnumKeyExW is, again, a Win32 API implemented in advapi32.dll. Below is the breakdown of the function call stack and where each tool is implemented:
As Microsoft documentation says, the remote system “requires the Remote Registry service to be running on the remote computer.” Again, this blog from Compass Security goes into more detail about the requirements, but by default, the service is disabled on workstation operating systems like Windows 11 and 10 and set to trigger start on server operating systems by interacting with the \PIPE\winreg named pipe. If the remote registry service is running (or triggerable), then the HKEY_USERS hive can be queried for a list of subkeys. These subkeys contain SIDs for users that are interactively logged on. Like NetWkstaUserEnum and NetSessionEnum, the RPC server is implemented only via the \PIPE\winreg named pipe.
Now that we have a diverse set of procedures and tooling examples that use a variety of execution modalities, we can start creating test cases to run for this technique. Below, I have included an example set of test cases and associated numbering system using each of the three distinct procedures and altering the execution modality for each one.
You can also find a full TOML runbook for the examples below here: https://ghst.ly/session-enumeration-runbook. All of the test cases are free or open source and can be executed via an Apollo agent with the Mythic C2 framework.
For example, our numbering looks like: Test Case X.Y.Z
A sample set of test cases we might include:
Network Session Enumeration (NetSessionEnum)
Interactive, Service, and Batch Logon Session Enumeration (NetWkstaUserEnum)
Interactive Session Enumeration (RegEnumKeyExW)
After executing each test case, we can determine if the test case was prevented, detected, or observed. Tracking information like this allows us to provide feedback on your controls and predict how likely they would detect or prevent an adversary’s arbitrary selection of procedure or execution modality. Also, we space test cases about 10 minutes apart; name artifacts like files, registry keys, and processes by their corresponding test case number; and alternate the machine and source user we are executing from to make finding observable telemetry easier. We may include or exclude certain test cases based on the organization’s security controls. For example, if they block and alert on all powershell.exe usage, we aren’t going to run 40 test cases across multiple techniques that attempt to call the PowerShell binary.
By researching and deconstructing each tool and looking at the underlying function call stacks, we found that regardless of which distinct procedure or execution modality was used, they all used three different RPC servers, each implemented using named pipes. This will also allow us to triangulate detection coverage and help determine if a custom or vendor-based rule is looking for a brittle indicator or a tool-specific detail\toolmark.
We now have a fairly broad set of test cases for a runbook that accounts for a wide variety of attacker tradecraft for this technique. Knowing this as a blue teamer or detection engineer will allow me to implement a much more comprehensive detection strategy for this particular technique around the three named pipes we discovered. This allows us to write robust detection rules, rather than looking for the string “Get-NetSession” in a PowerShell script. Would this produce a perfect detection for session enumeration? No. Does this include every single way an attacker can determine where a user is logged? No. Does deconstructing adversary tradecraft in this manner vastly improve our coverage for the technique? Absolutely.
In my next post, I will cover many log sources native to Windows (I’m counting Sysmon as native) and a couple of EDRs that allow us to detect logon session enumeration via named pipes (or TCP in some cases). Some of these sources you might be familiar with, others aren’t very well documented. Each of these log sources can be enabled and shipped to a centralized place like a SIEM. Each source has its requirements, provides a different context, and has its pros and cons for use in a detection rule.
Deconstructing Logon Session Enumeration was originally published in Posts By SpecterOps Team Members on Medium, where people are continuing the conversation by highlighting and responding to this story.
*** This is a Security Bloggers Network syndicated blog from Posts By SpecterOps Team Members - Medium authored by Garrett White. Read the original post at: https://posts.specterops.io/deconstructing-logon-session-enumeration-0426b8452ef5?source=rss----f05f8696e3cc---4