In early December, a number of malicious Python packages captured our attention, not just because of their malicious nature, but for the cleverness of their deployment strategy.
The threat actors behind these packages deviated from conventional tactics, introducing a nuanced twist in their approach. The first notable tactic was the exploitation of GitHub, a platform synonymous with trust and reliability within the developer community, to disseminate their malicious code. The packages themselves were mere vessels; the actual malicious content was not embedded within them but distributed through them.
This tactic capitalizes on the confidence developers inherently place in GitHub as a staple source for software tools, adding a layer of deceit to the attackers' scheme and complicating the task for developers in distinguishing between legitimate and suspicious packages.
But that is not the only thing that stands out in this attack attempt. In this blog, we will explain the various combined tactics the attacker used to make these packages stand out.
- A number of Python packages surfaced in December on PyPI, utilizing GitHub as a distribution channel for their malicious code.
- One of the packages combined obfuscation with encryption/decryption techniques to mask the harmful intent within the code.
- One of the packages deployed fileless malware, ensuring stealthy execution without leaving traces on disk and better circumventing modern EDR solutions.
- One of the packages exploited the reputation of the widely-used PySocks project to gain trust and increase the likelihood of their malicious packages being downloaded.
- All packages specifically targeted Windows machines.
The "httprequesthub" Package: A Multiple-Stage Malicious Process
The httprequesthub Python package stands out for its sophisticated multi-stage process, executing malicious code hidden within layers of encryption and obfuscation.
httprequesthub attack flow
The package starts by decoding a Base64 encoded string within its setup.py file, unveiling a URL that points to a GitHub gist created by the threat actor. This gist acts as the first external payload source.
First stage payload in setup.py file
At the time of publication, the user and gist are still active.
Upon accessing the URL, the package retrieves a second-stage payload characterized by complex obfuscated code combined with arbitrary and non-descriptive variables and function names.
The attacker adds a unique twist by mixing the use of obfuscation and encryption to enhance the complexity of the code, making it even more challenging to understand its intent.
After manually simplifying this code, we get this:
Second stage payload after simplifying it.
Another base64 encoded URL within the executed code leads to yet another GitHub gist, deepening the layers of the attack. This GitHub gist and user profile are no longer active.
This phase also includes a specific condition to fetch and execute the code from the second URL only on Windows systems, tailoring the attack based on the victim's OS.
The third stage involves executing Python code from the second URL, which is also obfuscated. Simplifying this code reveals a blend of encryption and obfuscation, with a base64 encoded string undergoing a custom XOR decryption process. This produces a complex, encrypted code block, showcasing the attacker's dedication to concealing their payload's nature.
After again, manually simplifying this code we get this:
Third stage payload after simplifying it.
The sophistication of the attack escalates further with its reliance on fileless execution Instead of the traditional file-based execution, allowing it to bypass modern EDR solutions.
It dynamically allocates memory within the current process and transfers the decoded payload into this space. Utilizing the Windows API via the ctypes module, it manipulates system memory to create an executable thread directly within the memory, circumventing traditional disk-based detection mechanisms. This fileless execution approach is particularly concerning as it leaves no trace on the hard drive, posing a significant challenge for conventional security tools to detect and mitigate.
Given the multi-staged nature of this attack, it is extremely challenging to identify the malicious intent of the package through static analysis alone, even with the aid of machine learning. For such cases, advanced dynamic solutions are necessary alongside static methods to effectively detect such sophisticated threats.
We have yet to fully determine the end goal of this package.
The "easyhttprequest" Mysterious Package, Exploiting the Shadow of a Popular Project
easyhttprequest attack flow
The easyhttprequest Python package employs a deceptive technique by overriding the standard installation process with a custom PostInstall class embedded within its setup.py script. This class is meticulously mapped to the "install" command in the cmdclass dictionary and is designed to execute additional code when the package is installed using the setup.py install command.
Upon installation, the package's first move is to clone a GitHub repository (isaaknikolaev/PySocks) into a temporary directory on the user's system, creating a folder named "PySocks.”
This repository is in fact a fork of the vastly popular "Anorov/PySocks" repository, whose corresponding Python package "pysocks" boasts millions of weekly downloads. This tactic of riding off the reputation of a renowned project is a calculated move to cloak the package's true intent under the guise of a trustworthy source, enhancing its chances of evading detection.
This cloning occurs regardless of the operating system. However, the script includes a condition specifically for Windows systems, where it installs an additional Python package, dulwich (a package used for interacting with Git repositories)
Upon cloning the repository, the package checks the latest commit message for a particular trigger string (uJq93k8bmm7KqjL). If this string is present, the script removes the trigger string, decodes the remaining message, and proceeds to execute the remaining part of the commit message, which is encoded in Base64. This execution step is where the potential for running malicious code lies.
At the time of discovery, no malicious content was found in the commit message of the cloned repository. This could indicate that either the package was intercepted and sanitized before the attacker could deploy their intended malicious code, or the harmful content was never committed. Nevertheless, the structure of the package indicates a clear intent for malicious use, showcasing a sophisticated method of hiding and executing potentially harmful code through a seemingly innocent package installation.