"The packages may be linked to malware discussed in a Threat Intelligence report on OceanLotus," Kaspersky's analysis concluded after finding a novel payload delivered through PyPI in July 2025.
How the PyPI packages were constructed and distributed
Attackers uploaded three projects to PyPI carrying malicious wheel (.whl) packages that imitated benign libraries and tempted users to install them via pip. The observable packages and first upload dates were:
- uuid32-utils — first upload 2025-07-16; pip install uuid32-utils; author masked as laz**** / laz****@tutamail.com
- colorinal (color terminal text) — first upload 2025-07-22; pip install colorinal; author masked as sym**** / sym****@proton.me
- termncolor (ANSI terminal formatting) — first upload 2025-07-22; pip install termncolor; author masked as sym**** / sym****@proton.me
Distribution metadata showed Windows x86/x64 and Linux x86_64 wheel builds. The attacker concealed the real payload by embedding the malicious package as a dependency: termncolor appeared benign but imported the malicious colorinal library.
Initial infection chain and the dropper behavior
Installing colorinal-0.1.7 (Windows example) extracts a dropper file named terminate.dll into the installed library folder. When the colorinal package is imported, the package's __init__.py executes and immediately invokes colorinal/unicode.py. A function named is_color_supported() ostensibly checks terminal color support but instead loads terminate.dll into the Python process and calls its exported function envir, passing the UTF‑8 string xterminalunicod.
The dropper’s envir function performs three tasks: decrypt embedded data with AES-CBC using the passed parameter as the key, deploy the final payload ZiChatBot, and remove the dropper and malicious Python script. Decrypted strings recovered by the dropper include "libcef.dll", "vcpacket", "pkt-update", and "vcpktsvr.exe". The dropper LZMA-decompresses embedded data to produce vcpktsvr.exe and libcef.dll and places them into %LOCALAPPDATA%\\vcpacket.
For persistence, the Windows dropper creates a registry autorun entry under HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run named "pkt-update" that points to the deployed vcpktsvr.exe. The dropper also XOR-decrypts embedded shellcode with key 3a7, patches memory to reference terminate.dll, then redirects execution into that shellcode, which locates API addresses via a djb2-like hash and removes the dropper file.
The Linux wheel mirrors the same Python logic but carries terminate.so and installs a single ELF ZiChatBot binary to /tmp/obsHub/obs-check-update, sets it executable, and creates a crontab entry to run it hourly: 5 * * * * /tmp/obsHub/obs-check-update.
ZiChatBot’s command-and-control: Zulip REST APIs
The final payload, ZiChatBot, consists on Windows of libcef.dll (loaded by vcpktsvr.exe — file hash 48be833b0b0ca1ad3cf99c66dc89c3f4). ZiChatBot does not use traditional C2 servers. Instead, it communicates through public Zulip team chat REST APIs, authenticating requests with a bearer token header included in each HTTP call.
The analysis published the exact authentication header value seen in traffic (base64): TW9yaWFuLWJvdEBoZWxwZXIuenVsaXBjaGF0LmNvbTpVOFJFWGxJNktmOHFYQjlyUXpPUEJpSUE0YnJKNThxRw==. Decoded, this corresponds to: Morian-bot@helper.zulipchat.com:U8REXlI6Kf8qXB9rQzOPBiIA4brJ58qG.
ZiChatBot uses two Zulip channel-topic pairs: one to exfiltrate system information and the other to retrieve a message containing shellcode. When shellcode is received, ZiChatBot spawns a thread to execute it and, after execution, replies to the originating Zulip message with a heart emoji as an execution confirmation.
Infrastructure, remediation actions, and observed impact
The investigators found no traditional attacker infrastructure such as compromised servers or commercial VPS assets. Instead, the attack used PyPI for distribution and Zulip’s public service for C2. Zulip has deactivated the "helper" organization the attacker registered; Kaspersky recommended adding the full URL helper.zulipchat.com to denylists to help contain infected clients that may still try to connect.
The malicious wheels were removed from PyPI after public disclosure and Kaspersky pushed product detections for the relevant files. The company reported no observed infections in its telemetry or through public reporting to date.
Attribution and implications for defenders
Kaspersky submitted samples to its Threat Attribution Engine (KTAE) and reported that the ZiChatBot dropper shows 64% similarity to a previously analyzed dropper linked in a threat intelligence report to OceanLotus. The report also notes OceanLotus’s known targeting focus in the Asia‑Pacific region, a reported expansion into the Middle East, and prior use of GitHub in a phishing campaign during the first half of 2025 — framing the PyPI supply‑chain intrusion as a continuation of that exploration of software distribution channels.
What this means for Python developers, open‑source maintainers, and incident responders
- Python developers and package consumers: Treat newly published packages and similarly named replicas with caution; the campaign demonstrates how a dependency can be used to hide a malicious wheel. Verify package provenance and consider pinning known good hashes where possible.
- Open‑source maintainers and PyPI operators: Monitor for packages that include compiled wheels and unusual binary artifacts; dependency chains can be abused to conceal malicious code in otherwise benign packages.
- Incident responders and Zulip operators: Blocklist helper.zulipchat.com as recommended and search for the listed file paths, autorun registry key ("pkt-update"), and crontab entry (5 * * * * /tmp/obsHub/obs-check-update). Hashes for the malicious wheels and binaries were published with the analysis for detection use.
ZiChatBot’s use of public collaboration infrastructure and packaged Python wheels as a delivery mechanism signals a supply‑chain method that mixes compiled droppers with script-level hooks. The chain — from deceptive PyPI projects to a Zulip‑based C2 and a loader that self‑erases — raises a concrete question for defenders: will adversaries increasingly blend open package registries with public collaboration platforms to hide command channels? For now, the observable facts end with removal from PyPI, deactivation of the Zulip organization, and no confirmed infections in telemetry.
Original report: https://securelist.com/oceanlotus-suspected-pypi-zichatbot-campaign/119603/




