If You Hadn't: Detecting Active Directory Attacks with Suricata

In this article, Caster will demonstrate the capabilities of Suricata signatures to detect attacks against Active Directory.

If You Hadn't: Detecting Active Directory Attacks with Suricata

Active Directory is used in many networks and is often the target of attacks. In this article, I will demonstrate the capabilities of Suricata signatures to detect attacks against Active Directory.

Caster - If You Hadn't

Genre: Defensive
Label: exploit.org
Release Date: 27 May 2024

Performed by: Caster
Written by: Magama Bazarov
Cover Man: Magama Bazarov (Sony ILCE-7M3, f/5.6, 1/3 sec)

Intro

In this research, I will use Suricata to detect attacks against AD and demonstrate the signature writing process. That is, attack detection will take place at the network traffic level. By the way, it is an excellent option for those networks where it is not possible to buy an expensive IDS.

This article will talk about detecting the following attacks:

  1. LLMNR/NBT-NS Poisoning
  2. IPv6 Takeover
  3. LDAP Enumeration & Bruteforce
  4. DCSync
  5. AS-REP Roasting
  6. Kerberos User Enumeration & Bruteforce

LLMNR/NBT-NS Poisoning

One of the most common attacks against Windows machines. The attacker responds to LLMNR/NBT-NS/MDNS requests from legitimate machines and then impersonates the requested hosts. Responder is typically used for this, it automates the process of this attack. As a result of the LLMNR/NBT-NS/MDNS poisoning, the attacker obtains the NetNTLMv2-SSP of the account from which the request was generated.

LLMNR Poisoning Detection

In this case, you can write a signature to detect LLMNR Response packets that an attacker creates to trick Windows machines. An LLMNR Response packet in a Responder attack looks like this:

LLMNR Response Packet

The byte sequence in this packet |80 00 00 01 00 01| indicates that this packet is an LLMNR Response. It is to this byte sequence that the following signature can be written:

alert udp any 5355 -> any any (msg:"LLMNR Response Packet Detected, Possible LLMNR Poisoning"; flow:stateless; content:"|80 00 00 01 00 01|"; sid:1000000; rev:1;)

alert - indicates the type of rule. In this case, alert indicates that a warning will be generated when the rule is triggered;

udp - indicates the transport layer protocol to which the rule will respond. udp indicates that the rule applies to UDP traffic;

any 5355 - Source IP and port parameters. This specifies that the source IP address can be anything and the source port is 5355, which is the standard port for LLMNR;

-> - a direction symbol to indicate that traffic is going from source to destination;

any any - destination IP and port parameters. Indicates that the destination IP and port can be any;

msg: "LLMNR Response Packet Detected, Possible LLMNR Poisoning" is the message that will be displayed when the rule is triggered;

flow:stateless - specifies that traffic processing and inspection is independent of the state of the connection. A common practice for UDP traffic where there is no connection established before sending data, connectionless protocol;

content:"|80 00 00 00 01 00 00 01|" - the content being searched for in the packet, a byte sequence representing a specific part of the LLMNR packet, namely the response, which may be an indicator of an attack;

sid:1000000 -the unique rule identifier (SID, or Signature ID). This is a number that uniquely identifies a rule in a rule set;

rev:1 - indicates the version of the rule. This is a number that is incremented when a rule is updated or modified.

Now to verify that this signature works:

caster@kali:~$ sudo suricata -c /etc/suricata/suricata.yaml -r llmnrnbtnsmdnspoisoning.pcap
i: suricata: This is Suricata version 7.0.3 RELEASE running in USER mode
i: threads: Threads created -> RX: 1 W: 4 FM: 1 FR: 1   Engine started.
i: suricata: Signal Received.  Stopping engine.
W: pcap: 1/5th of packets have an invalid checksum, consider setting pcap-file.checksum-checks variable to no or use '-k none' option on command line.
i: pcap: read 1 file, 185 packets, 25899 bytes
Suricata logs, detection of LLMNR Poisoning

Thus it is possible to detect poisoning attack on the LLMNR protocol using such a Suricata signature.

NBT-NS Poisoning Detection

Similar to the detection of LLMNR Poisoning, the same signature can be written for NBT-NS Poisoning. First we need to understand the structure of the packet that the attacker sends to attack:

NBT-NS Response Packet

The byte sequence |85 00 00 00 00 01| indicates that this is specifically an NBT-NS Response packet. This byte sequence should be used to write a signature to detect suspicious NBT-NS Response packets.

The signature will look like the following:

