Feed
HighPublished 8 May 20263 packages · 7 versions

OceanLotus-attributed ZiChatBot PyPI droppers: uuid32-utils, colorinal, termncolor with Zulip-API C2

Summary

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.

typosquatinfostealercredential-theftobfuscationdormant-domain
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, termncolor uploaded 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)

  • PyPIcolorinal
    1.0.0
  • PyPItermncolor
    1.0.0
  • PyPIuuid32-utils
    1.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 a crontab entry that respawns the backdoor on every reboot
  • DLL sideloading on Windows (uuid32-utils / colorinal) and ELF .so loading on Linux — both wheel families carry platform-matched droppers inside the bdist
  • ZiChatBot Python 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 colorinal as a transitive dependency — a lockfile that only mentions termncolor still 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

  1. 1Grep every requirements.txt, Pipfile.lock, poetry.lock, and pdm.lock in scope for uuid32-utils, colorinal, or termncolor — all three were removed from PyPI but pinned lockfiles will still attempt to install them from caches / mirrors
  2. 2Quarantine any developer workstation or CI runner that ran pip install against one of the three names between 2025-07-16 and 2026-05-08; assume full host compromise and re-image
  3. 3On Windows, audit HKCU\Software\Microsoft\Windows\CurrentVersion\Run for unexpected entries pointing into %APPDATA% or %LOCALAPPDATA%
  4. 4On Linux, audit crontab -l (per-user) and /etc/cron.d/, /etc/crontab for unexpected jobs added during the dwell window
  5. 5Egress hunt: outbound to *.zulipchat.com REST APIs from Python interpreters that should not be using Zulip — ZiChatBot is the only published example of Zulip-as-C2 to date
  6. 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

pypi-2026-05-08-oceanlotus-zichatbot-zulip-c2