Affected Platforms: Microsoft Windows
Impacted Users: Any organization
Impact: Compromised machines are under the control of the threat actor and stolen information can be used for future attacks
Severity Level: Medium
FortiGuard Labs has encountered a new and active Stealit malware campaign that leverages Node.js’ Single Executable Application (SEA) feature to distribute its payloads. This campaign was uncovered following a spike in detections of a particular Visual Basic script, which was later determined to be a component for persistence.
Earlier Stealit campaigns were built using Electron, an open-source framework that packages Node.js scripts as NSIS installers for distribution. This new campaign has adopted Node.js' native Single Executable Application, which similarly bundles scripts and their assets into standalone binaries. Both approaches are effective for distributing Node.js-based malware, as they allow execution without requiring a pre-installed Node.js runtime or additional dependencies.
Based on the observed filenames, this malware is still being distributed as disguised installers for games and VPN applications, as was the case in previous campaigns. Recent samples we observed are bundled in PyInstaller and common compressed archives and uploaded to file-sharing sites such as Mediafire and Discord.
This blog provides a detailed technical analysis of this new Stealit campaign.
Along with the updated malware binary, Stealit has relocated its panel website to new domains. When we first observed this campaign, the panel—also functioning as the Command-and-Control (C2) server—was hosted at stealituptaded[.]lol. However, that domain quickly became inaccessible as the C2 server was moved to iloveanimals[.]shop.
Accessing the panel leads to a commercial website for Stealit, which promotes itself as offering "professional data extraction solutions" through various subscription plans. A dedicated features page outlines its capabilities, highlighting typical remote access trojan (RAT) functionalities such as file extraction, webcam control, live screen monitoring, and ransomware deployment targeting both Android and Microsoft Windows systems. The site also features instructional videos that demonstrate how the service operates on each platform.
Figure 1: Stealit homepage
The website offers payment plans for the Windows and Android versions of the stealer, with lifetime subscriptions available for approximately $ 500 and $ 2,000, respectively.
Figure 2: Stealit subscription pricing
The service also has a Telegram channel named StealitPublic, where they post updates and promotions to possible clients. The main contact person is a Telegram user with the handle @deceptacle.
Figure 3: A promotional post on StealIt’s Telegram channel
This Stealit’s campaign begins with the installer component that downloads additional components from its C2 server. All of Node.js’s scripts bundled in the executables are heavily obfuscated to complicate analysis.
The installer component involves several layers before the actual main installer script is executed.
As mentioned earlier, this malware campaign distributes the malicious Node.js scripts using the SEA feature.
Node.js SEA is currently an experimental feature that is being actively developed, with the primary purpose of distributing and running Node.js applications as a single executable binary on systems that do not have Node.js installed. As a tradeoff, since all the required application code, dependencies, and assets need to be built into a single executable file, a simple hello world Node.js SEA for Windows could be 85MB in size.
The malicious installer script to be executed by Node.js is stored as a raw data resource (RCDATA) named NODE_SEA_BLOB. In addition to the main script, that resource data also contains the original path of the script before packaging. In the samples we encountered, this path includes a directory named StealIt, strongly suggesting that it belongs to the stealer malware service of the same name. Moreover, the path also includes angablue, which indicates that it was built using AngaBlue — an open-source project that aims to automate the building of Node.js SEA executables.
Figure 4: NODE_SEA_BLOB resource data
The extracted 1.3MB installer script is heavily obfuscated to complicate analysis. In brief, it contains a large blob (~1.2MB) that is later decoded and executed for the second layer.
Figure 5: Second-layer script as an array of encoded strings
At the end of the script, this blob is decoded and executed directly in memory using Node.js’ require function, which is commonly used to import modules.
Figure 6: Code snippet for the decoding and execution of the second layer
Essentially, the second layer is a function object with another large script taken as the second argument. This time, the script is not encoded but is still heavily obfuscated.
The script in the argument, which serves as the third layer, is also executed in memory, following the same method as the second layer.
This stage performs all the functions to install the main components of the malware in the system.
Here is a manually commented code snippet of the third stage, which executes a previously downloaded and decoded component.
Figure 7: Commented code snippet of component execution
The variants we encountered log a detailed execution progress that is visible in the console log when they are run under a debugger.
Figure 8: Malware execution logs under a debugger
In addition to console logging, if this malware is executed with high privileges, it writes the logs to a specific, hardcoded filepath: C:\Users\PC\AppData\Local\errorlx\error.log, creating all the necessary subdirectories beforehand.
If enabled, it performs various checks to detect if it’s running in an analysis environment, categorized based on the type of specific artifacts it’s looking for in the system. These categories are internally referred to as the following:
If two or more of these checks are not satisfied, it determines that it’s inside a virtual setup.
Advanced Process Detection – This check contains logic bugs that result in inaccurate outcomes. However, the intention is to run the wmic process command with the get Name, ProcessId, ExecutablePath, CommandLine /format:csv option to list all running processes and their execution information in the system. It determines if any of the process information contains the following:
These checks are skipped if the running process’s path and process name are on its whitelist. See Appendix: Installer – Process Path Whitelist and Appendix: Installer – Process Name Whitelist
It retrieves the parent process information by running the following command:
wmic process where ProcessId={malware process ID} get Name,CommandLine,ExecutablePath /format:csv
If any of these checks reveal that the malware is being analyzed, it will terminate with the following error message box:
Figure 9: Message box displayed if the anti-analysis check fails
Once it passes through the anti-analysis checks, it proceeds to the actual installation of malware components.
It first writes a base64-encoded authentication key in %temp%\cache.json. This 12-character alphanumeric key is used to authenticate with its C2. This is the same key used by subscribers of the malware service to log in to their dashboards, where they are likely to monitor and control their victims.
Figure 10: Stealit dashboard login page requiring the authentication key
It then proceeds to download the initial components from the following URLs:
The downloaded data are saved to %UserProfile%\Appdata\Local\{word list}\{random alphanumeric}\{filename}.exe.br where:
To prevent Windows Defender from scanning the downloaded files, all the created directories are added to the exemption list by executing the following PowerShell command:
powershell -Command "Add-MpPreference -ExclusionPath {directory}'
The downloaded data are decompressed using the Brotli algorithm and saved in the same directory, following their current filenames without the .br extension. For example, save_data.exe.br is decompressed and saved as save_data.exe.
Similar to the installer, these components are also Node.js scripts packaged as executables. However, while the installer uses Node.js’ official SEA to achieve this, these are packaged using an open-sourced project called Pkg. This tool uses a different implementation that involves actual patching of the official Node.js node.exe to support the execution of the embedded NodeJS scripts.
The files are executed with specific arguments immediately after decompression. Analysis of these components are discussed in the next sections.
Once “game_cache.exe” is downloaded and executed, it creates a Visual Basic script, startup.vbs, which launches it. That script is then placed in the Windows startup folder (i.e., %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\startup.vbs) to ensure that the file is automatically executed upon system startup.
Figure 11: startup.vbs executes game_cache.exe
This component is only downloaded and executed if the malware has been executed with high privileges.
Once this file executes, it drops a file named cache.exe in the same directory and is executed with the following command line:
cache.exe all -o {current directory}\output -v --no-kill
cache.exe is a tool developed from the open-source project ChromElevator, which aims to extract information specifically from Chromium-based browsers. It claims to bypass security features implemented by these browsers, thereby further increasing its chances of success.
Figure 12: ChromElevator usage information
This component extracts information from a long list of applications.
Before it begins gathering information from target applications, it tries to terminate related processes.
Figure 13: Procmon logs show malware trying to terminate targeted applications
It then proceeds to extract information from various browsers, including Google Chrome and Microsoft Edge. For the complete list of target browsers, please see Appendix: Stats_db.exe - Browser Targets. The extracted information is stored in the %Temp%/BrowserData directory.
Aside from browsers, it also extracts information from a variety of applications, including:
This client is responsible for communicating with the command-and-control (C2) server and executing instructions issued by threat actors. It runs using an authentication key passed as an argument.
Initially, this client drops additional components in the victim system in the %Temp% directory, including:
It initially connects to the C2 by sending the following victim information via an HTTP POST request to https[:]//root[.]iloveanimals[.]shop/panelping in JSON format:
- Username
- HWID (Hardware ID)
- Key (for authentication)
Example:
{"pcName":"[username]","hwid":"[UUID]","key":"[12-character key]"}
From here on, it will be waiting for commands from the C2 server.
Based on the functionalities advertised on Stealit’s website, this component can be controlled by the threat actors to perform the following:
Feature |
Description |
Live Screen View |
Stream victim's screen in real-time |
Live Webcam Access |
View camera feed from victim's device |
System Management |
Remote shutdown, restart, or control system behavior |
Ransom Chat Panel |
Communicate directly with the victim |
Fake Alert Message |
Push custom fake system alerts to the victim |
Log Refresh |
Retrieve updated logs instantly without needing re-injection |
CMD Executor |
Send and execute terminal commands live |
Remote Audio Player |
Play any sound or music on victim's device |
EXE Installer + Startup Binder |
Upload, execute, and persist any payload |
File Grabber |
Collect files from Desktop, Documents, Downloads, and other critical paths |
Wallpaper Changer |
Remotely set any image as victim's desktop wallpaper |
Table 1: Stealit features
Within weeks, new Stealit samples reverted to the Electron framework, this time encrypting bundled Node.js scripts with AES-256-GCM. Functionally, they operate the same as the SEA variant described earlier.
This new Stealit campaign leverages the experimental Node.js Single Executable Application (SEA) feature, which is still under active development, to conveniently distribute malicious scripts to systems without Node.js installed. Threat actors behind this may be exploiting the feature’s novelty, relying on the element of surprise, and hoping to catch security applications and malware analysts off guard.
Furthermore, it employs heavy obfuscation and numerous anti-analysis techniques to evade detection and complicate analysis. Once installed, it is capable of controlling the victim’s system and extracting information, including login credentials and cryptocurrency wallets, from a wide variety of applications.
This is an active campaign, and in the course of writing this article, we observed shifts in tactics, including switching back to delivering their payload via the Electron framework and relocating their panels to new domains.
FortiGuard will continue monitoring this threat.
FortiGuard AntiVirus detects the malicious files identified in this report as:
The FortiGuard Web Filtering Service detects the C2 URLs cited in this report as Malicious and blocks them.
Due to the ease of disruption, damage to daily operations, potential impact on an organization's reputation, and the unwanted destruction or release of PII, among other concerns, it is essential to keep all AV and IPS signatures up to date.
We also recommend that organizations have their end users participate in our free NSE training, NSE 1 – Information Security Awareness. It includes a module on internet threats designed to help end users learn how to identify and protect themselves from various types of phishing attacks.
If you believe these or any other cybersecurity threats have impacted your organization, please contact our Global FortiGuard Incident Response Team.
554b318790ad91e330dced927c92974d6c77364ceddfb8c2a2c830d8b58e203c
aa8f0988f1416f6e449b036d5bd1624b793b71d62889afdc4983ee21a1e7ca87
5ea27a10c63d0bbd04dbea5ec08fe0524e794c74d89f92ac6694cfd8df786b1f
083c4e0ffdc9edf0d93655ee4d665c838d2a5431b8064242d93a545bd9ad761b
432b8414113a8c14c0305a562a93ed926e77de351bac235552a59cc02e1e5627
8e1cf254d23e2b94c77294079336339ececf33a3e7ee1a3621ee4e0df0695ce5
919a2107ac27e49cdaa60610706e05edfc99bd3f2e9ca75da4feb6a5f2517c27
e004f8e39e489dec74a13d99836ee5693bd509047ecf49f3fc14efc143a161b5
818350a4fb4146072a25f0467c5c99571c854d58bec30330e7db343bceca008b
8814db9e125d0c2b7489f8c7c3e95adf41f992d4397ed718bda8573cb8fb0e83
24b3def3f374c5f17ec9f1a347c71d9c921155c878ab36e48dd096da418bf782
c38130d7cb43cf3da4858247a751d7b9a3804183db8c4c571b6eede0590474da
https[:]//iloveanimals[.]shop/
https[:]//iloveanimals[.]shop/user/login
https[:]//root[.]iloveanimals[.]shop/download/save_data
https[:]//root[.]iloveanimals[.]shop/download/stats_db
https[:]//root[.]iloveanimals[.]shop/download/game_cache
https[:]//root[.]iloveanimals[.]shop/panelping
https[:]//root[.]stealituptaded[.]lol/download/save_data
https[:]//root[.]stealituptaded[.]lol/download/stats_db
https[:]//root[.]stealituptaded[.]lol/download/game_cache
https[:]//cdn[.]discordapp[.]com/attachments/1395171942494896190/1413957011837816915/VrchatPlugin.rar?ex=68bdd195&is=68bc8015&hm=b9f359a7f75b84d1b860d2aa4dd92f8adad3a2feef5d82832f49d664a256ff7b&
https[:]//www[.]mediafire[.]com/file/9ni7pgjxuw8pc6h/ShaderSetup.rar/file
Https[:]//download1529[.]mediafire[.]com/8006s55pduvgtQ0THBMZxcLtlrh20a5BnfF18n8YfGUB8P7M5U3mEQb-UYYDCrMHsSG0aWvnyy_LIMg2OnTc4kuNYmWzjWLQwOds-qSfhdO03NOQFAAaYCPiOvB8nU7mBEHe-3a5gDSufW6upPbFXyGlbzBTdtpcrVPXokNKOYZ9/c4zbp39q02jvrn8/Aykadia.rar
Browser Extension ID |
Crypto Wallet |
egjidjbpglichdcondbcbdnbeeppgdph |
Trust |
nkbihfbeogaeaoehlefnkodbefgpgknn |
Metamask |
hnfanknocfeofbddgcijnmhnfnkdnaad |
Coinbase |
fhbohimaelbohpjbbldcngcnapndodjp |
BinanceChain |
bfnaelmomeimhlpmgjnjophhpkkoljpa |
Phantom |
ibnejdfjmmkpcnlpebklmnkoeoihofec |
TronLink |
fnjhmkhhmkbjkkabndcnnogagogbneec |
Ronin |
aholpfdialjgjfhomihkjbmgjidlcdno |
Exodus |
aeachknmefphepccionboohckonoeemg |
Coin98 |
bhghoamapcdpbohphigoooaddinpkbai |
Authenticator |
afbcbjpbpfadlkmhmclhkeeodmamcflc |
MathWallet |
ffnbelfdoeiohenkjibnmadjiehjhajb |
YoroiWallet |
hpglfhgfnhbgpjdenjgmdgoeiappafln |
GuardaWallet |
cjelfplplebdjjenllpjcblmjkfcffne |
JaxxxLiberty |
amkmjjmmflddogmhpjloimipbofnfjih |
Wombat |
cgeeodpfagjceefieflmdfphplkenlfk |
EVERWallet |
pdadjkfkgcafgbceimcpbkalnfnepbnk |
KardiaChain |
hmeobnfnfcmdkdcmlblgagmfpfboieaf |
XDEFI |
lpfcbjknijpeeillifnkikgncikgfhdo |
Nami |
aiifbnbfobpmeekipheeijimdpnlpgpp |
TerraStation |
efbglgofoippbgcjepnhiblaibcnclgk |
MartianAptos |
nphplpgoakhhjchkkhmiggakijnkhfnd |
TON |
dmkamcknogkgcdfhhbddcghachkejeap |
Keplr |
hifafgmccdpekplomjjkcfgodnhcellj |
CryptoCom |
ejjladinnckdgjemekebdpeokbikhfci |
PetraAptos |
mcohilncbfahbmgdjkbpemcciiolgcge |
OKX |
fhmfendgdocmcbmfikdcogofphimnkno |
Sollet |
epapihdplajcdnnkdeiahlgigofloibg |
Sender |
opcgpfmipidbgpenhmajoajpbobppdil |
Sui |
khpkpbbcccdmmclmpigdgddabeilkdpd |
SuietSui |
jnlgamecbpmbajjfhmmmlhejkemejdma |
Braavos |
ebfidpplhabeedpnhjnobghokpiioolj |
FewchaMove |
mcbigmjiafegjnnogedioegffbooigli |
EthosSui |
dlcobpjiigpikoobohmabehhmhfoodbb |
ArgentX |
jbdaocneiiinmjbjlgalhcelgbejmnid |
NiftyWallet |
odbfpeeihdkbihmopkbjmoonfanlbfcl |
BraveWallet |
blnieiiffboillknjnepogjhkgnoapac |
EqualWallet |
fihkakfobkmkjojpchpfgcmhfjnmnfpi |
BitAppWallet |
kncchdigobghenbbaddojjnnaogfppfj |
iWallet |
fhilaheimglignddkjgofkcbgekhenbh |
AtomicWallet |
nlbmnnijcnlegkjjpcfjclmcfggfefdm |
MewCx |
nanjmdknhkinifnkgdcggcfnhdaammmj |
GuildWallet |
nkddgncdjgjfcddamfgcmfnlhccnimig |
SaturnWallet |
fnnegphlobjdpkhecapkijjdkgcjhkib |
HarmonyWallet |
mgffkfbidihjpoaomajlbgchddlicgpn |
PaliWallet |
aodkkagnadcbobfpggfnjeongemjbjca |
BoltX |
kpfopkelmapcoipemfendmdcghnegimn |
LiqualityWallet |
dngmlblcodfobpdpecaadgfbcggfjfnm |
MaiarDeFiWallet |
ookjlbkiijinhpmnjffcofjonbfbgaoc |
TempleWallet |
ejbalbakoplchlghecdalmeeeajnimhm |
Metamask |
kjmoohlgokccodicjjfebfomlbljgfhk |
Ronin |
akoiaibnepcedcplijmiamnaigbepmcb |
Yoroi |
ocglkepbibnalbgmbachknglpdipeoio |
Authenticator |
djclckkglechooblngghdinmeemkbgci |
MetaMask |