alert udp any 137 -> any 137 (msg:"NBT-NS Response Packet Detected, Possible NBT-NS Poisoning"; flow:stateless; content:"|85 00 00 00 00 01|"; sid:1000001; rev:1;)

alert - indicates the type of rule. In this case, alert indicates that a warning will be generated when the rule is triggered;

udp - indicates the transport layer protocol to which the rule will respond. udp indicates that the rule applies to UDP traffic;

any 137 -> any 137 are the source and destination network addresses and ports. "any" indicates any IP address, and 137 indicates the port that is used by the NBNS protocol;

msg: "NBT-NS Response Packet Detected, Possible NBT-NS Poisoning" is the message that will be displayed when the rule is triggered;

flow:stateless - specifies that traffic processing and inspection is independent of the state of the connection. A common practice for UDP traffic where there is no connection established before sending data, connectionless protocol;

content:"|85 00 00 00 00 00 00 00 01|" - the content that is being searched for in the packet, a byte sequence representing a specific part of the NBT-NS packet, namely the response, which can be an indicator of an attack;

sid:1000001 - the unique rule identifier (SID, or Signature ID). This is a number that uniquely identifies a rule in a rule set;

rev:1 - indicates the version of the rule. This is a number that is incremented when a rule is updated or modified.

Now to verify that this signature works:

caster@kali:~$ sudo suricata -c /etc/suricata/suricata.yaml -r llmnrnbtnsmdnspoisoning.pcap
i: suricata: This is Suricata version 7.0.3 RELEASE running in USER mode
i: threads: Threads created -> RX: 1 W: 4 FM: 1 FR: 1   Engine started.
i: suricata: Signal Received.  Stopping engine.
W: pcap: 1/5th of packets have an invalid checksum, consider setting pcap-file.checksum-checks variable to no or use '-k none' option on command line.
i: pcap: read 1 file, 185 packets, 25899 bytes
Suricata logs, detection of NBT-NS Poisoning

NBT-NS Poisoning can be detected with such a signature.

MDNS Poisoning Detection

MDNS is also a target for poisoning attack, essentially the same detection principle as in the case of LLMNR/NBT-NS. It is necessary to study the structure of the Response packet that the attacker sends:

MDNS Response Packet

The byte sequence |84 00 00 00 00 01| will indicate that this is an MDNS Response packet. I will write a signature for this byte sequence:

alert udp any 5353 -> any 5353 (msg:"MDNS Response Packet Detected, Possible MDNS Poisoning"; flow:stateless; content:"|84 00 00 00 00 01|"; sid:1000002; rev:1;)

alert - indicates the type of rule. In this case, alert indicates that a warning will be generated when the rule is triggered;

udp - indicates the transport layer protocol to which the rule will respond. udp indicates that the rule applies to UDP traffic;

any 5353 -> any 5353 are the source and destination network addresses and ports. "any" indicates any IP address, and 5353 indicates the port that is used by the MDNS protocol;

msg: "MDNS Response Packet Detected, Possible MDNS Poisoning" is the message that will be displayed when the rule is triggered;

flow:stateless - specifies that the processing and inspection of traffic is independent of the state of the connection. A common practice for UDP traffic where there is no connection established before sending data, connectionless protocol;

content:"|84 00 00 00 00 00 00 00 00 01|" - content that is searched for in the packet, a byte sequence representing a specific part of the MDNS packet, namely the response, which can be an indicator of an attack;

sid:1000002 - the unique rule identifier (SID, or Signature ID). This is a number that uniquely identifies a rule in a rule set;

rev:1 - indicates the version of the rule. This is a number that is incremented when a rule is updated or modified.

Now to verify that this signature works:

caster@kali:~$ sudo suricata -c /etc/suricata/suricata.yaml -r llmnrnbtnsmdnspoisoning.pcap
i: suricata: This is Suricata version 7.0.3 RELEASE running in USER mode
i: threads: Threads created -> RX: 1 W: 4 FM: 1 FR: 1   Engine started.
i: suricata: Signal Received.  Stopping engine.
W: pcap: 1/5th of packets have an invalid checksum, consider setting pcap-file.checksum-checks variable to no or use '-k none' option on command line.
i: pcap: read 1 file, 185 packets, 25899 bytes
Suricata logs, detection of MDNS Poisoning

These are the signatures that can be used to detect attacks on LLMNR/NBT-NS/MDNS protocols using Responder.

IPv6 Takeover

An attack in which an attacker imposes itself as a DNS server at the IPv6 level by sending specially generated DHCPv6 Advertise messages. The problem is that Windows prioritizes IPv6 over IPv4. Therefore, an attacker can intercept DNS queries. Typically, mitm6 is used for this attack.

