ReversingLabs has discovered a malicious npm package disguised as the software tool Material Tailwind. Here's an in-depth look at our discovery — and threat analysis.
Note: This analysis was updated on Friday, Sept. 23 with new information on an additional MachO executable.
Highlighting the rise in risk from open source software repositories, ReversingLabs researchers discovered a new technique that threat actors are using to sow open source repositories with malicious code: a malicious npm package masquerading as Material Tailwind, which is described on their website as “an easy to use components library for Tailwind CSS and Material Design.”
Both of these components are recognizable names and massively popular libraries among developers, netting millions of downloads each. Tailwind specifically serves as an open-source CSS framework that doesn’t provide predefined classes for elements, while Material Design is a design language that uses grid-based layouts, responsive animations, and other visual effects.
In contrast, the malicious Material Tailwind npm package, while posing as a helpful development tool, has an automatic post-install script, which downloads a password protected zip file that contains a malicious executable: a custom-packed Windows executable capable of running PowerShell scripts.
The ReversingLabs research team spotted the package using our Titanium Platform, which tracks software behaviors, specifically looking for packages that contain obfuscated code. Here's our in-depth overview of how we came across this package, as well as how our team deobfuscated the malicious code to gain insight into the threat actor’s methods, and indicators of compromise (IOCs) that can help your organization determine whether or not you have been compromised.
Obfuscated code: A red flag in npm packages
As with previous discoveries, Material Tailwind caught the attention of the Titanium Platform’s behavior indicator because it contained code obfuscated with JavaScript Obfuscator.
Unlike the previous research cases, however, the threat actor responsible for Material Tailwind did quite a good job at making the package description as convincing as possible. Upon closer inspection, however, we noted that the package description is, in fact, copied from another npm package named tailwindcss-stimulus-components. The threat actor took special care to modify the entire text and code snippets to replace the name of the original package with Material Tailwind. The malicious package also successfully implements all of the functionality provided by the original package.
Post-install shenanigans
But behavior indicators don’t lie. One of the JavaScript files present in the package contains obfuscated code. It also happens that this tailwindcss-stimulus-scripts.min.cjs file is also declared as postinstall script in package.json file. Packages delivered via npm let developers declare various types of scripts inside package.json file, those get executed at some point of the package lifecycle.
Postinstall scripts get executed immediately after package installation. This is why they are a quite popular mechanism for achieving code execution among threat actors. From the perspective of a threat researcher: an obfuscated script that is set to run immediately after installation is a (big) red flag.
In the case of Material Tailwind, the obfuscated script was deobfuscated and its content was analyzed in detail.
Figure 1: npm module imports
Looking at the deobfuscated script content, the list of imported modules already looks suspicious. It contains modules for file system operations, encryption, network communication, archive decompression and process manipulation.
The module first sends a POST request with platform information to a specific IP address and validates that it is executed on a Win32 system. Then it constructs a download link containing the type of the operating system. It also adds a parameter which is probably used to validate that the download request is coming from the victim's machine. This parameter is generated by performing a bcrypt hash of the victim's IP address and removing the first 7 bytes from the hash value.
Figure 2: Code responsible for stage 2 download
The downloaded file is a password protected zip archive named DiagnosticsLogger.zip which contains only one file, and it is named DiagnosticsHub.exe. The name of the executable varies between different versions of the package. For the current ZIP archive version, the password that encrypts its contents is “J##$dj&%qvvV89”. Since the archive contains only one file, password protection is likely used to avoid basic antivirus checks.
The chosen file names suggest that the attacker is trying to disguise the payload as some kind of diagnostic tool. Finally, the script spawns a child process that executes the downloaded file using cmd /c command.
Windows executable
The downloaded Windows executable implements several protections to frustrate analysis. It is packed with a custom runtime packer. The Assembly unpacking routine utilizes xmm registers. Typically used for high precision math, they’re abused here for evading security solutions. The malicious code also performs long sleep delays in its execution, another effort to avoid detection. While running, the Windows executable tries to contact trustworthy domains like google.com to verify that it has internet access, and detect if it is executing in a sandboxed environment.
Figure 3: Base64 decrypted powershell command creating Scheduled Task
Packed information includes several Powershell code snippets responsible for command and control, communication, and process manipulation. Persistence is achieved by executing a base64 encoded Powershell command which sets up a scheduled task to be executed daily.
At stage 2, the malware fetches a XOR encrypted and base64 encoded file from a public Google Drive link. In case this link isn’t accessible two alternative download locations exist, one at Github and another one at OneDrive. The XOR key it uses for decryption is the hardcoded string “AJUHKJHOIU351q23AJKI8i7y”.
Figure 4: Google drive file decryption routine
At the time of publication, the encrypted file contains a single IP address, which is the location of its command and control (C2) server, from which the malware receives encrypted instructions using a dedicated socket connection. During dynamic analysis of the malware the C2 server responded with a command indicating that the status of the victims machine wasn’t initialized, which triggered execution of a Powershell command performing a directory listing of the “C:\Program Files” and “C:\Program Files (x86)” folders. The output was stored in the “C:\ProgramData\DiagnosticsLog\Diagnost.log” file, probably to be uploaded to the C2 server later.
Figure 5: Powershell directory listing command
MachO executable (update as of 9/23/2022)
The malicious package was initially reported to the npm security team on Monday, Sept. 20. The npm security team responded quickly, removing the affected package within 24 hours. But while they removed it from the npm package repository, they didn’t replace it with a security holder version, like they usually do. That gave the attacker an opportunity to publish new versions under the same package name, which happened on Thursday, Sept. 22. Three new versions were published, and they contained modified versions of the postinstall script.
Figure 6: Updated code responsible for stage 2 download
The new versions added code which triggers if the package is installed on Darwin operating system. In that case, instead of a password protected zip file, a different archive containing two MachO files compiled for ARM and x86-64 architectures, is downloaded and executed on the compromised machine.
MachO executables are much simpler than the described Windows executables. Important strings are created by concatenating ASCII characters during execution. Persistence is acquired by creating LaunchAgents, a technique typical for macOS malware. The file name suggests that malware tries to mimic the legitimate CoreSimulator framework related to the Xcode developer toolset used for developing macOS applications. Instructions are fetched from C2 server by performing curl request, and curl output is then redirected to sh command for execution.
Cross platform support, and the fact that new versions of the package were released quickly after the removal of the first ones, shows that a skilled actor is behind this malware — one that is determined to keep this malware operational.
Imposter packages are on the rise
This Material Tailwind attack is just the latest example of a growing trend: malicious npm packages that attempt to fool developers by posing as legitimate packages. For example, in the IconBurst campaign that we first discovered and disclosed in early July, we noted malicious npm packages that name-squatted on heavily-used and legitimate packages, which hid their malicious content using code obfuscation.
These types of software supply chain attacks can be spotted almost daily now. In most of these cases, the malware in question is fairly simple Javascript code that is rarely even obfuscated. Sophisticated multistage malware samples like Material Tailwind are still a rare find.
In this case the complexity of the malware tactics leads to a conclusion that sophisticated actors could be behind this attack. For now, our analysis of the situation tells us that Material Tailwind’s stage two payload can be classified as a fully functional Trojan malware. It uses a lot of techniques to complicate reverse engineering. Additionally, IP redirection using a file hosted on a legitimate service like Google Drive is also performed before the communication with the actual C2 server.
Given the advanced nature of this malicious package and the fact that it is imitating widely used software development libraries, it is safe to assume that threat actors feel emboldened to continue taking advantage of open source repositories. And as their evasion techniques become more advanced over time, it is essential for software development shops to use a product like ReversingLabs Titanium Platform to spot malicious activity, and keep a close eye on application behaviors prior to including a new third-party dependency in their software.
Future updates regarding this incident will be shared in this blog post.
Indicators of Compromise (IoC)
IP addresses:
85.239.54.17
135.125.137.220
46.249.58.140:13338
Package versions:
material-tailwindcss |
2.3.0 |
466ed2f97d127e91ce29d79cd05dbedbe04c5c07 |
material-tailwindcss |
2.3.1 |
faab8d9ad58d383ab895ff98bc215b497e78a89c |
material-tailwindcss |
2.3.2 |
dbd157edaa3f76d14f2bb2c2d81bab33db147f44 |
material-tailwindcss |
2.3.4 |
cf27558d19b8f7311f48d95ad2f4c24972939929 |
material-tailwindcss |
2.3.5 |
98e37967dbd6ed93ea9e93dbe9617da8770e60c8 |
material-tailwindcss |
2.3.6 |
c913e33c245dd7257ea671b9ec5f97b65c110371 |
Zip file:
81977085079d5629cd9a932055273ed38a7ce87b
e21f62e59bdb08e612065569f169cd5967987d88
Stage 2 PE payload:
748a67a4276a7547f2413c14b7de7f76342038ef
09ecdcc7abd426204ba8d494ce1a6431a5d0d6b9
MachO stage 2 archive:
9915c952ce178eaac65912d4f94cc966840e59eb
MachO stage 2 payload:
d6958efce576ac790d3a053988060ff3da92b5e5
3f13b5fcde0a0451221f2d96322857e99d490406
Stage 2 IP redirect providers:
h[XX]ps://onedrive.live.com/download?cid=8F081466BABC9F13&resid=8F081466BABC9F13%21109&authkey=AOGgyB9v2wrFkJM
h[XX]ps://drive.google.com/uc?export=download&id=1eaFJYy0cLLONFaMDKMUmcU6Js0jG5p8r
h[XX]ps://raw.githubusercontent.com/jfrank4512/Mdam/main/test.txt
Keep learning
- Find the best building blocks for your next app with RL's Spectra Assure Community, where you can quickly search the latest safe packages on npm, PyPI and RubyGems.
- Get up to speed on securing AI/ML systems and software with our Special Report. Plus, see the Webinar: The MLephant in the Room.
- Learn about complex binary analysis and why it is critical to software supply chain security in our Special Report. Plus: Take a deep dive with RL's white paper.
Explore RL's Spectra suite: Spectra Assure for software supply chain security, Spectra Detect for scalable file analysis, Spectra Analyze for malware analysis and threat hunting, and Spectra Intelligence for reputation data and intelligence.