Normal view

There are new articles available, click to refresh the page.
Before yesterdayMain stream

Deconstructing Logon Session Enumeration

21 June 2024 at 14:18

Purple Teaming

How we define and create test cases for our purple team runbooks

Intro

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.

Defining Unique Test Cases

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:

  1. Distinct Procedures: Jared defines this as “a sequence of operations that, when combined, implement a technique or sub-technique.” We attempt to deconstruct tools that implement the technique to find functional differences, whether that tool is open-source or a Microsoft binary. This can require reverse engineering or reviewing source code to reveal what the tool is doing under the hood. It also might involve writing or altering existing tooling to meet your needs. An example of this can be found in part 1 of Jared’s blog On Detection: Tactical to Functional, where he reviews the source code of Mimikatz’s sekurlsa::logonPasswords module. If the tool implements a unique set of operations in the call graph, then we define that as a distinct procedure.
  2. Execution Modality: We then alter the execution modality, which changes how the set of functions is implemented. This is outlined in part 12 of Jared’s blog On Detection: Tactical to Functional: “one tool that is built into the operating system (Built-in Console Application), a tool that had to be dropped to disk (Third-Party Console Application), a tool that could run in PowerShell’s memory (PowerShell Script), a tool that runs in the memory of an arbitrary process (Beacon Object File), and a tool that can run via a proxy without ever touching the subject endpoint (Direct RPC Request)”. This variation helps us determine if we run the same distinct procedure but with a different execution mechanism (Beacon Object File, Unmanaged PowerShell, etc.) or is implemented in a different programming language (C, Python, PowerShell, etc.) will alter whether your security controls detected or prevented it.
  3. Minor Variations: Finally, we introduce slight variations to alter the payload, target user, computer, or process depending on the technique we are working on. In the case of logon session enumeration, we alter local vs. remote logon sessions and the machine we are targeting (i.e., file server, workstation, etc). During purple team assessments, we often find ourselves using this variation based on the organization’s environmental factors. For other techniques, these environmental factors normally include choosing which account to Kerberoast or which process to inject into.

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.

Deconstructing Distinct Logon Session Enumeration Procedures

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:

NetSessionEnum Function Call Graph

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:

NetWkstaUserEnum Function Call Graph

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:

RegEnumKeyExW Function Call Graph

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.

Putting it all Together with Test Cases

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

  • X — Distinct Procedure
  • Y — Execution Modality
  • Z — Minor Variation

A sample set of test cases we might include:

Network Session Enumeration (NetSessionEnum)

  • Test Case 1.0.0 — Enumerate SMB Sessions From Third-Party Utility On Disk (NetSess)
  • Test Case 1.1.0 — Enumerate SMB Sessions via Beacon Object File (BOF) — get-netsession
  • Test Case 1.2.0 — Enumerate SMB Sessions via PowerView’s Get-NetSession
  • Test Case 1.3.0 — Enumerate SMB Sessions via Proxied RPC

Interactive, Service, and Batch Logon Session Enumeration (NetWkstaUserEnum)

  • Test Case 2.0.0 — Enumerate Interactive, Service, and Batch Logon Sessions from BOF (netloggedon) — Server
  • Test Case 2.0.1 — Enumerate Interactive, Service, and Batch Logon Sessions from BOF (netloggedon) — Workstation
  • Test Case 2.1.0 — Enumerate Interactive, Service, and Batch Logon Sessions from Impacket (netloggedon.py)
  • Test Case 2.2.0 — Enumerate SMB Sessions via PowerView’s Get-NetLoggedOn

Interactive Session Enumeration (RegEnumKeyExW)

  • Test Case 3.0.0 — Enumerate Interactive Sessions via reg_query BOF (Server)
  • Test Case 3.0.1 — Enumerate Interactive Logon Sessions via reg_query BOF (workstation)
  • Test Case 3.1.0 — Enumerate Interactive Sessions from Impacket (reg.py)

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.

Conclusion

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.

References


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.

The post Deconstructing Logon Session Enumeration appeared first on Security Boulevard.

❌
❌