RA Guard will not prevent this attack

It is through DHCPv6 messages that the attacker imposes itself as a DNS server, mitm6 can be run with the --no-ra flag, so RA Guard will not be an effective solution to combat mitm6.

DHCPv6 Packet Types

The DHCPv6 protocol has the following message types:

  • DHCPv6 Solicit: This message is initiated by the client to start communication with DHCPv6 servers. The client broadcasts or multicasts this message to discover available DHCP servers on the network. Upon receiving a Solicit message, DHCPv6 servers may respond with a DHCP Advertise message offering their configuration.
  • DHCPv6 Advertise: This message is sent by the DHCPv6 server in response to a DHCPv6 Solicit message from the client. It informs the client that the server is available to provide configuration settings, such as default gateway and DNS server.
  • DHCPv6 Request: After receiving a DHCPv6 Advertise message, the client selects a DHCPv6 server and sends a DHCPv6 Request message to formally request the proposed settings. This message can also be used to confirm or update previously received configuration settings when the device reconnects to the network.
  • DHCPv6 Reply: The DHCPv6 Reply message is used by the server to confirm the provisioning or updating of an IP address and other configuration parameters to a device. It can also be sent by the server in response to a DHCP Release message from a client when the client releases a leased IP address.

Attack Deconstruction

To write a signature, you need to clearly understand what static elements may be in the packet that could indicate suspicious activity. Let's look at a DHCPv6 Advertise packet from the attacker's machine.

The |02| byte indicates that this is specifically a DHCPv6 Advertise packet. The presence of a DHCPv6 Advertise in the user segment is itself an anomaly, because this type of DHCPv6 message is sent only by a DHCPv6 server, which is not normally located on the user segment.

Advertise package type information from RFC 8415

Based on this element in the DHCPv6 packet you can write a signature, it will look like this:

alert udp any any -> any 546 (msg:"Suspicious DHCPv6 Advertise Packet Detected, Possible attack using mitm6"; content:"|02|"; depth:1; sid:1000008; rev:1;)

alert - indicates the type of rule. In this case, alert indicates that a warning will be generated when the rule is triggered;

udp - indicates the transport layer protocol to which the rule will respond. udp indicates that the rule applies to UDP traffic;

any any -> any 546 - the first any indicates any source IP address, the second any indicates any source port, the arrow -> indicates the direction of traffic from source to destination, the third any indicates any destination IP address, 546 indicates the destination port, which is the standard port for DHCPv6 clients;

msg: "Suspicious DHCPv6 Advertise Packet Detected, Possible attack using mitm6" is the message that will be displayed when the rule is triggered;

content:"|02|" is an indication of the specific packet content that must be detected for the rule to be triggered. |02| means that the rule is looking for a packet that has the byte 02 in the specified position. An entry in the form |02| is used to denote a hexadecimal value in the content.

depth:1 - specifies how deep in the packet to search for the specified content means that only the first byte of the packet should be checked;

sid:1000008 - the unique rule identifier (SID, or Signature ID). This is a number that uniquely identifies a rule in a rule set;

rev:1 - indicates the version of the rule. This is a number that is incremented when the rule is updated or modified.

Verify that the signature works:

caster@kali:~$ sudo suricata -c /etc/suricata/suricata.yaml -r mitm6.pcap
i: suricata: This is Suricata version 7.0.3 RELEASE running in USER mode
i: threads: Threads created -> RX: 1 W: 4 FM: 1 FR: 1   Engine started.
i: suricata: Signal Received.  Stopping engine.
i: pcap: read 1 file, 91 packets, 8006 bytes
Suricata logs, DHCPv6 Advertise packet detection

In this way, it is possible to detect attacks using mitm6.

LDAP Attacks

LDAP can also be a target for an attacker. It can be used in the initial collection of domain information, and there are also bruteforce attacks on accounts via LDAP.

Enumeration Detection

Like I said, LDAP can be used to gather domain information. In my lab network, I will be using the windapsearch tool. I will renumber the accounts, and then I need to examine the traffic recorded at the time of the attack.

caster@kali:~/windapsearch$ python3 windapsearch.py --dc-ip 10.10.150.131 -u [email protected] -p Password123 --da
Traffic dump during LDAP enumeration

An LDAP search request is a request to search for information in the LDAP directory. This query is used to retrieve entries from the directory that match certain criteria.

