Feature #3285


rules: XOR keyword

Added by Brandon Murphy almost 2 years ago. Updated 2 days ago.

In Progress
Target version:


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 -, 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;



Related issues

Related to Feature #2695: websocket supportAssignedJason IshActions
Related to Task #4097: Suricon 2020 brainstormNewVictor JulienActions
Actions #1

Updated by Brandon Murphy almost 2 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.

Actions #2

Updated by Jason Ish almost 2 years ago

Actions #3

Updated by Victor Julien almost 2 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.

Actions #4

Updated by Brandon Murphy almost 2 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;

Actions #5

Updated by Brandon Murphy almost 2 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.

Actions #6

Updated by Simon Dugas over 1 year ago

Here is a first attempt to implement this feature:

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.

Actions #7

Updated by Victor Julien over 1 year ago

  • Status changed from Feedback to In Review
  • Assignee changed from Community Ticket to Simon Dugas
Actions #8

Updated by Jeff Lucovsky 10 months ago

  • Related to Task #4097: Suricon 2020 brainstorm added
Actions #9

Updated by Victor Julien 10 months 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

Actions #10

Updated by Victor Julien 10 months ago

  • Subject changed from XOR keyword to rules: XOR keyword
  • Target version changed from TBD to 7.0rc1
Actions #11

Updated by Victor Julien 18 days ago

Hi Simon, have you looked into doing this as a transform?

Actions #12

Updated by Victor Julien 2 days ago

  • Status changed from In Review to In Progress

Also available in: Atom PDF