Python Package Index (PyPI) is the official repository of Python software packages. It is a widely used third-party resource for Python developers to find and install useful libraries and tools for their projects. However, as with any software repository, including GitHub, npm, and RubyGems, PyPI is not immune to attacks from bad actors.
We've previously selected the top 8 malicious packages found on the npm registry. In an effort to surface more awareness of this issue on PyPI, below we cover the top 8 malicious attacks that recently caught the eyes of our security researchers.
Since 2019, Sonatype's security research team have discovered a total of 108,973 packages flagged as malicious, suspicious, or proof-of-concept. We keep you informed about the latest security vulnerabilities and threats in order to keep your build environments protected. We provide you with the information and insights you need to stay one step ahead of the bad actors and keep your projects safe.
PyTorch dependency confusion attack
In December 2022, PyTorch disclosed a malicious dependency posing as a legitimate library in their popular machine learning framework. The attack targeted users who installed PyTorch-nightly via Linux pip between December 25, 2022 and December 30, 2022, and worked using a namespace or dependency confusion tactic.
The attackers registered the package name torchtriton on the official PyPI registry with a high version number. During dependency resolution with Python, PyPI registries generally take precedence over private or alternative registries, so the bad actors used that to their advantage. The payload read various files, including SSH keys and up to 1000 files in the $HOME directory, and exfiltrated information back to a command-and-control (C2) server.
PyTorch renamed the torchtrion package to pytorch-triton, and reserved the package name in PyPI to prevent similar future incidents. Users of the stable release were not affected.
"cobo-python-api" targeted developers using Mac computers
Another attack in PyPI applied dependency confusion attempting to trick developers into downloading a tainted version of the crypto library Cobo Custody Restful in cobo-python-api. The package does not have an official distribution through PyPI, so attackers uploaded a compromised version with the same name, hoping that the package manager (pip) used by developers would prioritize the malicious version over the legitimate GitHub version.
The attackers included the malicious code in setup.py so developers would deploy the malware as soon as they'd run pip install. The code checks the operating system of the computer, and if it is MacOS, it decodes the concatenation of four hexadecimal strings that represent two commands:
that downloads the file slack-helper and makes it executable, and:
that runs the binary slack-helper in the background and discards the output logs.
Four other vendors flagged the binary as malware.
RAT mutants: Information stealers and remote access trojans
In late December 2022 and early January 2023, our security researchers also detected six malicious packages in PyPI that combined the capabilities of a remote access trojan (RAT) and information stealers. We coined them "RAT mutants." These packages were named easytimestamp, pyrologin, discorder, discord-dev, style.py, and pythonstyles.
The malicious packages launched a PowerShell script that fetched a ZIP file and installed libraries that allowed the attacker to control the target's mouse and keyboard and take screenshots. The packages were also stealers, extracting sensitive information such as saved passwords, cryptocurrency wallet data, and cookies. They sought to install cloudflared, a command-line tool for Cloudflare Tunnel, which would allow remote access to the infected machine via a Flask-based application.
Later in January this year, we found this type of malware in four more packages: forenitq, forenith, forenity, and forenitz. After further investigation, we reported them to PyPI to be taken down. The fastest case took about 20 minutes from publication to deletion.
Looking at setup.py in forenitq, we found the following first-stage payload:
The attacker creates three temporary files that download and execute Windows binaries from specific URLs using the "start" command. Even though the slugs /rat and /clip are suggestive of malicious intent, we couldn't confirm that assumption without looking under the hood.
The now inactive page hosted at hxxp://20[.]226[.]18[.] showed a link to a Discord invite that was already expired or private. We noticed that the package was posing as the popular colorama package, using their metadata for a possible StarJacking attempt.
After deobfuscating the RAT file, we found a line that loads a possible clipboard hijacker, but the specifics of it were Base64-encoded:
Upon decoding, we get a Python code designed to hijack a victim's clipboard to replace the intended cryptocurrency wallet address with the attacker's address:
It looks for specified patterns like bitcoin (bc1), Ethereum (0x), Monero (4), and litecoin (L or M or 3), and when a pattern is found, it replaces the intended address with the attacker's cryptocurrency wallet address.
The code uses the pyperclip library to copy and paste clipboard data. It will install the library if it's not already installed and then copy the cryptocurrency wallet address to the clipboard. The code is then set on a continuous loop to monitor the clipboard for wallet address patterns.
Additionally, we uncovered more techniques this RAT mutant uses to evade detection: a first-stage payload added to the file forenitq/ansi.py instead of setup.py, and a second-stage polymorphic payload that changes every time you run the binary.
The attacker also added a new C2 with a very complete help menu in Portuguese:
Many malicious actors are eager to steal your crypto funds and system credentials to further penetrate your infrastructure. Their RAT malware keeps mutating to be more evasive and damaging to serve this malicious purpose.
"pywx": Zooming out to see the malware
In this instance, a package named pywx started by copying a legit package, in this case object_pool, and then injected an import statement to run malicious code from an external source.
At first glance, the setup.py of pywx appeared legitimate, with almost identical fields to the original setup.py of object_pool. The same author, email, and license were all there.
But when you zoom out in the code-editor window, the malicious import injection can be seen, hidden by 321 spaces.
Turning on word wrapping, the malicious code was revealed to be an encoded Base64 string:
And after decoding, we found the following Python script:
This is a Python script that downloads and executes malicious code from a remote URL. The script would often run with pythonw.exe instead of python.exe to avoid opening a console window and keep code execution hidden from the user.
"minimums" doesn't execute in a virtual machine
Threat actors have also been known to design malware that validates the presence of a virtual machine before attempting to execute. One such package was minimums.
The package contained a payload in setup.py that attempts to download a Trojan virus from a rogue server, install it, and log the installation result using a Discord webhook.
Let's take a deeper look:
The malware first checked if the current operating system is Windows. It then checked if the environment was running in a virtual machine or sandbox environment. It did this by validating the presence of specific files associated with VMware and VirtualBox, as well as checking for the presence of certain processes commonly used by security researchers.
If the environment was a virtual machine, the code immediately returned without executing any further.
Next, the code checked whether or not the USERNAME environment variable matched one of the specified usernames (beferg, kimberlyro, amamar, andcoleman, rachestew, ralphgra, raymonke, joehal, pink, victoho, sharonj, etc.) and returned if it does.
Finally, the code attempted to make a request to hxxps[:]//wtfismyip[.]com/text, a site to detect the victim's public IP and verify if it should infect that machine or not. If all validations passed (no VM, no known user, no debugging processes running, no known IP address), the malware downloaded, executed a binary, and then used a Discord webhook to warn the attacker that the module had been installed.
As mentioned before, the purpose of these validations was to avoid executing the payload in a research environment where it could be easily detected.
GTA 5 multihack site linked to the httops package
The httops package caught our attention due to its similarity with the HTTP acronym. The authors of this package possibly tried to accomplish a typosquatting attack, targeting developers who mistyped the name of the package.
Another possibility that our security researchers considered was if an attacker could steal the user's login credentials and API token of a popular PyPI maintainer and potentially add this innocent-sounding library as a dependency. In that case, all the users who installed or updated the popular package could get infected.
Further analysis of httops package's setup.py revealed a payload encoded with Base64:
After decoding, it led to a site hosted on the URL hxxp://54[.]237[.]36[.]60/.
The website, apparently run by a user called "Dark_ZerO," invited people to download cheats for the video game GTA 5. Users might have inadvertently installed some type of backdoor or RAT along with the mods.
Users were prompted to download a file called "Loader.zip" (148 bytes) that, after extraction, created a folder of the same name with no files. After running a few scenarios, our suspicion leaned towards the possibility of a test the bad actor intended to run to see how many users were lured into downloading the "GTA 5 Multihack" before actually conducting their campaign.
Our security researchers reported this malicious package to PyPI, and it was removed shortly thereafter. As gamers increasingly become targets of bad actors, it's always a good idea to avoid downloading pirated video games or cheats. Not only are they illegal, but they can easily turn out to be a playground for bad actors.
Copycat information stealers
We uncovered a series of info-stealers distributed via Python packages on PyPI. The investigation suggested these packages were copycat versions of the notorious W4SP stealer, a piece of malware that has impacted the open source software supply chain since July 2022.
Info-stealers are pieces of malware designed to steal private information, such as passwords, credit cards, and cryptocurrency wallets. We found copycats leveraged the popular W4SP stealer in the form of "Satan Stealer," "Fade Stealer," and now "Creal Stealer." Bad actors use Discord infrastructure for data exfiltration and offer the malware through a malware-as-a-service (MaaS) model.
Developers should be vigilant when installing packages from PyPI. Verify the authenticity of packages and use trusted sources when installing dependencies. In addition, organizations should implement security measures such as automated scanning and monitoring to detect and prevent attacks in their software supply chain.
Thousands of malicious packages drop a Windows trojan via Dropbox
We tracked a malware campaign over a weekend last month and discovered that a threat actor infiltrated PyPI with thousands of malicious packages.
One of the most alarming malicious packages recently uploaded to PyPI downloaded a Windows trojan from Dropbox. The package is one of many published and removed in batches on PyPI. Despite containing contextual terms like "libs" and "nvidiapaypalsuper," these packages were named quite arbitrarily and all contained the description, "A library for creating a terminal user interface."
Upon analysis, all of the packages contained identical payloads targeting Windows users. The setup.py file within these packages contained a one-liner Base64-encoded payload. This malicious code, which invoked a PowerShell command on an infected Windows machine to download second-stage infection from a Dropbox URL, is a Windows trojan with potential spyware and info-stealing code. The malware downloaded two malicious executables, WindowsCache.exe and update.exe, both of which have been identified as malware by VirusTotal.
Interestingly, the threat actor publishing these packages has called themselves 'EsqueleSquad' and mentioned their email address and website, "www.esquelesquad[.]rip" within these packages. However, it is still unclear what the purpose of the attack is, as the packages are named in a confusing manner with no obvious targets.
Dropbox suspended the offending URL, although the malicious copies of the executable can still be obtained from another source. Nonetheless, the influx of these packages in batches is continuing, and researchers are closely monitoring the situation.
Automate protection from software supply chain attacks
The packages mentioned above just scratch the surface of the volume of malware caught by our tools.
Sonatype's system uses ML/AI techniques to recognize unusual attributes for newly published components in public repositories. Data delivered via our tooling's near real-time detection capabilities helps prevent our customers from inadvertently consuming malicious components.
If you want to stay protected from software supply chain attacks, consider Sonatype Repository Firewall to automatically block malicious packages from reaching your development builds.
Written by Sonatype Developer Relations
As Sonatype's Developer Relations team, we empower software developers, infosec practitioners, and DevOps/SRE pros to do their best work.