LDAP Search requests have a Scope of Search:

  • Base Object: Only the specified base object is searched.
  • Single Level: The search is performed one level below the specified base object.
  • Whole Subtree: The search covers the entire subtree starting from the specified base object and including all its subordinate objects.

In my case windapsearch relies specifically on WholeSubtree to collect data:

WholeSubtree

With WholeSubtree, an attacker can obtain information about all objects in a directory, including users, groups, security policies, and other resources. The byte sequence 0a 01 02 0a 01 00 indicates that this is a WholeSubtree.

The signature will look as follows:

alert tcp any any -> any 389 (msg:"An LDAP Search Request packet with WholeSubtree was detected, a possible Active Directory domain reconnaissance."; content:"|0a 01 02 0a 01 00|"; depth:38; sid:100005; rev:1;)

alert - signature keyword indicating that an alert should be generated if the specified conditions are met;


tcp - the protocol to be analyzed (TCP);


any any - indicates that the traffic source can be any IP address and any port;


-> - indicates the direction of traffic from source to destination;


any 389 - the destination IP address can be any IP address, but the destination; port must be 389 (the standard port for LDAP);


msg:"An LDAP Search Request packet with WholeSubtree was detected, a possible Active Directory domain reconnaissance." - message that will be displayed when the rule is triggered;


content:"|0a 01 02 0a 01 00|" - the content signature to search for in the packet;


depth:38 - indicates that this pattern should be found in the first 38 bytes of the packet. This helps to reduce false positives by checking only a certain part of the packet;


sid:1000005 - the unique rule identifier (SID, or Signature ID). This is a number that uniquely identifies a rule in a rule set;


rev:1 - indicates the version of the rule. This is a number that is incremented when a rule is updated or modified.

Checking signature operation:

caster@kali:~$ sudo suricata -c /etc/suricata/suricata.yaml -r windapsearch-da.pcap
i: suricata: This is Suricata version 7.0.3 RELEASE running in USER mode
i: threads: Threads created -> RX: 1 W: 4 FM: 1 FR: 1   Engine started.
i: suricata: Signal Received.  Stopping engine.
i: pcap: read 1 file, 1793 packets, 822860 bytes
Suricata logs, detection of LDAP Enumeration (WholeSubtree)

Bruteforce Detection

Bruteforce attack is also possible against the LDAP protocol. In this case, you can get by with a rule that will detect 70 packets in 1 minute, which would indicate LDAP bruteforcing or port scanning against LDAP.

alert tcp any any -> any 389 (msg:"Potential LDAP bruteforce attack"; flow:to_server; threshold: type threshold, track by_src, count 70, seconds 60; sid:1000006; rev:1;)

alert tcp any any -> any 389 - this part specifies that the rule applies to TCP traffic from any source IP address and any source port to any destination IP address and destination port 389;

msg:"Potential LDAP bruteforce attack - message that will be displayed when the rule is triggered;

flow:to_server - this specifies the direction of the traffic. In this case, it indicates that the rule should inspect traffic flowing to the server;

threshold: type threshold, track by_src, count 70, seconds 60 - this sets the conditions for triggering the rule. It specifies a threshold where the rule will trigger if there are 70 or more connections (count 70) from the same source IP address (track by_src) to the destination within a 60-second period (seconds 60). This is indicative of a potential brute force attack, where multiple authentication attempts are made in a short time frame;

sid:1000006 - this is the Signature ID (SID) for the rule, a unique identifier for the rule;

rev:1 - this indicates the revision number of the rule, which is used for version control.

caster@kali:~$ sudo suricata -c /etc/suricata/suricata.yaml -r ldapbruteforce.pcap
i: suricata: This is Suricata version 7.0.3 RELEASE running in USER mode
i: threads: Threads created -> RX: 1 W: 4 FM: 1 FR: 1   Engine started.
i: suricata: Signal Received.  Stopping engine.
i: pcap: read 1 file, 1785 packets, 191901 bytes
Suricata logs, detection of LDAP Bruteforce

For LDAPS:

alert tcp any any -> any 636 (msg:"Potential LDAPS bruteforce attack"; flow:to_server; threshold: type threshold, track by_src, count 70, seconds 60; sid:1000007; rev:1;)

LDAP attacks can be detected with these signatures.

DCSync

One of the post-exploitation techniques. The DCSync attack is one of the attack techniques against Active Directory (AD) infrastructure used to extract user password hashes from a domain. This attack exploits standard data replication mechanisms between domain controllers in AD. This DCSync attack allows an attacker to emulate the behavior of a domain controller and request AD to replicate data.

This attack is performed using Mimikatz or Impacket (secretsdump)

