This blog post on detecting Mimikatz’ DCSync and DCShadow network traffic, accompanies SANS webinar “Detecting DCSync and DCShadow Network Traffic“.
Intro
Mimikatz provides two commands to interact with a Windows Domain Controller and extract or alter data from the Active Directory database.
These two commands are dcsync and dcshadow.
The dcsync command can be used, on any Windows machine, to connect to a domain controller and read data from AD, like dumping all credentials. This is not an exploit or privilege escalation, the necessary credentials are required to be able to do this, for example a golden ticket.
The dcshadow command can be used, on any Windows machine, to connect to a domain controller and write data to AD, like changing a password or adding a user. This too is not an exploit or privilege escalation: proper domain admin credentials are necessary to achieve this.
Both commands rely on the active directory data replication protocol: Directory Replication Service (DRS). This is a protocol (MSRPC / DCE/RPC based) that domain controllers use to replicate their AD database changes between them. The Microsoft API for DRS is DRSUAPI.
Such traffic should only occur between domain controllers. When DRS traffic is detected between a DC and a non-DC (a user workstation for example), alarms should go of.
Alerting
An Intrusion Detection System can detect DRSUAPI traffic with proper rules.

The IDS needs to be positioned inside the network, at a location where traffic between domain controllers and non-domain controllers can be inspected.
DCE/RPC traffic is complex to parse properly. For example, remote procedure calls are done with an integer that identifies the procedure to call. The name of the function, represented as a string for example, is not used in the DCE/RPC protocol. Furthermore, function integers are only unique within an API: for example, function 0 is the DsBind function in the DRSUAPI function, but function 0 is also the DSAPrepareScript in the DSAOP interface.
A very abstract view of such traffic, can be represented like this:

If an IDS would just see or inspect packet B, it would not be able to determine which function is called. Sure, it is function 0, but for which API? Is it DsBind in the DRSUAPI API or is is DSAPrepareScript in the DSAOP interface? Or another one …
So, the IDS needs to keep track of the interfaces that are requested, and then it can correctly determine which functions are requested.
Alerting dcsync
Here is captured dcsync network traffic, visualized with Wireshark (dcerpc display filter):

Frame 28 is our packet A: requesting the DRSUAPI interface
Frame 41 is our packet B: requesting function DsGetNCChanges
Notice that these packets do belong to the same TCP connection (stream 4).
Thus, a rule would be required, that triggers on two different packets. This is not possible in Snort/Suricata: simple rules inspect only one packet.
What is typically done in Suricata for such cases, is to make two rules: one for packet A and one for packet B. And an alert is only generated when rule B triggers after rule A triggers.
This can be done with a flowbit. A flowbit is literally a bit kept in memory by Suricata, that can be set or cleared.
These bits are linked to a flow. Simply put, a flow is a set of packets between the same client and server. It’s more generic than a connection.
Thus, what needs to be done to detect dcsync traffic using a flowbit, is to have two rules:
- Rule 1: detect packet of type A and set flowbit
- Rule 2: detect packet of type B and alert if flowbit is set
Suricata rules that implement such a detection, look like this:
alert tcp $WORKSTATIONS any -> $DCS any (
msg:"Mimikatz DRSUAPI";
flow:established,to_server;
content:"|05 00 0b|"; depth:3;
content:"|35 42 51 e3 06 4b d1 11 ab 04 00 c0 4f c2 dc d2|"; depth:100;
flowbits:set,drsuapi;
flowbits:noalert;
reference:url,blog.didierstevens.com; classtype:policy-violation; sid:1000010; rev:1;)
alert tcp $WORKSTATIONS any -> $DCS any (
msg:"Mimikatz DRSUAPI DsGetNCChanges Request";
flow:established,to_server;
flowbits:isset,drsuapi;
content:"|05 00 00|"; depth:3;
content:"|03 00|"; offset:22; depth:2;
reference:url,blog.didierstevens.com; classtype:policy-violation; sid:1000011; rev:1;)
The first rule (Mimikatz DRSUAPI) is designed to identify a DCERPC Bind to the DRSUAPI API. The packet data has to start with 05 00 0B:

5 is the major version of the protocol, 0 is the minor version, and 0B (11 decimal) is a Bind request.
A UUID is used to identify the DRSUAPI interface (this is not done with a string like DRSUAPI, but with a UUID that uniquely identifies the DRSUAPI interface):

The UUID for DRSUAPI is
e3514235-4b06-11d1-ab04-00c04fc2dcd2
In network packet format, it is
35 42 51 e3 06 4b d1 11 ab 04 00 c0 4f c2 dc d2.
When both content clauses are true, the rule triggers. The action that is triggered, is setting a flowbit named drsuapi:
flowbits:set,drsuapi;
A second action, is to prevent the rule from generating an alert when setting this flowbit:
flowbits:noalert;
This explains the first rule.
The second rule (Mimikatz DRSUAPI DsGetNCChanges Request) is designed to detect packets with a DRSUAPI request for function DsGetNCChanges. The packet data has to start with 05 00 00:

5 is the major version of the protocol, 0 is the minor version, and 00 is an RPC request.
And further down in the packet data (position 22 to be precise) the number of the function is specified:

Number 3 is DRSUAPI function DsGetNCChanges.
When flowbit drsuapi is set and both content clauses are true, the rule triggers.
flowbits:isset,drsuapi;
And an alert is generated.
Notice that the rule names contain the word Mimikatz, but these rules are not specific to Mimikatz: they will also trigger on regular replication traffic between DCs. The key to use these rules properly, is to make them inspect network traffic between domain controllers and non-domain controllers. Replication traffic should only occur between DCs.
Alerting dcshadow
Mimikatz dcshadow command also generates DRSUAPI network traffic, and the rules defined for dcsync also trigger on dcshadow traffic.
One lab in SANS training SEC599, Defeating Advanced Adversaries – Purple Team Tactics & Kill Chain Defenses, covers dcsync and its network traffic detection. If you take this training, you can also try out dcshadow in this lab.
The dcshadow command requires two instances of Mimikatz to run. First, one running as system to setup the RPC server:


And a second one running as domain admin to start the replication:

This push instruction starts the replication:

dcshadow network traffic looks like this in Wireshark (dcerpc display filter):

Notice the DRSUAPI bind requests and the DsGetNCChanges requests -> these will trigger the dcsync rules.
DRSUAPI_REPLICA_ADD is also an interesting function to detect: it adds a replication source. The integer that identifies this function is 5.

A rule to detect this function can be created based on the rule to detect DsGetNCChanges.
What needs to be changed:
- The opnum: 03 00 -> 05 00
- The rule number, sid:1000011 -> sid:1000014 (for example)
- And the rule message (preferably): “Mimikatz DRSUAPI DsGetNCChanges Request” -> “Mimikatz DRSUAPI DRSUAPI_REPLICA_ADD Request”
alert tcp $WORKSTATIONS any -> $DCS any (
msg:"Mimikatz Mimikatz DRSUAPI DRSUAPI_REPLICA_ADD Request";
flow:established,to_server;
flowbits:isset,drsuapi;
content:"|05 00 00|"; depth:3;
content:"|05 00|"; offset:22; depth:2;
reference:url,blog.didierstevens.com; classtype:policy-violation; sid:1000014; rev:1;)
More generic rules
It is also possible to change the flowbit setting rule (rule for packet A), to generate alerts. This is done by removing the following clause:
flowbits:noalert;
Alerts are generated whenever the DRSUAPI interface is bound to, regardless of which function is called.
And a generic rule for a DRSUAPI function call can also be created, by removing the following clause from the DsGetNCChanges rule (for example):
content:”|03 00|”; offset:22; depth:2;
Byte order and DCEPRC
DCERPC is a flexible protocol, that allows different byte orders. A byte order, is the order in which bytes are transmitted over the network. When dealing with integers that are encoded using more than one byte, for example, different orders are possible.
The opnum detected in the dcsync rule, is 3. This integer is encoded with 2 bytes: a most significant byte (00) and a least significant byte (03).
When the byte order is little-endian, the least significant byte (03) is transmitted first, followed by the most significant byte (00). This is what is present in the captured network traffic.
But when the byte order is big-endian, the most significant byte (00) is transmitted first, followed by the least significant byte (03).
And thus, the rules would not trigger for big-endian byte-order.
The byte order is specified by the client in the data representation bytes of the DCERPC packet data:

