Mystic Stealer signature

Mystic Stealer C2 key exchange.

alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"ET MALWARE Mystic Stealer C2 Client Hello Packet"; flow:established,to_server; flowbits:set, mystic_stealer_conn_init; flowbits:noalert; dsize:4; content:"|b5 19 6f 94|"; fast_pattern; reference:md5,df80b1e50cfebb0c4dbf5ac51c5d7254; reference:url,inquest.net/blog/2023/06/15/mystic-stealer-new-kid-block; reference:url,www.zscaler.com/blogs/security-research/mystic-stealer; classtype:trojan-activity; sid:9999990; rev:1; metadata:created_at 2023_06_02, malware_family Mystic Stealer, signature_severity Major, updated_at 2023_06_02;)

alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"ET MALWARE Mystic Stealer C2 Session Key Response Packet"; flow:established,to_client; flowbits:isset, mystic_stealer_conn_init; dsize:256; reference:md5,df80b1e50cfebb0c4dbf5ac51c5d7254; reference:url,inquest.net/blog/2023/06/15/mystic-stealer-new-kid-block; reference:url,www.zscaler.com/blogs/security-research/mystic-stealer; classtype:trojan-activity; sid:9999991; rev:1; metadata:created_at 2023_06_02, malware_family Mystic Stealer, signature_severity Major, updated_at 2023_06_02;)

Cheers!

1 Like

Thank you for the share, dspruell! The Inquest (your team!) and Zscaler research teams provided a great writeup about Mystic Stealer.

The two Suricata rules provided should be released in our ruleset today. Also, I created a Suricata sig to detect the Admin Panels noted in the blog.

Looking forward to your future shares and blogs!

:hotdog:

2 Likes

Sharing some of ET’s QA notes regarding the submitted Mystic Stealer rules –

2046295 - ET MALWARE Mystic Stealer C2 Session Key Response Packet (malware.rules)

  • Rule was QA’ed. If we omit needed flowbit, the rule alerts a lot and there is an oppurtunity to improve rule performance by adding more content
  • Need to release as disabled to prevent negative ruleset impact

2046294 - ET MALWARE Mystic Stealer C2 Client Hello Packet (malware.rules)

  • Rule was tested and performed well as is.
  • Will release this ruile without “flowbits: noalert” so it alerts on Mystic Stealer activity
  • Flowbit is still set and available for 2046295

If you identify new content to add to 2046295, please let us know and we may move 2046295 from disabled to enabled.

1 Like

Thanks for the feedback! Just to note some detail I didn’t include in the initial post - we intended the rules to be used only as a pair, flagging the successful bidirectional handshake.

When Mystic makes its initial connection to the C2, it sends the 4 byte hello packet, and receives a 256 byte key to be used as the session key for encrypting further transmissions. The first client >> server packet is a simple 4 byte frame on any port, and the server >> client response packet is purely 256 bytes of pseudorandom key material used by the client - it’s unlikely there will be any further opportunity to enhance or tighten that (no structure to it, just raw, random key bytes).

If we omit needed flowbit, the rule alerts a lot and there is an oppurtunity to improve rule performance by adding more content

What makes it necessary to test with omitting the flowbit on 2046295? Hoping to understand that, as my assumption is that as long as the flowbit is left intact, the rule shouldn’t process/alert unless it’s flagging a complete key exchange handshake, which should be only during a C2 event. Is it the case that Suricata doesn’t evaluate the match further if the required flowbit isn’t set on the flow?

To be clear, we took this approach because simply a four byte match on a TCP stream on any port seemed like it could result in some rate of false positives, but the complete handshake seemed a much better data quality prospect.

I appreciate the collaboration and expect I’ll learn more as a result. :mechanical_arm:

2 Likes

Perhaps this does not solve any of the problems listed above, but in my own style I would add a position in the stream.
First rule 2046294:
stream_size: client, =, 5;
stream_size: server,=, 1;

Second rule 2046295:
stream_size: client,=, 5;
stream_size: server, =, 257;

Yes, as I write the rules for the sandbox, such a load on the sensor is quite acceptable for us.

2 Likes

Apologies for the delayed response! I was reflecting on ET’s QA process with @trobinson667 and how it led to us to releasing…

  • “2046294 - ET MALWARE Mystic Stealer C2 Client Hello Packet” as active
  • “2046295 - ET MALWARE Mystic Stealer C2 Session Key Response Packet” as disabled/deactivated.

@trobinson667 shared some great insight that I’d like to share here now.

Before I get started, I want to mentioned I made a mistake. In my previous comment, I said

If we omit needed flowbit, the rule alerts a lot and there is an oppurtunity to improve rule performance by adding more content.

During QA, our process did not omit the flowbit mystic_stealer_conn_init when testing “2046295 - ET MALWARE Mystic Stealer C2 Session Key Response Packet”. Apologies for the confusion my comment caused.