Traffic analysis

You need to analysis the traffic to figure out exactly what to write a signature for.

DCERPC Traffic

There's an interesting picture emerging here. First of all, it involves a Bind request to use the DRSUAPI interface. Secondly, DRSUAPI in turn is the interface for managing data replication in Active Directory.

Then we come to the second interesting packet - DsGetNCChanges request DsGetNCChanges is the primary mechanism for requesting data replication in Active Directory. In a DCSync attack, an attacker uses this request to retrieve sensitive data such as user password hashes.

Signature Writing

I think it is these suspicious packets that you can write signatures for. However, a single rule will not be enough as we need to capture two packets. Therefore, we will have to bind them by flowbit

First, a special rule is needed to detect the Bind request and use the DRSUAPI interface.

Byte sequences for Bind requests and DRSUAPI UUID

The byte sequence |05 00 0b| indicates the DCERPC protocol version, minor version and also indicates that this is a Bind request.

|05| - version;

|00| - version (minor);

|0b| - Bind request;

Then the byte sequence 35 42 51 e3 06 4b d1 11 ab 04 00 c0 4f c2 dc d2 points to the UUID of the DRSUAPI interface. The presence of this sequence in the packet indicates the use of DRSUAPI, which is natural to a DCSync attack:

DRSUAPI interface UUID in bytes

The first rule for DCSync discovery would look like this:

alert tcp any any -> any any (msg:"DRSUAPI interface usage detected"; flowbits:set,drsuapi; flowbits:noalert; 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; sid:1000003; rev:1;)

alert - indicates the type of rule. In this case it is "alert", which means that it creates an alert when the corresponding packet is detected;

tcp - the protocol to which the rule applies. In this case it is TCP;

any any -> any any - specifies the source and destination addresses and ports. "any any" means that the rule applies to all IP addresses and ports of both source and destination.

msg: "DRSUAPI interface usage detected" - the message that will be output when the rule is triggered;

flowbits:set,drsuapi - use flowbits to set a bit named "drsuapi";

flowbits:noalert - specifies that this rule should not generate alerts on its own, even if its conditions are met. This is necessary in this case because we need a second rule for accurate detection;

content:"|05 00 0b|" - the content signature to search for in the packet;

depth:3 - specifies that the above content check should be performed in the first 3 bytes of the packet payload;

content:"|35 42 51 e3 06 4b d1 11 ab 04 00 c0 4f c2 dc d2|" - another content signature to look for in the packet;

depth:100 - indicates that the above content check should be performed in the first 100 bytes of the packet payload;

sid:1000003 - the unique rule identifier (SID, or Signature ID). This is a number that uniquely identifies a rule in a rule set;

rev:1 - indicates the version of the rule. This is a number that is incremented when a rule is updated or modified.

Now a second rule is needed.

DsGetNCChanges request packet

The byte sequence |05 00 00| indicates that this is specifically an RPC request

|05| - version;

|00| - minor version;

|00| - RPC request.

Then another byte sequence: |03 00| - opnum 3 indicates that this is specifically a DsGetNCChanges function. The signature for detecting DsGetNCChanges would be as follows:

alert tcp any any -> any any (msg:"DsGetNCChanges request packet was detected. Possible DCSync attack"; flowbits:isset,drsuapi; content:"|05 00 00|"; depth:3; content:"|03 00|"; offset:22; depth:2; sid:1000004; rev:1;)

alert tcp any any -> any any - specifies that this rule applies to any TCP packets that can be sent from any port to any port;

msg:"DsGetNCChanges request packet was detected. Possible DCSync attack" - indicates that the corresponding message will be displayed when the rule is triggered;

flowbits:isset,drsuapi - the rule checks if the flowbits variable named drsuapi is set. Flowbits is used to track status and exchange information between rules. If the drsuapi variable was set by another rule earlier, then the first rule to detect the use of the DRSUAPI interface;

content:"|05 00 00|" - indicates that the rule is looking for the byte sequence 05 00 00 in the packet;

depth:3 - the search depth is limited to the first three bytes of the packet. This means that content:"|05 00 00|" must be found in the first three bytes of the packet;

content:"|03 00|" - indicates that the rule is looking for the byte sequence 03 00 in the packet;

offset:22 - indicates that the search for the 03 00 sequence starts at the 22nd byte of the packet. A more precise search for this sequence reduces the number of false positives. Without offset:22, the rule would be less specific and could trigger on other packets containing 03 00 anywhere. Using an offset makes the rule more precise and specific to the target traffic;

