
Recently, over 400 malicious packages were uploaded to PyPI (Python Package Index), the official code repository for the Python programming language. This indicates that using this form of attack to target software developers is not a passing fad.
Security firm Phylum recently discovered 451 packages that all contained nearly identical malicious payloads and were uploaded in rapid succession. Once installed, the package creates a malicious JavaScript extension that loads every time the browser is opened on the infected device. This trick allows the malware to survive reboots.
The JavaScript monitors the infected developer’s clipboard for cryptocurrency addresses that may be copied there. Once the address is found, the malware replaces it with the attacker’s address. Purpose: Intercept payments intended by the developer to another party.
In November, Phylum identified dozens of packages downloaded hundreds of times that covertly do the same thing using highly encoded JavaScript. Specifically:
- I created a textarea on the page
- pasted the contents of the clipboard
- We used a set of regular expressions to find common cryptocurrency address formats
- Replaced the identified address with an attacker controlled address in a previously created textarea
- Copied the textarea to the clipboard
Phylum Chief Technology Officer Louis Lang said in a November post: “This fraudulent search/replace allows end-users to unintentionally transfer funds to attackers.”
New obfuscation method
Not only has the number of malicious packages being uploaded increased significantly, but the latest campaigns also use vastly different methods to hide their tracks. While the package published in November used encoding to hide the behavior of JavaScript, the new package replaces function and variable identifiers with random 16-bit combinations of Chinese ideograms shown in the following table. Write in a format you think
| Unicode code point | Ideogram | meaning |
|---|---|---|
| 0x4eba | people | Man; People; Mankind; Someone Else |
| 0x5200 | knife | knives; old coins; measurements |
| 0x53e3 | mouth | mouth; open end; entrance, gate |
| 0x5973 | woman | woman, girl; feminine |
| 0x5b50 | Child | children; fruits, seeds |
| 0x5c71 | Mountain | mountain, hill, peak |
| 0x65e5 | Day | sun; sun; daytime |
| 0x6708 | Month | Every month |
| 0x6728 | wood | wood; timber; timber; wood |
| 0x6c34 | water | water, liquids, lotions, juices |
| 0x76ee | eye | eyes; look, look.department, topic |
| 0x99ac | Horse | horse; surname |
| 0x9a6c | Horse | horse; surname |
| 0x9ce5 | bird | bird |
| 0x9e1f | bird | bird |
Using this table, the line of code
''.join(map(getattr(__builtins__, oct.__str__()[-3 << 0] + hex.__str__()[-1 << 2] + copyright.__str__()[4 << 0]), [(((1 << 4) - 1) << 3) - 1, ((((3 << 2) + 1)) << 3) + 1, (7 << 4) - (1 << 1), ((((3 << 2) + 1)) << 2) - 1, (((3 << 3) + 1) << 1)]))
create a built-in function chr maps a function to a list of integers [119, 105, 110, 51, 50]The . line then joins it into the string that finally creates 'win32'.
A phylum researcher explains:
I see a series of calls like this
oct.__str__()[-3 << 0]. of[-3 << 0]is evaluated to[-3]andoct.__str__()evaluates to a string'<built-in function oct>'. using Python’s index operator[]with a string that has-3In this case, we get the third character from the end of the string.'<built-in function oct>'[-3]is evaluated to'c'Continuing this for the other two here,'c' + 'h' + 'r'And a simple evaluation of the complex bitwise arithmetic added at the end would be:''.join(map(getattr(__builtins__, 'c' + 'h' + 'r'), [119, 105, 110, 51, 50]))of
getattr(__builtins__, 'c' + 'h' + 'r')It just provides a built-in functionchrand it mapschrto a list of ints[119, 105, 110, 51, 50]And then join it all together into a string and finally give us'win32'This technique continues throughout the code.
Although it looks like highly obfuscated code, the researchers say the technique is ultimately easy to defeat just by observing what the code does at runtime.
The latest batch of malicious packages tries to take advantage of typos developers make when downloading one of these legitimate packages.
- Bitcoin library
- ccxt
- Cipher comparison
- crypto feed
- free trade
- selenium
- Solana
- Viper
- websocket
- Finance
- panda
- matplotlib
- aiohttp
- beautiful soup
- tensorflow
- selenium
- scrapie
- Colorama
- scikit learning
- pie torch
- pygame
- py installer
For example, a package targeting a legitimate vyper package used 13 filenames with one letter omitted or duplicated, or replaced two letters of the correct name.
- Hyper
- vper
- view
- pipe
- vvyper
- viper
- viper
- Vaipia
- Viper
- yvper
- vpyer
- washed
- wash
“This technique is easy to automate using scripts (which we leave as an exercise for the reader). The longer the canonical package name, the greater the likelihood of typosquat,” says the study. person writes. “For example, our system detected 38 typosquats. cryptocompare A package published around the same time by a user named pinigin.9494”
The availability of malicious packages in legitimate code repositories that closely resemble legitimate package names dates back to at least 2016. This time, a college student uploaded her 214 booby-trapped packages to her PyPI, RubyGems, and NPM repositories that contained slightly altered legitimate package names. As a result, the spoofing code ran him over 45,000 times on over 17,000 distinct domains, more than half of which were given strong administrative privileges. Since then, so-called typosquatting attacks have flourished.
The blog post includes the names of all 451 malicious packages found by Phylum researchers. It’s not a bad idea for someone trying to download he one of the legitimate packages for the purpose of double-checking whether he’s accidentally acquired a malicious doppelgänger.