Feature #3285
closedrules: XOR keyword
Description
Due to masked WebSocket usage with Masked payloads and XOR in general used by malware for network "encryption", I'm wondering if it would be possible to add support for XOR similar to the existing base64_decode/base64_data keywords.
The only existing method I am aware of for achieving this outcome using existing features is a Lua script/rule. However this depends heavily on user configuration to be useful. Providing an XOR keyword has the benefit of not requiring Lua support and provides a general purpose function that could be used with Masked Payloads within WebSockets and any other network communications using XOR.
WebSocket support has been requested here - https://redmine.openinfosecfoundation.org/issues/2695, but does not directly address the use of Masked Payloads.
An example of keyword usage might be
xor:key <xor key in hex>, bytes <value>, offset <value>, relative;
xor_data;
Thanks
Files
Updated by Brandon Murphy about 5 years ago
Having given a bit more thought, this solution would only work where XOR keys are known. This limitation moves the usefulness of this request to address Masked Paylaods of WebSockets as the XOR Key is supposed to be randomly per each WebSocket frame.
Updated by Jason Ish about 5 years ago
- Related to Feature #2695: websocket support added
Updated by Victor Julien about 5 years ago
- Status changed from New to Feedback
- Assignee set to Community Ticket
- Target version set to TBD
I suppose it would be useful to use the result of byte_extract as input to the key.
Updated by Brandon Murphy about 5 years ago
Adding a real world example of how this will be helpful.
AZORult 3.2 uses a static XOR key to encode network communications. PCAP is attached and taken from Any.Run
See Packet 74 for the initial checkin via POST. This traffic can be decoded as described in this CyberChef Recipe
The Initial Checkin of AZORult uses a unique ID generated from system details as documented by Cylance
Today, as the values change depending on each infected system, detecting the initial checkin is difficult and very prone to false negative, or is based on "circumstantial" detection, or based on post initial checkin activity.
The requested feature would allow for direct detection of this type of CnC communicators.
Using the attached pcap as an example. Here is a rule utilizing the proposed keyword.
alert http $HOME_NET any -> $EXTERNAL_NET any (http.method; content:"POST"; http.uri; content:".php"; endswith; http.request_body; content:"|4a 2f 2b|"; fast_pattern; depth:3; xor: key 0d0ac8, bytes 133, offset 0; xor_data; pcre:"/^G(?:[A-F]|%3[0-9]){7}%2D(?:[A-F]|%3[0-9]){8}%2D(?:[A-F]|%3[0-9]){8}%2D(?:[A-F]|%3[0-9]){8}%2D(?:[A-F]|%3[0-9]){9}$/"; sid:1; rev:1; classtype:command-and-control;)
notice the xor keyword is applied to the http.request_body buffer and xor_data is a sticky buffer.
also, while 133 bytes is longer than the buffer, 133 bytes is the longest possible encoded/xor'ed unique ID.
Note - this rule will cover any of the unique IDs that are G[0-9] when fully decoded. Additional rule(s) would be required to match G[A-F] while maintaining a maybe okish fast pattern;
Updated by Brandon Murphy about 5 years ago
Victor Julien wrote:
I suppose it would be useful to use the result of byte_extract as input to the key.
Yes, that would be very useful. It would address the WebSockets use case and, i've seen more than one sample where malware configs/c2 comms/stage 2 binaries, etc are XOR'ed but the key is at a specific offset in the stream.
Updated by Simon Dugas over 4 years ago
Here is a first attempt to implement this feature:
- https://github.com/OISF/suricata/pull/5015
- https://github.com/OISF/suricata-verify/pull/243
The only difference with the syntax discussed in this issue is the xor key is surrounded in double-quotes when specifying a hex string. This allows us to distinguish it from a byte_extract variable.
Updated by Victor Julien over 4 years ago
- Status changed from Feedback to In Review
- Assignee changed from Community Ticket to Simon Dugas
Updated by Jeff Lucovsky about 4 years ago
- Related to Task #4097: Suricon 2020 brainstorm added
Updated by Victor Julien about 4 years ago
The idea at the 2020 brainstorm call was:
extend byte_extract to allow arbitrary length extract for the key
xor transform keyword that can either take the variable name from byte extract or a static key as input
Updated by Victor Julien about 4 years ago
- Subject changed from XOR keyword to rules: XOR keyword
- Target version changed from TBD to 7.0.0-beta1
Updated by Victor Julien over 3 years ago
Hi Simon, have you looked into doing this as a transform?
Updated by Victor Julien over 3 years ago
- Status changed from In Review to In Progress
Updated by Victor Julien about 3 years ago
- Related to Task #4762: Suricon 2021 brainstorm added
Updated by Philippe Antoine about 3 years ago
- Status changed from In Progress to In Review
Updated by Simon Dugas about 3 years ago
Last time I was looking into transforms they didn't seem to support a "sticky buffer" on the entire TCP payload or holding on to variables such as keys. That was a while ago and I think the transforms API may have improved since then, I'll have a look at catenacyber's PR. I have plenty of test cases and suricata-verify tests that could be useful.
My apologies for the late response.
Updated by Victor Julien about 3 years ago
- Assignee changed from Simon Dugas to Philippe Antoine
Updated by Philippe Antoine almost 3 years ago
- Status changed from In Review to Closed