depth:2 - the search depth of the second byte sequence is limited to two bytes starting at the 22nd byte of the packet;

sid:1000004 - the unique rule identifier (SID, or Signature ID). This is a number that uniquely identifies a rule in a rule set;

rev:1 - indicates the version of the rule. This is a number that is incremented when a rule is updated or modified.

Now to verify that the signature works:

caster@kali:~$ sudo suricata -c /etc/suricata/suricata.yaml -r dcsync.pcap
i: suricata: This is Suricata version 7.0.3 RELEASE running in USER mode
i: threads: Threads created -> RX: 1 W: 4 FM: 1 FR: 1   Engine started.
i: suricata: Signal Received.  Stopping engine.
W: pcap: 1/1th of packets have an invalid checksum, consider setting pcap-file.checksum-checks variable to no or use '-k none' option on command line.
i: pcap: read 1 file, 96 packets, 33650 bytes
Suricata logs, detection of DCSync Attack

This is how you can detect a DCSync attack by tracking the use of the DRSUAPI interface and the DsGetNCChanges packet.

AS-REP Roasting

AS-REP Roasting - is a Kerberos protocol attack method that targets Active Directory accounts that have pre-authentication disabled.

How this attack works

I'll explain this attack briefly. It is conducted in several stages:

  • AS-REP Request: The attack begins by sending an authentication request (AS-REQ) on behalf of an account that does not require a Pre-Authentication mechanism. Such accounts are specifically configured without requiring Pre-Authentication to simplify the attack process;
  • AS-REP Response: The domain controller responds (AS-REP) and includes an encrypted TGT (Ticket Granting Ticket) that is encrypted using the account password hash;
  • Hash Extraction: An attacker intercepts this AS-REP response and extracts encrypted data from it, which can be thought of as a hash of the account password;
  • Hash analysis: The obtained hash can be brute-force or rainbow tables attacked to obtain the account password.

AS-REP Roasting (impacket-GetNPUsers)

First, I will run an AS-REP Roasting attack using impacket-GetNPUsers to analyze the traffic:

caster@kali:~/kerberos-research$ impacket-GetNPUsers -dc-ip 192.168.0.71 myownsummer.org/ -usersfile usernames.txt -format hashcat -outputfile hashes.txt
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation

[email protected]:c494472eb2709a075425bdea0b4518a6$57a21fd2f10f707590048d8bcc23463abffef99ed0705b62bb8c04dabf156ef55153d04d83b960ad106777afda3dc21589b55616f1849c5e691e5a947668ffaf1ad27a35d7d1d4ee6e8b37fc7a764a86f9d5e761d2a0952260683fa847fdfa175dd3940321d14961ca428883be81837c89d358c0344c58d83eac327b5667efcb0443ad5d2c20a398d318897fc9a6522b6d3a57410989e07db5ba1b1a5be52d5e70e84ff0372b39291fc01a7d5b8e7a3fb3a7f34d56c13a5b0b3c2c2605bfcf3741696d7f3239ec20fd4643967f010f6c293ffdb974d3bb7867c6b0cc0541c21c8981f0aac073947e659b8a968612a51fee52
[email protected]:551a7700665fdc828ec80d10f566cf4c$e4ab451eae086256c57c91ebb993bb9c3b255d8ff716bdcdcc589a932c3494e35a8649fe7c6b6049abbddbf2c409ed48d9807f9bf2b70cc46486149637ad577c26df4ee6cc1015a08365812d8355cca593b256adf47eb227f8a1e083b93652635f961617f5d4144c0e25f70e27f5e8f782ebc08bc0934776d1edb30c120405d3ae04a474b7611574b8f724a9c45ae057448dacf4a0f6f7b38fa8ad879158ce12dba086190d6e3cf93ba214d5a8c182217b874aefaa284331f5dbd16a059768643079b1a6fa6a26e39e5f3c4a981cf630819dd04c3b18f6e399a93a22fc19a66b8e66553bdff2c6cfe669a29d35e83cf3dbc9

In my case, only two users of the myownsummer.org domain have pre-authentication disabled, which is the point of AS-REP Roasting.

Analysis of the AS-REQ packet. This byte sequence a0 07 03 05 00 50 80 00 00 a1 indicates the body of the AS-REQ request:

KRB AS-REQ Body

Also worth noting is krbtgt, this string is a key indicator because krbtgt is the account name of the Kerberos Ticket Granting Ticket (TGT) service. In AS-REP Roasting attacks, the attacker attempts to obtain encrypted data for this account to then attempt to crack passwords. The string krbtgt is pointed to by the byte sequence 6b 72 62 74 67 74

