[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f4vjBsH3YmIeuXkOf0DZUn-skoDS58ik1JNDCrGc7b3U":3},{"article":4,"iocs":54},{"id":5,"title":6,"slug":7,"summary":8,"ai_summary":9,"brief":10,"full_text":11,"url":12,"image_url":13,"published_at":14,"ingested_at":15,"relevance_score":16,"entities":17,"category_id":33,"category":34,"article_tags":38},"a6a18297-a164-454c-9689-6ff4d88375ea","OceanLotus suspected of using PyPI to deliver ZiChatBot malware","oceanlotus-suspected-of-using-pypi-to-deliver-zichatbot-malware-e65fb4","Kaspersky researchers uncovered malicious wheel packages in PyPI that targeted both Windows and Linux and contained a dropper delivering malware dubbed ZiChatBot. We attribute this activity to OceanLotus APT.","Kaspersky researchers discovered malicious Python wheel packages on PyPI uploaded starting July 2025, attributed to OceanLotus APT. The packages (uuid32-utils, colorinal, termncolor) acted as droppers delivering ZiChatBot, a previously unknown malware that uses Zulip chat app REST APIs as C2 infrastructure instead of traditional command servers. The attack exemplifies a carefully planned supply chain compromise, with one benign-looking package concealing malicious dependencies.","OceanLotus deploys ZiChatBot malware via malicious PyPI packages targeting Windows and Linux.","Table of Contents IntroductionTechnical detailsSpreadingMalicious wheel packagesInitial infectionWindows versionDropper for ZiChatBotLinux versionZiChatBotInfrastructureVictimsAttributionConclusionsIndicators of compromise Authors GReAT Introduction Through our daily threat hunting, we noticed that, beginning in July 2025, a series of malicious wheel packages were uploaded to PyPI (the Python Package Index). We shared this information with the public security community, and the malware was removed from the repository. We submitted the samples to Kaspersky Threat Attribution Engine (KTAE) for analysis. Based on the results, we believe the packages may be linked to malware discussed in a Threat Intelligence report on OceanLotus. While these wheel packages do implement the features described on their PyPI web pages, their true purpose is to covertly deliver malicious files. These files can be either .DLL or .SO (Linux shared library), indicating the packages’ ability to target both Windows and Linux platforms. They function as droppers, delivering the final payload – a previously unknown malware family that we have named ZiChatBot. Unlike traditional malware, ZiChatBot does not communicate with a dedicated command and control (C2) server, but instead uses a series of REST APIs from the public team chat app Zulip as its C2 infrastructure. To conceal the malicious package containing ZiChatBot, the attacker created another benign-looking package that included the malicious package as a dependency. Based on these facts, we confirm that this campaign is a carefully planned and executed PyPI supply chain attack. Technical details Spreading The attacker created three projects on PyPI and uploaded malicious wheel packages designed to imitate popular libraries, tricking users into downloading them. This is a clear example of a supply chain attack via PyPI. See below for detailed information about the fake libraries and their corresponding wheel packages. Malicious wheel packages The packages added by the attacker and listed on PyPI’s download pages are: uuid32-utils library for generating a 32-character random string as a UUID colorinal library for implementing cross-platform color terminal text termncolor library for ANSI color format for terminal output The key metadata for these packages are as follows: Pip install command File name First upload date Author \u002F Email pip install uuid32-utils uuid32_utils-1.x.x-py3-none-[OS platform].whl 2025-07-16 laz**** \u002F laz****@tutamail.com pip install colorinal colorinal-0.1.7-py3-none-[OS platform].whl 2025-07-22 sym**** \u002F sym****@proton.me pip install termncolor termncolor-3.1.0-py3-none-any.whl 2025-07-22 sym**** \u002F sym****@proton.me Based on the distribution information on the PyPI web page, we can see that it offers X86 and X64 versions for Windows, as well as an x86_64 version for Linux. The colorinal project, for example, provides the following download options: Distribution information of the colorinal project Initial infection The uuid32-utils and colorinal libraries employ similar infection chains and malicious payloads. As a result, this analysis will focus on the colorinal library as a representative example. A quick look at the code of the third library, termncolor, reveals no apparent malicious content. However, it imports the malicious colorinal library as a dependency. This method allows attackers to deeply conceal malware, making the termncolor library appear harmless when distributing it or luring targets. The termncolor library imports the malicious colorinal library During the initial infection stage, the Python code is nearly identical across both Windows and Linux platforms. Here, we analyze the Windows version as an example. Windows version Once a Python user downloads and installs the colorinal-0.1.7-py3-none-win_amd64.whl wheel package file, or installs it using the pip tool, the ZiChatBot’s dropper (a file named terminate.dll) will be extracted from the wheel package and placed on the victim’s hard drive. After that, if the colorinal library is imported into the victim’s project, the Python script file at [Python library installation path]\\colorinal-0.1.7-py3-none-win_amd64\\colorinal\\__init__.py will be executed first. The __init__.py script imports the malicious file unicode.py This Python script imports and executes another script located at [python library install path]\\colorinal-0.1.7-py3-none-win_amd64\\colorinal\\unicode.py. The is_color_supported() function in unicode.py is called immediately. The code loads the dropper into the host Python process The comment in the is_color_supported() function states that the highlighted code checks whether the user’s terminal environment supports color. The code actually loads the terminate.dll file into the Python process and then invokes the DLL’s exported function envir, passing the UTF-8-encoded string xterminalunicod as a parameter. The DLL acts as a dropper, delivering the final payload, ZiChatBot, and then self-deleting. At the end of the is_color_supported() function, the unicode.py script file is also removed. These steps eliminate all malicious files in the library and deploy ZiChatBot. For the Linux platform, the wheel package and the unicode.py Python script are nearly identical to the Windows version. The only difference is that the dropper file is named “terminate.so”. Dropper for ZiChatBot From the previous analysis, we learned that the dropper is loaded into the host Python process by a Python script and then activated. The main logic of the dropper is implemented in the envir export function to achieve three objectives: Deploy ZiChatBot. Establish an auto-run mechanism. Execute shellcode to remove the dropper file (terminate.dll) and the malicious script file from the installed library folder. The dropper first decrypts sensitive strings using AES in CBC mode. The key is the string-type parameter “xterminalunicode” of the exported function. The decrypted strings are “libcef.dll”, “vcpacket”, “pkt-update”, and “vcpktsvr.exe”. Next, the malware uses the same algorithm to decrypt the embedded data related to ZiChatBot. It then decompresses the decrypted data with LZMA to retrieve the files vcpktsvr.exe and libcef.dll associated with ZiChatBot. The malware creates a folder named vcpacket in the system directory %LOCALAPPDATA%, and places these files into it. To establish persistence for ZiChatBot, the dropper creates the following auto-run entry in the registry: [HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run] \"pkt-update\"=\"C:\\Users\\[User name]\\AppData\\Local\\vcpacket\\vcpktsvr.exe\" 12 [HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run]\"pkt-update\"=\"C:\\Users\\[User name]\\AppData\\Local\\vcpacket\\vcpktsvr.exe\" Once preparations are complete, the malware uses the XOR algorithm to decrypt the embedded shellcode with the three-byte key 3a7. It then searches the decrypted shellcode’s memory for the string Policy.dllcppage.dll and replaces it with its own file name, terminate.dll, and redirects execution to the shellcode’s memory space. The shellcode employs a djb2-like hash method to calculate the names of certain APIs and locate their addresses. Using these APIs, it finds the dropper file with the name terminate.dll that was previously passed by the DLL before unloading and deleting it. Linux version The Linux version of the dropper places ZiChatBot in the path \u002Ftmp\u002FobsHub\u002Fobs-check-update and then creates an auto-run job using crontab. Unlike the Windows version, the Linux version of ZiChatBot only consists of one ELF executable file. system(\"chmod +x \u002Ftmp\u002FobsHub\u002Fobs-check-update\") system(\"echo \\\"5 * * * * \u002Ftmp\u002FobsHub\u002Fobs-check-update\" | crontab - \") 12 system(\"chmod +x \u002Ftmp\u002FobsHub\u002Fobs-check-update\") system(\"echo \\\"5 * * * * \u002Ftmp\u002FobsHub\u002Fobs-check-update\" | crontab - \") ZiChatBot The Windows version of ZiChatBot is a DLL file (libcef.dll) that is loaded by the legitimate executable vcpktsvr.exe (hash: 48be833b0b0ca1ad3c","https:\u002F\u002Fsecurelist.com\u002Foceanlotus-suspected-pypi-zichatbot-campaign\u002F119603\u002F","https:\u002F\u002Fmedia.kasperskycontenthub.com\u002Fwp-content\u002Fuploads\u002Fsites\u002F43\u002F2026\u002F04\u002F04194912\u002FSL-OceanLotus-featured.jpg","2026-05-06T13:00:34+00:00","2026-05-06T14:00:15.137787+00:00",9,[18,21,24,27,30],{"name":19,"type":20},"OceanLotus","threat_actor",{"name":22,"type":23},"PyPI supply chain attack (July 2025)","campaign",{"name":25,"type":26},"PyPI (Python Package Index)","technology",{"name":28,"type":29},"Kaspersky","vendor",{"name":31,"type":32},"Zulip","product","26b0b636-0e31-4db1-bffb-61bdf9f20a58",{"id":33,"icon":35,"name":36,"slug":37},null,"Supply Chain","supply-chain",[39,44,49],{"category":40},{"id":41,"icon":35,"name":42,"slug":43},"89f78b1c-3503-45a1-9fc7-e23d2ce1c6d5","Malware","malware",{"category":45},{"id":46,"icon":35,"name":47,"slug":48},"ade75414-7914-4e23-a450-48b64546ee70","Open Source","open-source",{"category":50},{"id":51,"icon":35,"name":52,"slug":53},"e7b231c8-5f79-4465-8d38-1ef13aea5a14","Threat Intelligence","threat-intelligence",[55,58,61],{"type":43,"value":56,"context":57},"ZiChatBot","Previously unknown malware family delivered via PyPI dropper packages",{"type":43,"value":59,"context":60},"terminate.dll","Windows dropper payload loaded into Python process",{"type":43,"value":62,"context":63},"terminate.so","Linux dropper payload equivalent"]