Attack Detection Fundamentals: Discovery and Lateral Movement - Lab #1

In the third part of F-Secure Consulting's Attack Detection Workshop series, covering Discovery and Lateral Movement, we explored a number of offensive techniques for discovering assets of value, be that users or file shares, and methods for moving between compromised hosts. We also explored the detection strategies that can be employed to spot these using our own detection stacks. As with previous workshops, the following blog provides a step-by-step guide to recreating the demos from that Discovery and Lateral Movement workshop, as well as exercises to further the reader's understanding of the concepts shown.

A recording of the workshop can be found here.

In the first lab of this workshop, we are once again going to make use of the Covenant framework. We will launch a basic executable launcher and, from there, explore some techniques for acquiring user credential material through kerberoasting and AS-REP roasting. Both of these will be achieved using Rubeus, one of the many tools integrated into Covenant. There is also a further exercise using the functionality provided by SharpSploit to enumerate domain users and groups.

From a detection standpoint, we will make use of a telemetry source that we haven’t touched on too much yet, Event Tracing for Windows, aka ETW. Understanding the ins and outs of ETW isn’t a topic for this post, though there are plenty of great resources available to further your understanding (Roberto Rodriguez’s post is probably a good place to start). For the purposes of this exercise, the important thing to note is that we can create consumers that, as the name suggests, consume events from event providers. These providers allow us to get access to telemetry from a wide array of system operations. These include everything from network activity to the use of .NET. For this lab, we’re going to log ETW events using SilkService, an open-source tool developed by Ruben Boonen. 

By Ruben’s own admission, SilkService is not an enterprise-ready tool that should be deployed across a corporate estate, but it’s exactly what we need to demonstrate the value of ETW as a log source, and demonstrate some of the telemetry that Endpoint Detection and Response (EDR) providers make use of to detect malicious activity.

We won’t walk through the setup of SilkService here (both Ruben’s README and Roberto’s blog cover this). To keep things simple though, provided below is the SilkService configuration we’ll be using for this lab. This registers a single consumer, capturing events from the Microsoft-Windows-LDAP-Client ETW provider. This will capture all the LDAP queries that our host makes as we carry out our activities.

Microsoft-Windows-LDAP-Client ETW Provider

NOTE: The userkeywords field set to 0x1, this flag specifies that we only want to log search requests and the parameters passed to them. The responses to our search queries aren’t logged.


DISCLAIMER: Set up of the tools and the testing environment might not be covered comprehensively within this lab. We will assume basic familiarity with Linux/Windows command line and the ability of the reader to deploy the necessary frameworks. For that, it is recommended to follow the suggested references for the official tutorials and walkthrough published by the framework's author. In addition, we have modified our lab environment to include users that are kerberoastable and AS-REP roastable, this setup is left as an exercise for the reader.  

Required Tools

  • Active Directory domain with at least one DC and workstation
  • HELK (optional)
  • SilkService
  • Covenant


1 – Listener Setup

From previous workshops you should be familiar with Covenant and its use of Listeners, Launchers and Grunts. As before, we’re going to setup a HTTP listener. Ensure the “ConnectAddress” and “ConnectPort” parameters are set appropriately.

covenant listener

We’re then going to generate a binary launcher. Ensure we’re using our newly-created listener, and click “Generate” and then “Download”.

create grunt

You should now have your “GruntStager.exe” file downloaded - this is our Grunt .NET implant. We’re going to skip our Initial Access step here and simply copy-and-paste the Grunt onto our target host running SilkService. 

2 – Roastable User Enumeration

As well as “Domain Admins” and other groups considered high-value, other Active Directory objects are also of interest to us when we carrying out Discovery activities. One notable target is users that are what is colloquially referred to as ‘roastable’. This includes users that are susceptible to one of the following:

-         Kerberoasting

-         AS-REP roasting

While we won’t go into the technical details of how these attacks work here (there are several great blogs on these topics, not least harmj0y’s posts on the subject here and here), suffice to say that certain configurations of Active Directory enable the retrieval of credential material for offline brute-forcing.

Kerberoastable Users

One tool to achieve both kerberoasting and AS-REP roasting is Rubeus. Conveniently for us, Rubeus, like SharpSploit as we'll see later, is integrated into Covenant. Using our existing Grunt implant, we can execute the following command line to attempt to retrieve credential material for all kerberoastable accounts.

Rubeus kerberoast


Looking at that output we can see Rubeus has searched for kerberoastable users, found one such user, and requested the credential material for that user. Now, while there are other log sources that can be used to detect the actual kerberoasting action taking place,  for the purposes of this exercise we’re going to concern ourselves with that first stage – the discovery of users that are kerberoastable.

If we take a look at the Rubeus codebase, we can see this code block (with some additional code removed for readability) assembling an LDAP filter string.

// if no user specified, filter out the krbtgt account and disabled accounts
string userSearchFilter = "";

userFilter = "(!samAccountName=krbtgt)(!(UserAccountControl:1.2.840.113556.1.4.803:=2))";

string userSearchFilter = "";

