Brute Ratel - Scandinavian Defence


The opinions expressed in this post is that of the author and absolutely also that of the presenters' employers, parents, pets, governments, mentors, siblings, and the Council of the City of Eugene, Oregon.


Brute Ratel is a so-called "red team" malware created by some Twitter malware developer who claims to be an ex-EDR engineer. Right now, it is most known for being abused by various ransomware gangs and the author lying about that despite extensive proof otherwise. The reverse engineering project was instigated by these reports of abuse by RaaS. More specifically, abuse by Blackcat / ALPHV affiliates were reported by Sophos in private circles on July 1st 2022.

The version being reverse engineered is called "Scandinavian Defence" - the version most commonly abused by TAs. However, other versions (up to the latest as of the time of writing, which is 27/01/2023) are available to this author, and might be discussed at a later date should time permit. However, the work done on the current version is enough to give an in-depth understanding of the way Brute Ratel was designed, and the author's capabilities and lack thereof.

The payload was generated using the same leaked builder that is used extensively by threat actors. The generated format is a blob of position independent code, which takes the following form.




The generated loader is typically a shellcode (which is sometimes later stuffed into a PE file). The shellcode can be decompiled as:

The function decrypt_and_run is a generic PE mapper that passes a context structure to the mapped PE containing the key. A RC4 key is stored in the last 8 bytes of encrypted_payload_followed_by_key, this is used for both payload decryption and config decryption.

It should be noted that the configuration and encrypted payload are initialised on the stack - that is, with a series of mov/push. The reasons for this are likely incompetence from the developer who doesn't know what RIP-relative addressing is.

Inner payload

Inner payload initialisation

The inner payload is a "DLL" file whose entrypoint takes a single pointer to a context structure provided by the outer layer. This context structure takes the following form:

The loader_unmap_ptr and loader_clear1/loader_clear2 are regions that the inner payload would clear and free upon initialisation, this is to clean up traces of the outer layer.

Next, various APIs are initialised and syscall IDs grabbed. They are generic - nothing special to talk about there.

The config is decrypted and stored into the context. This is done by base64 decoding and then RC4-ing with the key appended to the encrypted payload mentioned earlier. The format is as follows.

Each format entry is separated by |, with some supporting arrays that are separated by the character , such as the http host array etc. An example decoded config would be:

Payload communication (encoding layer)

Communication happens over either DoH or HTTP(s). Data is encrypted with a block cipher with the key specified in the config.

HTTPs traffic is just data POST with appended/prepended data alongside custom headers, typical C2 stuff, nothing special.

DNS communication is spread over a series of A/TX requests - A for sending and TX for receiving. For requests of size less than 64 bytes the sequences is as follows:

For requests of size larger than 64 bytes the sequence is as follows:

All data is encrypted with an AES variant, more details will follow.

Payload communication (internal layer)

The communication starts with the following handshake.

Server response: The server response is a base64-encoded string, the decoded variant of which is used for the "auth" parameter of further requests.

After this initial handshake, Brute Ratel loops and sends the check-in request.


Server responses contain base64 encoded and encrypted commands. Commands are separated with "," and are each base64 encoded internally. A max of 50 concurrent commands are supported at a time.


The cryptography used for encrypting communication is a variant of the AES block cipher. The table used is the exact same (though incremented by 1 at rest and "decoded" by subtracting 1 from every entry in the table at runtime). However, the operations are slightly different. An abridged decompilation follows. It should be noted that this author is not an expert at cryptography, and function names designated here might be inaccurate.

Functionalities overview

The following commands are supported by Brute Ratel.

As the author of this post did not consult the brute ratel manual during the process of reverse engineering (except googling one to find out that "CM" stood for "crisis-monitor"), the naming represents the perspective of reverse engineering and likely differs from the perspective of a typical threat actor utilizing the malware.

Copy-pastas, focaccia, lasagna and piccata

There are several commands in Brute Ratel that are interesting. The reasons for them being deemed interesting varies - sometimes it is because it is a paste of GPL2 code that violates the license, sometimes it is because of unique(ly bad) design choices.

The first is the minidump. It is pasted ReactOS code (GPL2). It is important to note that the pasting was done in a remarkably obtuse way.