krbtgt string

I wrote the following signature to detect AS-REP Roasting:

alert tcp any any -> any 88 (msg:"Suspicious Kerberos Packet, Possible AS-REP Roasting attack"; flow: to_server, stateless; content:"|a0 07 03 05 00 50 80 00 00 a1|"; content:"|6b 72 62 74 67 74|"; fast_pattern; content:!"|a2 03 02 01 0c|"; sid:1000008; rev:1;)

alert - indicates that an alert will be generated when the rule is triggered;

tcp - indicates that the rule applies to TCP traffic;

any any -> any 88 - the rule will apply to any source IP address and port and any target IP address on port 88, which is the default port for Kerberos;

msg:"Suspicious Kerberos Packet, Possible AS-REP Roasting attack" - message that will be output when the signature is triggered. In this case, the message indicates a possible AS-REP Roasting attack;

flow: to_server, stateless;:

  • flow: to_server - specifies that the signature should only trigger on traffic directed to the server;
  • stateless - indicates that the signature operates without regard to the state of the connection;

content:"|a0 07 03 05 00 50 80 00 00 a1|" - sequence of bytes indicating the body of the AS-REQ request;

content:"|6b 72 62 74 67 74|"; fast_pattern;:

  • content:"|6b 72 62 74 67 74|" - points to the string krbtgt
  • fast_pattern - indicates that this string is used for quick matching at the beginning of the packet content check;

content:!"|a2 03 02 01 0c|";:

  • ! - means a negative condition, i.e. the rule should work if the specified sequence is not present in the packet;
  • a2 03 02 01 0c - is a sequence of bytes indicating the presence of pre-authentication. The absence of this sequence indicate the possibility of an AS-REP Roasting attack.

sid:100001 - unique signature identifier;

rev:1 - signature version indicating its revision

Verify that this signature works:

caster@kali:~/kerberos-research$ sudo suricata -c /etc/suricata/suricata.yaml -r asreproasting-impacket.pcap
i: suricata: This is Suricata version 7.0.3 RELEASE running in USER mode
i: threads: Threads created -> RX: 1 W: 4 FM: 1 FR: 1   Engine started.
i: suricata: Signal Received.  Stopping engine.
W: pcap: 1/1th of packets have an invalid checksum, consider setting pcap-file.checksum-checks variable to no or use '-k none' option on command line.
i: pcap: read 1 file, 198 packets, 22824 bytes

This is the signature that can be used to detect AS-REP Roasting using impacket-GetNPUsers.

Why does the absence of bytes a2 03 02 01 01 01 01 0c indicate no pre-authentication?

Kerberos uses pre-authentication to prevent certain types of attacks. When pre-authentication is enabled, the client must include a timestamp encrypted with the user's key in its AS-REQ request. This timestamp is then verified by the domain controller to confirm the authenticity of the request.

Kerberos uses ASN.1 (Abstract Syntax Notation One) to encode its messages. In the case of pre-authentication, a certain structure is included in the AS-REQ request, which may look like the following:

a2 - Context-specific tag.
03 - Length of the following byte sequence (3 bytes).
02 01 0c - INTEGER value 12 (0x0c) indicating the use of pre-authentication.

a2 03 02 01 0c

If pre-authentication is disabled, this structure will be missing from the AS-REQ request. Therefore, searching for the absence of this byte sequence allows you to identify accounts that have pre-authentication disabled, making them vulnerable to AS-REP Roasting attacks.

Thus, the content:!"|a2 03 02 01 0c|" element in the signature indicates the lack of pre-authentication in the AS-REQ request, which is an indicator of vulnerability to AS-REP Roasting attacks.

AS-REP Roasting Attack (Rubeus)

During AS-REP Roasting attack using Rubeus I noticed that the byte sequence for AS-REQ body is slightly different from the byte sequence for AS-REQ body when I run impacket-GetNPUsers I think it has to do with the peculiarities of the implementation of these tools.

Rubeus
KRB AS-REQ byte sequence (Rubeus)
KRB AS-REQ byte sequence (impacket-GetNPUsers)

In fact, the signature for AS-REP Roasting when using Rubeus is not much different from the signature for AS-REP Roasting when using impacket-GetNPUsers:

alert tcp any any -> any 88 (msg:"Suspicious Kerberos Packet, Possible AS-REP Roasting attack (Rubeus)"; flow: to_server, stateless; content:"|a0 07 03 05 00 40 80 00 10 a1|"; content:"|6b 72 62 74 67 74|"; fast_pattern; content:!"|a2 03 02 01 0c|"; sid:100002; rev:1;)