string encFilter = "";

userSearchFilter = String.Format("(&(samAccountType=805306368)(servicePrincipalName=*){0}{1})", userFilter, encFilter);

In its default setting we end up with a query as follows: 


Breaking it down we can see the following:

  • & - This prefix asserts all subsequent filters must be met.
  • (samAccountType=805306368) – Only Active Directory users (not computers, groups, etc.)
  • (servicePrincipalName=*) – User accounts that have any service principal name (SPN) entries
  • (!samAccountName=krbtgt) – Omit the krbtgt account from this search
  • (!(UserAccountControl:1.2.840.113556.1.4.803:=2)) – Omit accounts that are disabled

Now if we go and search through our Microsoft-Windows-LDAP-Client ETW provider logs for this filter, we hopefully(!) get a hit:

kerberoast etw trace

It’s worth mentioning that Rubeus, and many tools like it, including a number of filtering options to tailor the kerberoastable users returned. We won’t go into them all here but it’s a worthwhile exercise to read through the Rubeus kerberoasting code and understand the various LDAP filters it can apply.

NOTE: For our purposes, we’re forwarding SilkService logs onto HELK, as described in Roberto Rodriguez’s blog. It’s worth noting though that these are also being logged to the system event log and we could view them there.

This telemetry source is particularly useful as it allows us to trivially map the LDAP queries being made to the processes that executed them. In the screenshot above, we can clearly see “GruntStager” in the ProcessName field - of course, this isn’t the most discrete! But even in this contrived example, it highlights an opportunity for us to baseline the applications that make LDAP queries and the types of queries that they make. Enumeration of roastable users and high-value AD groups - including “Domain Admins” but also extending to any business-critical group – carried out by a process that wouldn’t typically request such information, would be worthy of investigation.


AS-REP Roastable Users

In the next exercise for this lab, we’ll try AS-REP roasting, again with Rubeus, and reviewing what our LDAP log source can do for us. As with previous exercises, we can run this straight from our Grunt, this time with the following command:

Rubeus asreproast

grunt asrep

Using the same approach as before, let’s take a look at the Rubeus codebase and understand the LDAP filter being used to retrieve users that could be subject to an AS-REP roast (again omitting additional filters for readability).

string userSearchFilter = "";
if (String.IsNullOrEmpty(userName))
userSearchFilter = "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304))";

And again, breaking this query down: 

  • & - All subsequent filters must be met.
  • (samAccountType=805306368) - Only Active Directory users (not computers, groups, etc.)
  • (userAccountControl:1.2.840.113556.1.4.803:=4194304) – Users have the "Do not require Kerberos preauthentication" enabled.

We can confirm this by performing the LDAP query ourselves. Let’s open Active Directory Users and Computers (ADUC) and select the search feature:

as rep filter

From here, we can select “Custom Search”:

as rep filter2

Now, if we copy and paste our LDAP query into the search field and search, we see a single user is returned:

as rep filter3 

If we view the account properties of our “Administrator” user, as we expect, we can see that the “Do not require Kerberos preauthentication” is set to enabled (obviously for our lab we’ve set this account property ourselves!)

as rep user

Much like the existence of SPNs for our kerberoastable users, the lack of enforced Kerberos preauthentication is what makes a user AS-REP roastable.

And just as before, looking for evidence of this filter in the logs, we can see the request being made.

asreproast etw

3 – Domain Admins Enumeration

As with many post-exploitation frameworks, Covenant has a ton of functionality that we can use to our advantage when carrying out reconnaissance of our testing environment. One of the most notable inclusions is the integration of SharpSploit (another toolset developed by Covenant’s author Ryan Cobb). The applications of SharpSploit go far beyond solely reconnaissance, with persistence, lateral movement and privilege escalation techniques included.

As an additional exercise for the reader, we could make use of the Covenant GetDomainGroup or GetDomainUser commands. For the former, as the name suggests, we can pass it a group-of-interest as an argument - in this case “Domain Admins” - and if successful it will return information about that group. We could also customise the Covenant Tasks to accept LDAP filters or make use of PowerView to experiment with the generated LDAP queries.

Get-DomainGroup “Domain Admins”

get domain admins

Looking at the ETW logs generated by the Microsoft-Windows-LDAP-Client provider we can see the following:

ldap etw trace


In this first lab of the Discovery workshop we covered how an attacker could identify users of interest, both in terms of their importance within Active Directory, and in terms of opportunities to kerberoast and AS-REP roast. We used a new log source, Event Tracing for Windows, or ETW, to capture events generated by the LDAP queries we made.

Performing some very superficial analysis of the Rubeus codebase, we could retrieve the LDAP filters we would expect it to use, and we’ve observed those in the logs.

The main takeaways from this first lab are:

  • An introduction to the low-level ETW telemetry we can capture and hunt with.
  • An introduction to several techniques used by threat actors for identifying targets and valuable users in a target environment.
  • The value of basic open-source tool analysis for spotting opportunities for detection.

Let's see if we can discover some exposed file shares in the next lab here.