If the first nibble of the first byte of the data representation is one, the byte order is little-endian.
Big-endian is encoded with nibble value zero.
We have developed rules that check the byte-order, and match the opnum value accordingly:
alert tcp $WORKSTATIONS any -> $DCS any (msg:"Mimikatz DRSUAPI DsGetNCChanges Request"; flow:established,to_server; flowbits:isset,drsuapi; content:"|05 00 00|"; depth:3; byte_test:1,>=,0x10,4; byte_test:1,<=,0x11,4; content:"|03 00|"; offset:22; depth:2; reference:url,blog.didierstevens.com; classtype:policy-violation; sid:1000012; rev:1;)
alert tcp $WORKSTATIONS any -> $DCS any (msg:"Mimikatz DRSUAPI DsGetNCChanges Request"; flow:established,to_server; flowbits:isset,drsuapi; content:"|05 00 00|"; depth:3; byte_test:1,>=,0x00,4; byte_test:1,<=,0x01,4; content:"|00 03|"; offset:22; depth:2; reference:url,blog.didierstevens.com; classtype:policy-violation; sid:1000013; rev:1;)
alert tcp $WORKSTATIONS any -> $DCS any (msg:"Mimikatz DRSUAPI DRSUAPI_REPLICA_ADD Request"; flow:established,to_server; flowbits:isset,drsuapi; content:"|05 00 00|"; depth:3; byte_test:1,>=,0x10,4; byte_test:1,<=,0x11,4; content:"|05 00|"; offset:22; depth:2; reference:url,blog.didierstevens.com; classtype:policy-violation; sid:1000015; rev:1;)
alert tcp $WORKSTATIONS any -> $DCS any (msg:"Mimikatz DRSUAPI DRSUAPI_REPLICA_ADD Request"; flow:established,to_server; flowbits:isset,drsuapi; content:"|05 00 00|"; depth:3; byte_test:1,>=,0x00,4; byte_test:1,<=,0x01,4; content:"|00 05|"; offset:22; depth:2; reference:url,blog.didierstevens.com; classtype:policy-violation; sid:1000016; rev:1;)
Notice that Suricata and Snort can also be configured to enable the dcerpc preprocessor. This allows for the creation of rules that don’t have to take implementation details into account, like byte-order:
alert dcerpc $WORKSTATIONS any -> $DCS any (msg:"Mimikatz DRSUAPI DsGetNCChanges Request"; flow:established,to_server; dce_iface:e3514235-4b06-11d1-ab04-00c04fc2dcd2; dce_opnum:3; reference:url,blog.didierstevens.com; classtype:policy-violation; sid:1000017; rev:1;)
But such rules can have a significantly higher performance impact, because of the extra processing performed by the dcerpc preprocessor.
Conclusion
In this blog post we show how to detect Active Directory replication network traffic. Such traffic is normal between domain controllers, but it should not be detected between a non-domain controller (like a workstation or a member server) and a domain controller. The presence of unexpected DRS traffic, is a strong indication of an ongoing Active Directory attack, like Mimikatz’ DCSync or DCShadow.
The rules we start with operate at a low network layer level (TCP data), but we show how to develop rules at a higher level, that are more versatile and require less attention to implementation details.
Finally, the rules presented in this blog post are alerting rules for a detection system. But they can easily be modified into blocking rules for a prevention system, by replacing the alert action by a drop or reject action.
All the rules presented here can also be found on our IDS rules Github repository.
About the authors
Didier Stevens is a malware expert working for NVISO. Didier is a SANS Internet Storm Center senior handler and Microsoft MVP, and has developed numerous popular tools to assist with malware analysis. You can find Didier on Twitter and LinkedIn.
You can follow NVISO Labs on Twitter to stay up to date on all our future research and publications.