Checking this signature:

caster@kali:~/kerberos-research$ sudo suricata -c /etc/suricata/suricata.yaml -r asreproast-rubeus.pcap 
i: suricata: This is Suricata version 7.0.3 RELEASE running in USER mode
i: threads: Threads created -> RX: 1 W: 4 FM: 1 FR: 1   Engine started.
i: suricata: Signal Received.  Stopping engine.
W: pcap: 1/7th of packets have an invalid checksum, consider setting pcap-file.checksum-checks variable to no or use '-k none' option on command line.
i: pcap: read 1 file, 286 packets, 339846 bytes
Detected AS-REP Roasting (Rubeus)

Kerberos User Enumeration & Bruteforce

On the network, an attacker can perform user enumeration using kerbrute, also use it to perform Password Spray attacks, password brute force, etc.

But the problem for the attacker is that kerbrute requires AS-REQ packets to be sent, and this happens at a very fast speed. This can be a jumping off point for signature writing, because for example 10 AS-REQs sent in 30 seconds is an anomalous behavior that network engineers will pay attention to.

Here is an example of a kerbrute exploit in which the attacker searched for existing users in an Active Directory domain.

caster@kali:~/kerberos-research$ ./kerbrute userenum --dc dc01.myownsummer.org -d myownsummer.org usernames.txt

    __             __               __     
   / /_____  _____/ /_  _______  __/ /____ 
  / //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
 / ,< /  __/ /  / /_/ / /  / /_/ / /_/  __/
/_/|_|\___/_/  /_.___/_/   \__,_/\__/\___/                                        

Version: v1.0.3 (9dad6e1) - 05/18/24 - Ronnie Flathers @ropnop

2024/05/18 21:10:43 >  Using KDC(s):
2024/05/18 21:10:43 >  	dc01.myownsummer.org:88

2024/05/18 21:10:44 >  [+] VALID USERNAME:	 [email protected]
2024/05/18 21:10:44 >  [+] VALID USERNAME:	 [email protected]
2024/05/18 21:10:44 >  Done! Tested 22 usernames (2 valid) in 0.591 seconds
Kerberos User Enumeration (kerbrute)
Abundance of AS-REQ packets on the air

This number of AS-REQ packets in a few seconds is an anomalous behavior in the network. The following signature can be written on this to track anomalous AS-REQ within the network.

alert udp any any -> any 88 (msg:"Kerberos High Rate of KRB-AS-REQ, Possible User Enumeration/Bruteforce Attack"; content:"|a1 03 02 01 05 a2 03 02 01 0a|"; threshold:type limit, track by_src, count 10, seconds 30; sid:100000; rev:1;)

alert - indicates that an alert will be generated when the rule is triggered;

udp - indicates that the rule applies to UDP traffic;

any any -> any 88 - the rule will apply to any source IP address and port and any target IP address on port 88, which is the default port for Kerberos

msg:"Kerberos High Rate of KRB-AS-REQ, Possible User Enumeration/Bruteforce Attack" - a message when a rule is triggered. Indicates a high frequency of KRB-AS-REQ requests, which may indicate user enumeration or a bruteforce attack;

content:"|a1 03 02 01 05 a2 03 02 01 0a|" - byte sequence indicating that this is a KRB-AS-REQ packet;

KRB AS-REQ header bytes

threshold:type limit, track by_src, count 10, seconds 30:

  • threshold - indicates the thresholds for triggering the rule;
  • type limit - limit on the number of triggers;
  • track by_src - track by source (number of requests from each source);
  • count 10 - triggers if the number of requests exceeds 10;
  • seconds 30 - time period for tracking requests (30 seconds);

sid:100000 - unique signature identifier;

rev:1 - signature version indicating its revision.

Verify the operation of this signature:

caster@kali:~/kerberos-research$ sudo suricata -c /etc/suricata/suricata.yaml -r kerbruteusernum.pcap 
i: suricata: This is Suricata version 7.0.3 RELEASE running in USER mode
i: threads: Threads created -> RX: 1 W: 4 FM: 1 FR: 1   Engine started.
i: suricata: Signal Received.  Stopping engine.
i: pcap: read 1 file, 64 packets, 10435 bytes
Kerberos user enumeration detection

This is how you can detect Kerberos user enumeration/bruteforce using the Suricata signature.

Outro

In this research, I demonstrated the capabilities of Suricata signatures to detect attacks on Active Directory.

Subscribe to exploit.org

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
[email protected]
Subscribe