SPL Nuggets: Visualizing RDP/TS Connections from Eventlogs

In case you haven’t checked the previous article from the series, this is another easy to replicate SPL query that generates great value while keeping the code quite simple. Who does not like simple solutions to somewhat big problems?

Problem Statement

How to visually represent Remote Desktop (RDP) or Terminal Server connections within my network?

There are certainly many data sources eligible for achieving that. From network sniffer data, to EDR telemetry or even a custom script that runs netstat every second (don’t do that!).

Since this series is SIEM focused, the main data source are logs. Just like we’ve demonstrated in the previous post, one can extract really valuable info from Windows eventlogs. Those are usually leveraged for forensics, hunting/detection or troubleshooting.

It comes as no surprise, Windows (logs) is perhaps the #1 data source for SIEM projects focused on Security Monitoring. However, knowing what to log from the extensive list of (security) eventlog types is a challenge on itself.

A logon was attempted using explicit credentials

This is the eventlog ID 4648, that’s the one logging for instance runas and other interesting authentication related activities. Click here to learn more and make sure to check the “Security Monitoring Recommendations” section.

So, where’s my nugget?

The following query leverages the string “TERMSRV” present in some 4648 eventlogs — which surprisingly carry not only the source of an RDP connection, but the target host and user account info.

Below is how this log should look like:

Source: Menasec

Side note: above example log comes from another fantastic resource at MENASEC. Make sure you always link research work from others 😠

The query

In a nutshell, what goes on?

  1. The query filters in only the TS related 4648 events. The loose term (TERMSRV) speed things up (bloom filter) and Additional_Information makes sure the right info is in;
  2. The series of eval take care of data polishing, string normalization, etc;
  3. Dedup ensures only a single source/target tuple is considered;
  4. The appendpipe is not among the most used commands for sure, but perfectly fits the purpose here: performing multiple stats commands over the same results with safe subearches;
  5. In the end, we table only the relevant fields expected by the Sankey chart.

The results

Each vertical below represents either a host (source/target) or a user (source/target).

So following the first line, one could state there was at least one established RDP connection from vdi233 (source host) towards jumphost2 (target host). The source user logged on the source host was whistler, who used awhistler account to authenticate on the target host.

Rendered Sankey chart from a simulation dataset

As you’ve probably guessed, depending on how many hops (jump/bastion hosts) or how chained the RDP flows in your network are, you might need to tweak the search a little bit (extra appendpipes, etc), but this should cover most cases.

BONUS: Use Cases Pot!

After a quick look at the chart, can you spot the inconsistency? All source/target user names look similar, except for one. Are whistler and cosmo users working from the same laptop1 host? Or maybe acosmo (cosmo’s administrative account) is compromised? 😲

As a best practice, a technical user (helpdesk, admins) has multiple accounts, depending on the privilege level. This is pretty common in enterprise environments. And usually, they tend to have the same account pre/suffix. So it makes a good candidate for alerting when things mismatch.

Same holds true in case you want to track every unexpected (source) user holding the credentials for a given (target) service account. Or in case you want to track unwanted flows from jump host back to the users network, for instance.

Further Research

For more in-depth RDP/TS flow tracking via logs, look for events matching “Microsoft-Windows-TerminalServices”. Have a look here and there to know which event codes are relevant as those will provide even more use case potential.

The query is available from GitHub.

Have fun!