OceanLotus-attributed ZiChatBot PyPI droppers: uuid32-utils, colorinal, termncolor with Zulip-API C2
Kaspersky GReAT (2026-05-08) re-attributed three PyPI wheels uploaded by an attacker between 2025-07-16 and 2025-07-22 — uuid32-utils, colorinal, and termncolor — to the Vietnam-aligned OceanLotus (APT32) group. The droppers fetch a Windows DLL or Linux .so, persist via Run-key or crontab, and load ZiChatBot, a Python backdoor that uses public Zulip REST APIs as its C2 channel to blend with normal developer traffic.
- Threat actor
- OceanLotus / APT32 (Kaspersky moderate-confidence attribution)
- Detected by
- Kaspersky GReAT · Zscaler ThreatLabz
- Also known as
- ZiChatBot · APT32 PyPI wheel campaign · Zulip-API C2 backdoor
- Ecosystems
- PyPI
- Packages tracked
- 3
What happened
On 2026-05-08 Kaspersky's Global Research and Analysis Team published a re-attribution write-up linking three previously-disclosed malicious PyPI wheels to the Vietnam-aligned OceanLotus (APT32) group. The packages — uuid32-utils, colorinal, and termncolor — were first flagged in August 2025 by Zscaler ThreatLabz as generic supply-chain malware; Kaspersky's KTAE code-similarity engine matched the dropper logic at 64% against known APT32 implants, upgrading the incident from opportunistic crime to suspected state-sponsored espionage.
Campaign
All three wheels were uploaded between 2025-07-16 and 2025-07-22 from a fresh attacker account. uuid32-utils impersonates a 32-character UUID generator, colorinal impersonates a cross-platform terminal-colour utility, and termncolor is a benign-looking wrapper that lists colorinal as a transitive dependency — installing the latter pulls and detonates the former. Recorded download totals before PyPI takedown: uuid32-utils 1,479, colorinal 614, termncolor 387 (Kaspersky tally; Zscaler observed 529 / 355 for colorinal / termncolor in an earlier snapshot).
Payload — DLL sideload + crontab + Zulip C2
The bdist wheels carry a platform-matched dropper: a Windows DLL or a Linux .so. On Windows the dropper sideloads into a benign Python loader, drops a payload into %APPDATA%, and persists via HKCU\Software\Microsoft\Windows\CurrentVersion\Run. On Linux the equivalent path uses a crontab entry to respawn the backdoor on reboot. The implant — Kaspersky-named ZiChatBot — is a Python backdoor whose distinguishing feature is that it has no dedicated C2 server: every command, exfiltration, and heartbeat is funnelled through the public Zulip team-chat REST API (*.zulipchat.com). The attacker created Zulip organisations and channels under throwaway accounts, then used Zulip's OAuth tokens as authenticated C2 — outbound looks like ordinary developer traffic to a Slack-style chat service. Kaspersky reports the Zulip organisations were deactivated after disclosure.
Attribution
Kaspersky's KTAE clustering matched the dropper to OceanLotus / APT32 with moderate confidence at 64% code similarity. OceanLotus has been active since at least 2014 and historically targets Asia-Pacific governments, dissidents, automotive companies, and infrastructure operators with custom backdoors (KerrDown, Ratsnif, Cobalt Strike variants). The 2025-07 PyPI campaign represents a deliberate pivot to the open-source supply chain — APT32 had previously been observed using compromised websites and Skype/Telegram lures, not registry uploads.
Timeline
- 2025-07-10 — earliest attacker activity observed (first malicious commit to staging repos, per ThreatLabz reconstruction)
- 2025-07-16 → 2025-07-22 —
uuid32-utils,colorinal,termncoloruploaded to PyPI in three separate bursts - 2025-08 — Zscaler ThreatLabz publishes the original detection; PyPI removes the packages, Zulip deactivates the C2 organisations
- 2026-05-08 — Kaspersky GReAT publishes the OceanLotus / APT32 re-attribution write-up with KTAE similarity analysis
- 2026-05 → 2026-06 — re-attribution amplified by The Hacker News, GBHackers, GridinSoft, daily.dev, MalwareTips, and others
No CVE / GHSA covers the wave — PyPI security removed the packages but no advisory was created at the time. The Kaspersky write-up and the original Zscaler post are the only structured references; we record the Kaspersky attribution date as published because that is when the campaign became a named, attributed disclosure. Exact published version numbers per package are not enumerated in the public sources beyond Safety DB's record of uuid32-utils reaching 1.0.4; we list inferred initial-publish versions only, and a lockfile match on any version of these three names should be treated as compromise.
Affected packages (3)
- PyPI
colorinal1.0.0 - PyPI
termncolor1.0.0 - PyPI
uuid32-utils1.0.01.0.11.0.21.0.31.0.4
Impact
- Cross-platform persistence: Windows persistence via
HKCU\Software\Microsoft\Windows\CurrentVersion\Run, Linux persistence via acrontabentry that respawns the backdoor on every reboot - DLL sideloading on Windows (
uuid32-utils/colorinal) and ELF.soloading on Linux — both wheel families carry platform-matched droppers inside the bdist ZiChatBotPython backdoor connects to public Zulip REST APIs for command-and-control — perimeter detection that flags rare C2 hostnames will miss this because Zulip is allow-listed in many engineering environments- Sleeper window: ~10 months between PyPI publication (2025-07) and public re-attribution (2026-05-08); any environment that pinned these names in a lockfile during the window has run the backdoor
- Termncolor is a benign wrapper that imports
colorinalas a transitive dependency — a lockfile that only mentionstermncolorstill pulls and executes the malicious payload - OceanLotus / APT32 targeting profile is Asia-Pacific governments, dissidents, and enterprises; Kaspersky scored the dropper at 64% similarity to known APT32 implants in their KTAE engine
What to do
- 1Grep every
requirements.txt,Pipfile.lock,poetry.lock, andpdm.lockin scope foruuid32-utils,colorinal, ortermncolor— all three were removed from PyPI but pinned lockfiles will still attempt to install them from caches / mirrors - 2Quarantine any developer workstation or CI runner that ran
pip installagainst one of the three names between 2025-07-16 and 2026-05-08; assume full host compromise and re-image - 3On Windows, audit
HKCU\Software\Microsoft\Windows\CurrentVersion\Runfor unexpected entries pointing into%APPDATA%or%LOCALAPPDATA% - 4On Linux, audit
crontab -l(per-user) and/etc/cron.d/,/etc/crontabfor unexpected jobs added during the dwell window - 5Egress hunt: outbound to
*.zulipchat.comREST APIs from Python interpreters that should not be using Zulip —ZiChatBotis the only published example of Zulip-as-C2 to date - 6Rotate any credential reachable from a compromised host: SSH keys, cloud tokens (AWS / Azure / GCP), Git tokens, npm/PyPI publish tokens, and browser-stored session cookies
References
- Kaspersky SecurelistOceanLotus suspected of distributing ZiChatBot malware via wheel packages in PyPIsecurelist.com
- The Hacker NewsPyPI Packages Deliver ZiChatBot Malware via Zulip APIs on Windows and Linuxthehackernews.com
- Cyber Security NewsNew ZiChatBot Malware Uses Zulip REST APIs as Command and Control Servercybersecuritynews.com
- GridinSoftPyPI ZiChatBot Packages Linked to Suspected OceanLotus Campaigngridinsoft.com
- GBHackersZiChatBot Malware Abuses Zulip APIs for Stealthy C2 Operationsgbhackers.com
- Safety CLIuuid32-utils — Safety DB version historydata.safetycli.com