Decompiled Minidump vs Reactos Minidump

The malware author modified this by changing MinidumpWriteDump to write only several hardcoded streams, and also by making the minidump implementation write to a transacted file instead of to a regular file.

Transaction handling for minidump

Those who do detection engineering can already see the detection opportunities afforded here, and those who do software development can already see the incredible level of incompetence shown by this approach to modifying pasted code.

Likewise, the DCSync code is also copypasted, albeit this time from Github.

Transaction handling for minidump

There is further copypaste of the AD Recon code, also from Github this time.

Transaction handling for minidump

There could be other locations that code are pasted that were not recognised.

The COFF Loader is a bog-standard copy-paste of the implementation by TrustedSec with slight modifications. This can be confirmed by looking at the tail end of the code.

Decompiled COFF Loader cleanup - top: IDA decompilation of Brute Ratel, bottom: code from TrustedSec's repository

Indeed, another licence violation - as far as this author is aware the condition that "redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution" was not met.

SOCKs proxy

Brute ratel has a SOCKs proxy implementation. There is not much that is notable about this, other than that it can use an alternative profile for transmitting data as opposed to the primary communication profile.

Decrypt-and-Encrypt for forwarding

TCP/SMB Listener

Brute Ratel implements a TCP/SMB listener that forwards data from a pipe/socket back to the host. Strangely, the author designed it so that data is decrypted by the payload prior to sending to the C2. The likely reason is, as was suspected of many other design choices, a severe lack of critical thinking.

Decrypt-and-Encrypt for forwarding


Sleep-encrypt has two mode, one we will call "apc-driven" and the other "timer-driven". Both share the similarity of suspending a random thread and stealing its CONTEXT for the purpose of generating fake CONTEXT strugtures. A second thread has a series of APCs that sets the code to RW, encrypts it, applies this fake CONTEXT to the main thread, sleep, restores the CONTEXT, and then decrypt the code and set it back to RX. A pseudocode of the chain follows:

WaitForSingleObject(wait_event) NtProtectVirtualMemory(rw) CryptEncrypt(x) GetContextThread(primary, backup_ctx) SetContextThread(primary, cloned_ctx) WaitForSingleObjectEx(wait_event, wait_time) //will time out when sleep is over CryptDecrypt(x) NtProtectVirtualMemory(rx) SetContextThread(primary, backup_ctx)

The difference lies in the trigger method. The timer uses the pair of RtlCreateTimer/RtlRegisterWait to set this chain up and execute it, whereas the other utilises NtQueueApcThread to do so. Both take place inside a fiber.

Sleep logic

Detection recommendation

The following section will be limited to basic immediately observable detections, as the author of the malware will likely read the post and tweak things based on the detection recommendations mentioned here.


The DoH beaconing behaviour is easily detectable, the pattern is rather unique. This can be done using the information provided above.


Various methods can be used to detect Brute Ratel from an endpoint perspective, however these will be left out to avoid the malware author from realising things that he could not have realised on his own. The shameless self promotion section has more on access to such information.

Final notes

Those are the most notable implementation details one would find reverse engineering Brute Ratel. Overall, we find an unimaginatively copy-pasted mess, with fundamental knowledge one would expect a software engineer (let alone one who is security conscious) to have to be missing, not to mention basic concepts such as "not breaking software licences" to be missing. It is not atypical for malware developers to not pay attention to these as they focus only on their own bottom line and not much more, even when labelled "legitimate red team" offerings.

Shameless self promotion starts here

For access to the fully labelled IDBs and code utilized in the process of reverse engineering Brute Ratel, join the Discord server and DM me for more information about subscription (yes, it is paid). Tired of doing reverse engineering for your job and want to offload it to someone who has the ability to stare at IDA Pro for 18 hours without standing up? We can arrange that too. You can also find me on Twitter and get notifications of upcoming streams and new posts there. Are you a competitor of Brute Ratel who enjoyed watching your competition being ripped apart? You can be next too, don't fret, but you should subscribe to the Patreon anyways to support the work of an independent reverse engineer. Feel free as well to toss a coin to your boymoder @ bc1qen9sqx4c3tyuz90ucflh8tfs2ljmskh9x8zcht if the traditional finance system is not your cup of tea.