ESET Research has discovered a cluster of malicious Python projects being distributed in PyPI, the official Python package repository. The threat targets both Windows and Linux systems and usually delivers a custom backdoor. In some cases, the final payload is a variant of the infamous W4SP Stealer, or a simple clipboard monitor to steal cryptocurrency, or both. In May 2023, we reported on another cluster of packages we found on PyPI that delivers password and cryptocurrency stealing malware, but the two clusters appear to be different campaigns.
Key points of this blogpost:
ESET Research discovered 116 malicious packages in PyPI, the official repository of software for the Python programming language, uploaded in 53 projects.
Victims have downloaded these packages over 10,000 times.
Since May 2023, the download rate is more or less 80 per day.
The malware delivers a backdoor capable of remote command execution, exfiltration, and taking screenshots.
The backdoor component is implemented for both Windows, in Python, and Linux, in Go.
In some cases, the W4SP Stealer or a clipboard monitor that steals cryptocurrency, or both, is delivered instead.
PyPI is popular among Python programmers for sharing and downloading code. Since anyone can contribute to the repository, malware – sometimes posing as legitimate, popular code libraries – can appear there. We found 116 files (source distributions and wheels) from 53 projects containing malware. Some package names do look similar to other, legitimate packages, but we believe the main way they are installed by potential victims isn’t via typosquatting, but social engineering, where victims are walked through running pip install package-name to be able to use the “interesting” package for whatever reason.
Over the past year, victims downloaded these files more than 10,000 times; see Figure 1.
Figure 1. Malicious package downloads over the past year from PyPI using pip
PyPI packages can take two forms: source packages, which contain all project source code and are built upon installation, and prebuilt packages (called wheels), which may contain compiled modules for a specific operating system or Python version. Interestingly, in some cases the Python code in the source distribution differs from the built distribution. The former is clean, while the latter contains the malicious code. Python’s package manager, pip, favors a wheel when it’s available rather than a source distribution. As a result, the malicious one gets installed unless explicitly requested otherwise.
We have observed the operators behind this campaign using three techniques to bundle malicious code into Python packages.
Malicious test.py module
The first technique is to place a “test” module with lightly obfuscated code inside the package. Figure 2 shows a test.py file with a function called graby being defined and then called. Notice that the function handles both Windows and Linux systems.
Figure 2. Lightly obfuscated code inside test.py
This test module is imported in the middle of the source code of the package’s main module (__init__.py), so that the malicious code runs whenever the package is imported. Figure 3 shows a module that masquerades as a screenshotter and imports the malicious test.py.
Figure 3. In some packages, the main module imports the malicious code
PowerShell in setup.py
The second technique is to embed PowerShell code in the setup.py file, which is typically run automatically by package managers such as pip to help install Python projects.
Figure 4 shows a PowerShell script that downloads and executes the next stage.
Figure 4. In some packages, a malicious PowerShell script is embedded in the setup.py file
This PowerShell script downloads transfer[.]sh/eyRyPT/Updater.zip into a temporary directory as update.zip. The script then decompresses the ZIP file into C:ProgramData and deletes it from the temporary directory. Next, the script runs the pip program to install dependencies. Finally, it runs the Python code in C:ProgramDataUpdaterserver.pyw.
This technique only works on Windows and will fail to infest Linux systems.
In the package metadata from Figure 4 , you may have noticed that the author of the package is billythegoat356. There have been numerous reports associating this nickname with malicious activities, including an article from Phylum, where they reveal Billy’s potential link to W4SP Stealer.
In the third technique, the operators make no effort to include legitimate code in the package, so that only the malicious code is present, in a lightly obfuscated form. Figure 5 shows two pieces of malicious code for Windows being written into temporary files and then run with pythonw.exe, which is used instead of python.exe so that the code executes without opening a console window.
Figure 5. In some packages, only lightly obfuscated code is present
The next stages are Python packages, scripts, or binary files downloaded from either Dropbox or transfer.sh.
On Windows, persistence is achieved most of the time via a VBScript Encoded (VBE) file, which is an encoded VBScript file, written to %APPDATA%/Pythonenv/pythenenv.vbe. Figure 6 shows cmd.exe hiding the directory %APPDATA%/Pythonenv, running pythenenv.vbe, and then scheduling the VBE file to be run every five minutes under the task MicrosoftWinRaRUtilityTaskB.
Figure 6. Persistence on Windows systems is achieved with a scheduled task
On Linux, persistence is achieved by placing a malicious desktop entry, mate-user-share.desktop, in the ~/.config/autostart/ directory, as seen in Figure 7 . Files located in the autostart directory are executed on each system startup. The desktop entry uses the name of a MATE subproject for its filename, but it’s only to reduce suspicion because it has nothing to do with the desktop environment.
Figure 7. Persistence on Linux systems is achieved via the autostart directory
Figure 7 also shows the module downloads dl.dropbox[.]com/s/u3yn2g7rewly4nc/proclean to ~/.config/.kde/.kdepath. This is probably an effort to impersonate a configuration directory for the KDE Plasma GUI for Linux.
Launching the mate-user-share.desktop file in turn executes the downloaded .kdepath file, which is the Linux executable file containing the backdoor component.
Typically, the final payload is a custom backdoor that allows remote command execution, file exfiltration, and sometimes includes the ability to take screenshots. On Windows the backdoor is implemented in Python.
Figure 8 shows the backdoor creating a TCP socket connection to blazywound.ignorelist[.]com on port 6001. After sending the hostname, MAC address, and username to the C&C server, the backdoor will directly handle some commands or run any other command in a separate process and send back the command output and any error information to the server.
Figure 8. The Python implementation of the backdoor
On Linux, the backdoor is implemented in Go; see Figure 9 .
Figure 9. The Go implementation of the backdoor
In some cases, instead of the backdoor the payload is a variant of the infamous W4SP Stealer, or a simple clipboard monitor that steals cryptocurrency, or both. Figure 10 shows a clipboard monitor targeting Bitcoin, Ethereum, Monero, and Litecoin cryptocurrencies. The malware uses the legitimate pyperclip package to check clipboard content for wallet addresses. If found, the malware copies an attacker-controlled address to the clipboard in the hope that the victim pastes this address instead in a future cryptocurrency transaction.
Figure 10. A simple clipboard monitor implemented in Python
ESET products detect the malicious Python packages as variants of Python/Agent and Python/TrojanDownloader, and the backdoor as Python/Agent.AOY or Linux/Spy.Agent.BB.
Most of the packages were already taken down by PyPI at the time of this research. ESET communicated with PyPI to take action against the remaining ones and all of the known malicious packages are now offline. The full list of 116 packages can be found in our GitHub repository.
It’s worth noting that malware in a PyPI project repository isn’t a security issue with PyPI itself. In fact, the software running PyPI was recently audited by an external firm that assessed that PyPl “conformed to widely accepted best practices”.
PyPI continues to be abused by cyberattackers to compromise Python programmers’ devices. This campaign displays a variety of techniques being used to include malware in Python packages. Python developers should thoroughly vet the code they download, especially checking for these techniques, before installing it on their systems. As well as continuing to abuse the open-source W4SP Stealer, the operators have also deployed a simple, but effective, backdoor. We expect that such abuse of PyPI will continue and advise caution when installing code from any public software repository.
For any inquiries about our research published on WeLiveSecurity, please contact us at firstname.lastname@example.org.ESET Research offers private APT intelligence reports and data feeds. For any inquiries about this service, visit the ESET Threat Intelligence page.
Linux backdoor downloader..
Package with Linux backdoor installer.
Package with Windows backdoor.
Windows persistence installer.
Linux backdoor downloader.
For a full list of malicious packages, see our GitHub malware-ioc repository.
C&C server for backdoor component.
MITRE ATT&CK techniques
This table was built using version 14 of the MITRE ATT&CK framework.
Supply Chain Compromise: Compromise Software Dependencies and Development Tools
Malware is distributed using Python’s PyPl package management service.
Scheduled Task/Job: Scheduled Task
On Windows, persistence is achieved using a scheduled task.
Boot or Logon Autostart Execution: XDG Autostart Entries
On Linux, an autostart entry is created to launch the backdoor when the user logs in.
Masquerading: Match Legitimate Name or Location
On Linux, persistent files have names similar to legitimate software
Credentials from Password Stores: Credentials from Web Browsers
W4SP steals passwords from the installed web browsers.
To steal funds during a cryptocurrency transaction, clipboard data is replaced.
Command and Control
Non-Application Layer Protocol
The backdoor uses an unencrypted binary protocol over TCP.