Site icon API Security Blog

Two more malicious Python packages in the PyPI

![](https://media.kasperskycontenthub.com/wp-content/uploads/sites/43/2022/08/16112454/python_threat_featured-990×400.jpg)

On August 8, CheckPoint [published a report]() on ten malicious Python packages in the Python Package Index (PyPI), the most popular Python repository among software developers. The malicious packages were intended to steal developers’ personal data and credentials.

Following this research, we used our internal automated system for monitoring open-source repositories and discovered two other malicious Python packages in the PyPI. They were masquerading as one of the most popular open-source packages named “[requests]()”.

[![](https://media.kasperskycontenthub.com/wp-content/uploads/sites/43/2022/08/16082334/Two_more_malicious_Python_packages_in_the_PyPI_01.png)]()

Timeline of uploaded packages:

**Package name** | **Version** | **Timestamp (UTC)**
—|—|—
pyquest | 2.28.1 | 2022-07-30 10:11:47.000
pyquest | 2.28.2 | 2022-07-30 10:15:28.000
pyquest | 2.28.3 | 2022-07-30 10:19:14.000
ultrarequests | 2.28.3 | 2022-07-30 10:25:41.000

The attacker used a description of the legitimate “requests” package in order to trick victims into installing a malicious one. The description contains faked statistics, as if the package was installed 230 million times in a month and has more than 48000 “stars” on GitHub. The project description also references the web pages of the original “requests” package, as well as the author’s email. All mentions of the legitimate package’s name have been replaced with the name of the malicious one.

[![](https://media.kasperskycontenthub.com/wp-content/uploads/sites/43/2022/08/16082726/Two_more_malicious_Python_packages_in_the_PyPI_02-985×1024.png)]()

After downloading the malicious packages, it becomes clear that the source code is nearly identical to the code of the legitimate “requests” package, except for one file: exception.py. In the malicious package, this script was last modified on July 30, exactly on the date of publication of the malicious package.

[![](https://media.kasperskycontenthub.com/wp-content/uploads/sites/43/2022/08/16082831/Two_more_malicious_Python_packages_in_the_PyPI_04.png)]()

[![](https://media.kasperskycontenthub.com/wp-content/uploads/sites/43/2022/08/16082939/Two_more_malicious_Python_packages_in_the_PyPI_09-1024×401.png)]()

The malicious payload is a Base64-encoded Python script hidden in the “HTTPError” class. The script writes another Python one-liner script into a temporary file and then runs that file via the system.start() function. Then that one-liner script downloads the next-stage script from https://zerotwo-best-waifu[.]online/778112985743251/wap/enner/injector and executes it.

[![](https://media.kasperskycontenthub.com/wp-content/uploads/sites/43/2022/08/16083030/Two_more_malicious_Python_packages_in_the_PyPI_06.png)]()

## Downloader

The next stage is a downloader obfuscated with a publicly available tool named [Hyperion](). Obfuscation is done using multiple techniques, such as renaming variables and library functions, adding mixed boolean-arithmetic expressions and junk code, and compressing the code chunks with the zlib library.

The downloader terminates if the OS name is not “nt” (Windows). It randomly selects one of the directories under C:Users<username>AppDataRoaming or C:Users<username>AppDataLocal, generates a random eight-characters string consisting of the “bcdefghijklmnopqrstuvwxyz” characters and randomly picks one of extensions from the following list:

[‘.dll’, ‘.png’, ‘.jpg’, ‘.gay’, ‘.ink’, ‘.url’, ‘.jar’, ‘.tmp’, ‘.db’, ‘.cfg’]

Then the malware downloads the final stage payload from https://zerotwo-best-waifu[.]online/778112985743251/wap/shatlegay/stealer123365, saves it to the previously generated location and executes it.

[![](https://media.kasperskycontenthub.com/wp-content/uploads/sites/43/2022/08/16082909/Two_more_malicious_Python_packages_in_the_PyPI_05.png)]()

In order to achieve persistence on the infected machine, the malware creates a registry value with name “Realtek HD Audio Universal Service” in the HKCUSOFTWAREMicrosoftWindowsCurrentVersionRun Windows system registry branch.

The script searches for an existing executable in the %system32% directory, named SecurityHealthSystray.exe or the SystemSettingsAdminFlows.exe, adds a “&” character (to ensure sequential execution in a command-line string), and then adds the location of the Python interpreter with the location of the malicious script. It is worth noting that this method does not work properly, as the system starts only the first executable, and the persistence is not actually achieved.

C:WindowsSystem32 &

[![](https://media.kasperskycontenthub.com/wp-content/uploads/sites/43/2022/08/16083358/Two_more_malicious_Python_packages_in_the_PyPI_08-1024×236.png)]()

## Final payload: W4SP Stealer

The final payload is a Trojan written in Python and obfuscated with the same obfuscator as the downloader. The malware is dubbed “W4SP Stealer” by its author in the code.

Upon launching, the stealer identifies the external IP address of the victim’s machine by making a GET request to https://api.ipify.org and installs two legitimate PyPI packages – “requests” and “pycryptodome” in order to send exfiltrated data to the operator and work with cryptography for decrypting cookies and passwords from browsers. Then the malware starts collecting Discord tokens, saved cookies and passwords from browsers in separate threads.

[![](https://media.kasperskycontenthub.com/wp-content/uploads/sites/43/2022/08/16083500/Two_more_malicious_Python_packages_in_the_PyPI_07.png)]()

Collected passwords and cookies are stored in the files %TEMP%wppassw.txt and %TEMP%wpcook.txt in the following format:

UR1: | U53RN4M3: | P455W0RD:

H057 K3Y: | N4M3: | V41U3:

All files created by the stealer on the victim’s machine start with the line: “<-W4SP STEALER ON TOP->”. All collected data is sent to the operator via a Discord webhook ([.]com/api/webhooks/1001296979948740648/4wqCErLU3BVeKWnxDA70Gns5vcfxh5OCb3YDIFZaFujqfSRIwHH4YIu3aLOVWjCDeO1H) and rendered in a prettified format:

[![](https://media.kasperskycontenthub.com/wp-content/uploads/sites/43/2022/08/16082757/Two_more_malicious_Python_packages_in_the_PyPI_03.png)]()

The stealer also creates and sends a list of saved browser credentials for the URLs containing keywords “mail”, “card”, “bank”, “buy”, “sell”, etc. (see Appendix for a full list). Apart from that, it gathers data from the MetaMask, Atomic and Exodus wallets, as well as Steam and Minecraft credentials.

Having collected credentials, the stealer starts traversing the victim’s directories named Downloads, Documents and Desktop, looking for filenames containing the following words:

‘passw’, ‘mdp’, ‘motdepasse’, ‘mot de passe’, ‘login’, ‘paypal’,
‘banque’, ‘account’, ‘metamask’, ‘wallet’, ‘crypto’, ‘exodus’,
‘discord’, ‘2fa’, ‘code’, ‘memo’, ‘compte’, ‘token’

Interestingly, this list contains multiple French words: “mot de passe” (password), “mdp” (abbreviation for “mot de passe”), “banque” (bank), “compte” (account). The matching files are then uploaded to the same Discord channel.

The stealer also downloads a JavaScript payload from zerotwo-best-waifu[.]online/778112985743251/wap/dsc_injection, writing it into Discord’s index.js file. Then it kills the running discord.exe process, so that the user has to restart Discord, thus activating the payload.

subprocess.Popen(‘taskkill /im discord.exe /t /f’,shell=true)

The injected script monitors the victim’s actions such, as changing their email address, password or billing information. The updated information is also sent to the Discord channel.

We have already reported these [two]() [packages]() to the PyPI security team and Snyk Vulnerability Database.

Kaspersky solutions detect the threat with the following verdicts:

* Trojan.Python.Inject.d
* Trojan.Python.Agent.gj

## IOCs

### Samples

[34c9d77afd77611ce55716f23594275a]() | ultrarequests-2.28.3.tar.gz
—|—
[f2102dee0caba546ef98b47b373bab9a]() | pyquest-2.28.3.tar.gz
[556ee928fbffd4bbd1cec282ec1a5bb3]() | Downloader Script
[42f0f3b4d5a2be7f09d1c02668cb2c08]() | injected Discord index.js
[d7b6df674690c2e81c72ea031ed44a6f]() | W4SP stealer

### URLs

https://zerotwo-best-waifu[.]online/778112985743251/wap/enner/injector
https://zerotwo-best-waifu[.]online/778112985743251/wap/shatlegay/stealer123365
https://zerotwo-best-waifu[.]online/778112985743251/wap/dsc_injection

### Appendix

[‘mail’, ‘[coinbase](https://coinbase.com)’, ‘[gmail](https://gmail.com)’, ‘[steam](https://steam.com)’, ‘[discord](https://discord.com)’, ‘[riotgames](https://riotgames.com)’, ‘[youtube](https://youtube.com)’, ‘[instagram](https://instagram.com)’, ‘[tiktok](https://tiktok.com)’, ‘[twitter](https://twitter.com)’, ‘(https://facebook.com)’, ‘card’, ‘[epicgames](https://epicgames.com)’, ‘[spotify](https://spotify.com)’, ‘[yahoo](https://yahoo.com)’, ‘[roblox](https://roblox.com)’, ‘[twitch](https://twitch.com)’, ‘[minecraft](https://minecraft.net)’, ‘bank’, ‘[paypal](https://paypal.com)’, ‘[origin](https://origin.com)’, ‘[amazon](https://amazon.com)’, ‘[ebay](https://ebay.com)’, ‘[aliexpress](https://aliexpress.com)’, ‘[playstation](https://playstation.com)’, ‘[hbo](https://hbo.com)’, ‘[xbox](https://xbox.com)’, ‘buy’, ‘sell’, ‘[binance](https://binance.com)’, ‘[hotmail](https://hotmail.com)’, ‘[outlook](https://outlook.com)’, ‘[crunchyroll](https://crunchyroll.com)’, ‘[telegram](https://telegram.com)’, ‘[pornhub](https://pornhub.com)’, ‘[disney](https://disney.com)’, ‘[expressvpn](https://expressvpn.com)’, ‘crypto’, ‘[uber](https://uber.com)’, ‘[netflix](https://netflix.com)’]Read More

Exit mobile version