Smokest Stealer, a new malware family? Maybe?

tl;dr tl;dr multi-functionality RAT written in Deno JavaScript, oligomorphic mutation, lots of stuff it targets, friends online deobfuscated it. Deobfuscated code:

https://gist.github.com/vxunderground/48a67e51b375b74be953511b9082f732arrow-up-right

January 16th, 2025, MalwareHunterTeamarrow-up-right on Twitter noted the discovery of an unusual malware payload titled "topwebcomicsv1.msi"

After reviewing some of it's functionality on VirusTotal, he noted the malicious sample makes a GET request to:

http://sharecodepro.com/m/8752e5472b9a3a80/main

The URL contains a polymorphic JavaScript payload which relies on the Denoarrow-up-right JavaScript runtime. This is fairly unusual, as noted by both MalwareHunterTeam and myself. I personally cannot recall a time I saw a malware payload using this. Have you?

When you make a GET request you'll notice that on each invocation it does indeed mutate. However, the mutation it uses primarily revolves around variable naming conventions. The core underlying logic does not change. It is more akin to oligomorphicarrow-up-right mutation rather polymorphic mutation.

Previously I shared on Twitter I strongly dislike deobfuscating malicious JavaScript payloads, subsequent to this post several malware degenerates popped out the bushes volunteered, unironically, to de-obfuscating it just for the love of gamearrow-up-right. Hence, security researcher nullVoidPtrarrow-up-right spent her weekend de-obfuscating various malicious JavaScript payloads because ???

Let's look at it now.

First and foremost, each GET request to their C2 delivery URL can demonstrate clear as day their mutation characteristics. It also illustrates how primitive it is. Here is the first couple of lines which we can see change on each GET request:

const _0x224b90 = _0x64fd;
(function (_0x4f1d5e, _0x16bc75) {
    const _0x456e6a = _0x64fd, _0x1f1eea = _0x4f1d5e();
    while (!![]) {
        try {
            const _0x435a48 = parseInt(_0x456e6a(0x2a9)) / 0x1 + -parseInt(_0x456e6a(0x851)) / 0x2 * (-parseInt(_0x456e6a(0xd37)) / 0x3) + parseInt(_0x456e6a(0xdf5)) / 0x4 * (-parseInt(_0x456e6a(0xe19)) / 0x5) + -parseInt(_0x456e6a(0xe34)) / 0x6 * (-parseInt(_0x456e6a(0xa56)) / 0x7) + -parseInt(_0x456e6a(0x371)) / 0x8 + -parseInt(_0x456e6a(0x6ba)) / 0x9 * (-parseInt(_0x456e6a(0x427)) / 0xa) + -parseInt(_0x456e6a(0x6ce)) / 0xb;
            if (_0x435a48 === _0x16bc75)
                break;
            else
                _0x1f1eea['push'](_0x1f1eea['shift']());
        } catch (_0x1c340a) {
            _0x1f1eea['push'](_0x1f1eea['shift']());
        }
    }

As you can see, despite the code changing, the core functionality remains the same. This is classic oligomorphic mutation (not quite hash busting, but pretty damn closearrow-up-right)

When you de-obfuscate the malicious payload (courtesy of nullVoidPtr, I didn't want to deal with it) it unveils a rather large JavaScript stealer. It totals 8,448 lines of code even with a JavaScript beautifier.

The entry point is located on line 8,351.

It makes invocations to console.log ... but it doesn't appear anything is modified in the code base to pipe the output to nothing (???).

The first function call, initializeClient(), builds strings for the malicious domain sharecodepro.com and determines if the URL is active. However, to my surprise, it appears it does not contain any functionality to handle the URL not being active. In the event the C2 is dead the code is basically dead in the water. However, with the URL split code segment it APPEARS the author might INTEND to have multiple domains in the event one is dead. That is not present (yet?).

initializeClient also invokes the function hc() (speculatively thinking "HTTP Client" function?) which builds basic functionality for GET, POST, and WS (Web Socket).

Following the client initialization Smokest creates a mutex to ensure the payload only rules once. This is standard before.

Following this, Smokest creates a unique set of properties to identify the machine by invoking the function getHuidMd5. De-obfuscated it looks like this:

This is used as a unique identifier for the infected host. It used in several other places in the code base for the socket connection and initial registration with the C2:

The logged token (which is used elsewhere for registration) is a JWT (Json Web Token) which can be decoded pretty easily. JWT is Base64 encoded like this:

When Base64 decoded with Powershell:

We get this:

IAT being "Issued At" and EXP being "expired" in Unix timestamp (seconds since January 1st, 1970UTC) we get:

IAT of 2026-01-17 05:39:12 UTC is when I pulled the payload from the sharecodepro. Hence, in the future, we can use the IAT to determine when a host was infected.

Thankfully, and for reasons I still don't understand, the author of Smokest left us plenty of clues as to what it is doing and what it will do next. Here is the console.log invocations (with the middle stuff removed)

The author unironically gave us a tl;dr on what it's going to do, indirectly giving us a step-by-step on what to expect

I guess now we can just reverse engineer the individual functions because now we see the flow control...

The fingerprinting and identification it uses is pretty standard. Some of it derives from Deno, some of it uses the WINAPI.

You can see the invocation to Kernel32!GetComputerNameExW. Why did they name is Kernel324? I have no idea.

Subsequently, Smokest uses User32!GetAsyncKeyState for keylogging and exfiltrates data using sendCommand2().

Regardless, Smokest does contain a bit of interesting functionality. One of the event listeners it establishes allows commands to be sent and received.

Reverse engineering all of this individual commands would take a bit of time, and I've already lost interest in this malware sample. I am actually impressed by it's mutation-like features, how many features are present in Smokest, and it's (current) low detection score on VirusTotal. It using Deno is also an interesting strategy.

Very cool.

The author clearly put quite a bit of effort into the stealer functionality. While it primarily targets Chromium applications, the author has targeted probably every cryptocurrency wallet (and password manager) on the planet (I'm being hyperbolic... or maybe not, I'm not sure).

Last updated