OceanLotus (APT32) PyPI Supply Chain Campaign — ZiChatBot Cross-Platform Malware via uuid32-utils, termncolor & colorinal Wheels Using Zulip REST API for C2 — Threadlinqs Intelligence
As of 2026-05-30, OceanLotus (APT32) PyPI Supply Chain Campaign — ZiChatBot Cross-Platform Malware via uuid32-utils, termncolor & colorinal Wheels Using Zulip REST API for C2 is a high-severity malware threat attributed to APT32 (Vietnam), tracked by Threadlinqs Intelligence with 9 detection rules (Splunk SPL, Microsoft KQL, Sigma) and 42 indicators of compromise.
Threat ID: TL-2026-0467 · Severity: HIGH · Status: MONITORING · Category: MALWARE
Attribution: APT32 · Vietnam · ESPIONAGE
Kaspersky GReAT attributed a PyPI supply chain campaign to OceanLotus (APT32) involving three malicious wheel packages — uuid32-utils, termncolor and colorinal — uploaded between 10-22 July 2025 that
Overview
--------
Between 10 July and 22 July 2025, three malicious Python wheel packages were published to the Python Package Index (PyPI) by accounts laz**** (tutamail.com) and sym**** (proton.me): uuid32-utils (multiple 1.x.x versions), colorinal 0.1.7 and termncolor 3.1.0. termncolor depends on colorinal so installing termncolor pulls in the malicious chain; uuid32-utils carries the dropper directly. colorinal had ~529 downloads and termncolor ~355 downloads before removal. All three packages were taken down by PyPI maintainers, and the attacker-controlled Zulip organisation "helper" (helper.zulipchat.com) was officially deactivated by Kandra Labs. Kaspersky's Securelist disclosure on 6 May 2026 attributed the campaign to OceanLotus (APT32) — a Vietnam-aligned espionage group — based on a 64% similarity match between the dropped loader's decryption/decompression logic and a known OceanLotus dropper, surfaced by Kaspersky's Threat Attribution Engine. The malware family was named ZiChatBot for its use of the Zulip Chat platform as command and control.
Windows Infection Chain
------------------------
1. The user runs `pip install termncolor` (or installs uuid32-utils). The wheel registers `colorinal\unicode.py` which is imported by `__init__.py`.
2. `is_color_supported()` in unicode.py loads the bundled native module `terminate.dll` into the running Python process and invokes the exported function `envir` with the parameter `xterminalunicod` (UTF-8 encoded).
3. terminate.dll AES-CBC decrypts an embedded blob and drops two files into `%LOCALAPPDATA%\vcpacket\` — a legitimate signed Microsoft binary `vcpktsvr.exe` (the side-loading host) and the malicious `libcef.dll` (the ZiChatBot payload).
4. vcpktsvr.exe is launched, side-loads libcef.dll, and ZiChatBot begins execution.
5. Persistence is established by writing the registry value `HKCU\Software\Microsoft\Windows\CurrentVersion\Run\pkt-update` pointing to `%LOCALAPPDATA%\vcpacket\vcpktsvr.exe`.
6. The dropper and unicode.py self-delete to reduce forensic surface.
Linux Infection Chain
---------------------
1. The Linux variant of the wheel ships terminate.so (and a variant Backward.so) which performs the equivalent decryption stage.
2. The ELF payload is dropped to `/tmp/obsHub/obs-check-update`.
3. Persistence is established with the user crontab entry: `5 * * * * /tmp/obsHub/obs-check-update`.
ZiChatBot — C2 over Zulip
-------------------------
Unlike traditional malware ZiChatBot does not contact dedicated attacker infrastructure. Instead it authenticates to the Zulip Cloud REST API at `https://helper.zulipchat.com/api/v1/` using a hard-coded base64-embedded credential that decodes to `Morian-bot@helper.zulipchat.com:U8REXlI6Kf8qXB9rQzOPBiIA4brJ58qG`. It uses two fixed channel/topic pairs: one for posting harvested system information from the victim and one for fetching shellcode tasking. Shellcode is XOR-decoded with the three-byte key `3a7` and executed reflectively in the host process. The bot supports a single command — "execute shellcode received from server" — and acknowledges successful execution by sending the heart emoji (`:heart:`) reaction back to the C2 message. Strings, imports and configuration are protected with AES-CBC. Forensic analysis of the Zulip organisation showed three active operator users and 90,692 messages exchanged from 10 July 2025 onward.
Attribution
-----------
Kaspersky Threat Attribution Engine reported a 64% similarity score between ZiChatBot's loader code (decryption and decompression routines, control-flow markers and string obfuscation) and a known OceanLotus dropper. OceanLotus (also tracked as APT32, SeaLotus, APT-C-00, Cobalt Kitty, Ocean Buffalo) is a Vietnam-nexus espionage actor with a long history of supply chain abuse, watering-hole operations and signed-binary side-loading targeting ASEAN governments, dissidents, automotive and pharmaceutical sectors. The choice of Zulip as a C2 channel is novel for the actor and represent
Weaknesses (CWE)
CWE-506, CWE-829, CWE-1357, CWE-494
Target sectors: technology, software-development, open-source, government, defense, telecommunications, automotive, pharmaceutical, research-academia
Target regions: Southeast Asia, ASEAN, North America, Europe, Global (developer ecosystem)
Detections & IOCs
As of 2026-07-28, this threat has 9 detection rule(s) across Splunk SPL, Microsoft KQL and Sigma, and 42 indicator(s) of compromise. Detection query text and full IOC values are available to authenticated users and programmatically via the Threadlinqs MCP server (Purple tier). View plans.
MALWARE, HIGH, threat intelligence, cybersecurity, T1195, T1195.002, T1059.006, T1106, T1204.002, T1547.001, T1053.003, T1574.002, T1027, T1140