OK, now onto discussing ET QA’s process and why 2046295 was noted as having high check activity by Suricata!

===
TLDR: 2046295 - ET MALWARE Mystic Stealer C2 Session Key Response Packet does not have defined content. As you mentioned and as I understand now, this rule does not have good choices for content as the response packet is gibberish. We can not tighten the rule further.

Suricata will always process/check a rule in the following order: content, flowbits, then other rule options. Given this order, Suricata will not use defined flowbits to ignore rules when checking traffic.

If you would like to ensure Suricata does not check a rule against traffic, please define a fast_pattern content that is unique.

Keep in mind that Suricata will only run a check for a given rule if
1) the selected fast_pattern content appears in the analyzed traffic
2) no content is selected (oh no! This is bad!)

===

The ET QA process uses Suricata Engine’s Rule Profiling stats to determine if a rule is performant, 11.9. Rule Profiling — Suricata 8.0.0-dev documentation. Let’sfocus on the importance of checks and matches and how 2046295 - ET MALWARE Mystic Stealer C2 Session Key Response Packet was considered frequently checked.

A Suricata rule consists of three parts, (6.1. Rules Format — Suricata 6.0.0 documentation):

  • The action, that determines what happens when the signature matches
  • The header, defining the protocol, IP addresses, ports and direction of the rule.
  • The rule options, defining the specifics of the rule

As Suricata runs, it will take a ruleset and split the rules into buckets. These buckets are defined by header criteria like tcp $EXTERNAL_NET any -> $HOME_NET any.

Suppose there is traffic that satisfies a bucket’s header criteria, tcp $EXTERNAL_NET any -> $HOME_NET any. Then, Suricata will evaluate that bucket by iterating through each rule’s determined fast_pattern content THEN its other rule options.

What is a fast_pattern? It is a prefilter keyword placed after a rule’s content. This prefilter keyword only placed after one content value; its placement is explicitly user-defined or implicitly Suricata-defined. If you’d like to learn more about fast_patterns, see : 6.9.1.1. Suricata Fast Pattern Determination Explained — Suricata 6.0.0 documentation.

What are rule options? They are other parts of a rule such as other content or keywords like dsize and flowbits.

Without getting into too much detail, if a rule’s fast_pattern DOES NOT exists in traffic, then the rule is ignored and not checked. However, if the fast_pattern exists or NO CONTENT IS DEFINED AT ALL, then that rule will be checked so its entirety is evaluated for a possible match (e.g. alert) against traffic.

Again, a rule is first checked then it is evaluated completely to determine if there is a match.

Let’s review the provided rules.


Bucket 1: tcp $HOME_NET any -> $EXTERNAL_NET any
(msg:"ET MALWARE Mystic Stealer C2 Client Hello Packet"; flow:established,to_server;
content:"|b5 19 6f 94|"; fast_pattern; 
dsize:4; 
flowbits:set, mystic_stealer_conn_init; 
flowbits:noalert;)

This rule will be checked only if content:“|b5 19 6f 94|”; exists. This rule will be considered a match if dsize:4; is satisfied. After the match occurs, set the flowbit and suppressed the alert.

Bucket 2: tcp $EXTERNAL_NET any -> $HOME_NET any 
(msg:"ET MALWARE Mystic Stealer C2 Session Key Response Packet"; flow:established,to_client; 
flowbits:isset, mystic_stealer_conn_init;
dsize:256;)

This rule does not have defined content, thus no fast_pattern. It will get checked every time Bucket 2’s header crieria is satified against traffic!

However there’s a flowbit present. Does it prevent the checks? No, "in Suricata, flowbits:isset is checked after the fast pattern match but before other content matches. ", 6.35. Differences From Snort — Suricata 6.0.0 documentation

Let’s reword that…

If a rule has flowbits, the flowbits will not be checked first. The determined fast_pattern content will be used, then the flowbits and other rule options (like dsize)

This high check activity is why the rule was released as deactivated.

Instead of treating these rules as a pair, they were released as independent rules. The Mystic Stealer C2 Client Hello Packet rule was performant in QA and so the flowbits:noalert was removed. The flowbit mystic_stealer_conn_init still exists both rules so that anyone that activates" Mystic Stealer C2 Session Key Response Packet" may use both rules.

Let us know if you have any more questions! Answering your question also helped me further understand when flowbits are parsed in Suricata amongst other rule options.

***Additional Notes:
I would like to point out an interesting note about the flow keyword. “The flow keyword can be used to match on direction of the flow”, 6.10. Flow Keywords — Suricata 6.0.0 documentation. And so, this keyword would be considered in a bucket’s header data criteria too.

1 Like

Just added these suggestions to the rules and the changes should appear tomorrow. Thanks @Jane0sint!

1 Like