No Unaccompanied Miners: Supply Chain Compromises Through Node.js Packages
Mandiant
Written by: Alessandro Parilli, James Maclachlan
Starting mid-October 2021, Mandiant Managed Defense identified multiple instances of supply chain compromises involving packages hosted on Node Package Manager (NPM), the package manager for the Node.js JavaScript platform, either being compromised directly to deliver malware or simply being created to impersonate popular, legitimate packages. The latter is a technique known as typosquatting. NPM modules are a valuable target for threat actors due to their popularity amongst developers. They also have a high prevalence of complex dependencies, where one package installs another as a dependency often without the knowledge of the developer. Furthermore, the NPM repository npmjs.com does not require the code within the NPM package to be the same as the code within the linked GitHub repository. This means that the GitHub repository does not need to be compromised; only the NPM package.
While Mandiant assesses multiple threat groups to be leveraging these types of compromises, there is one prolific actor, UNC3379, whose activity will be discussed.
Supply Chain Compromises
By compromising a popular package used by developers, it is easy to amplify the distribution of malicious code directly to victims themselves at scale. This can be done either through dependency confusion, hijacking weak credentials, exploiting vulnerabilities to access the target code or using the names of packages abandoned by their developers. For example, in 2018, the NPM module “flatmap-stream” was compromised to deliver cryptocurrency stealing malware. This module was used as a dependency of the much more popular library “event-stream”. In doing so, the threat actors were able to achieve compromises at-scale with minimal effort. Figure 1 is a high-level diagram that demonstrates the threat actor’s process for said attack.
Figure 1: Stages of infection via a malicious/compromised developer library
The following are the stages of infection via a malicious/compromised developer library, as seen in Figure 1:
- Attacker collects information about the build pipeline and code base through open-source intelligence gathering.
- Attacker builds and publishes the custom package.
- Pipeline grabs most recent package and deploys without validation.
- Malicious code is deployed through which an attacker can collect sensitive information such as cryptocurrency wallet info or credentials.
A supply chain attack is nothing new. In 2017, the world was hit with the attack dubbed NotPetya. The malicious code, disguised as ransomware, exploited the NSA’s leaked EternalBlue vulnerability to infiltrate networks and then systematically destroy data. The attackers behind NotPetya breached a financial services software company who were a supplier for the Ukrainian Government.
In the same year, the utility CCleaner suffered a breach and hackers were able to replace the legitimate version of the software with a malicious one, that resulted in the compromise of more that 2 million hosts.
In 2020, UNC2452, a threat actor who's targeting is assessed to be consistent with Russian strategic interests, conducted a widespread supply chain attack leveraging a SolarWinds component. The breadth of victims impacted by UNC2452 included government organizations and Fortune 500 companies. Once again, attackers targeted the supply chain by injecting a backdoor code in the software component Orion, giving them access to the internal environment of the victims and deployed the SUNBURST malware after the updated code was distributed through a legitimate process. Mandiant was the first to detect and investigate the attack.
Another variation on the theme is the poisoning of open-source repositories, as is what happened in this case with the NPM packages. NPM packages have been abused, both by malicious actors and security researchers with the aim of raising awareness on the issue.
Spotlight: UNC3379
ua-parser-js Compromise
According to a GitHub issue raised on Oct. 22, 2021, at approximately 12:15 UTC, the NPM package “ua-parser-js", a popular Node.js library that amassed over 7 million downloads per week, was compromised to deliver malware. The threat actor was able to publish three malicious versions of the package by hijacking the author’s NPM account. According to the repository’s Git log, on Oct. 22, between 16:14 UTC and 16:25 UTC the package author committed a sanitized version of the malicious packages to stop further compromises.
Mandiant detected and responded to identical activity on systems across multiple organizations and industries. Mandiant tracks this cluster of activity as UNC3379. In addition to investigating the detected intrusions, Mandiant Managed Defense proactively searched through the environments of our customers to uncover additional evil.
“ua-parser-js” is a lightweight small footprint package deployed within a web application or server-side application to extract and filter the relevant data needed to parse a User Agent string (i.e., Browser, Engine, OS, CPU, and Device).
In this compromise, UNC3379 added multiple malicious scripts to the package that would ultimately result in the download and execution of both a Monero coin miner and a banking trojan known as DANABOT, depending on the operating system. The compromised versions of “ua-parser-js" were versions “0.7.29”, “0.8.0” and “1.0.0”.
Analysis of the Malicious Scripts Added to the Package
The infection was triggered by the package installation alone. The directive “preinstall” in the “package.json” file was used to execute a custom script before the actual installation process began. The executed script was named “preinstall.js”.
package.json:145: "preinstall": "start /B node preinstall.js & nodepreinstall.js",
- Windows – use of cmd.exe to execute “preinstall.bat”
preinstall.js:23: const bat = spawn('cmd.exe', ['/c', 'preinstall.bat']);
- Linux – use of bash to execute “preinstall.sh”
preinstall.js:4: exec("/bin/bash preinstall.sh", (error, stdout, stderr) => {
- Mac OSX – no execution
The shell script “preinstall.sh” performed a check on the victim’s geographical location:
preinstall.sh:1: IP=$(curl -k hxxps://freegeoip.app/xml/ | grep 'RU\|UA\|BY\|KZ')
Figure 2: preinstall.sh – download and execution of jsextension
Unlike its Linux counterpart, the windows script “preinstall.bat” did not have any geographical check. Instead, it proceeded to attempt to retrieve a resource from the IP address “159.148.186[.]228” using “curl.exe”, or “wget.exe” if “curl.exe” failed. If both failed, it finally leveraged “certutil.exe” to download the remote payload (Figure 3). The resource downloaded, “jsextension.exe”, was the Windows version of the Monero coin miner and was executed with the same parameters as its Linux counterpart. Additionally, the script tried to download a resource from the URL “hxxps://citationsherbe[.]at/sdd.dll” and save it to disk with the filename “create.dll” located in the project’s “node_modules/ua-parser-js" directory. Mandiant analysis revealed the DLL to be consistent with DANABOT whose config contained the following command and control (C2) servers:
- 185.158.250[.]216:443
- 45.11.180[.]153:443
- 194.76.225[.]46:443
- 194.76.225[.]61:443
Figure 3: preinstall.bat – download of “jsextension.exe” and “create.dll”
The script subsequently utilized the native binary “tasklist.exe” to enumerate the running processes on the system to check if the coin miner executable “jsextension.exe” was already running before executing both the coin miner and the DANABOT DLL. The script attempted to execute DANABOT by leveraging regsvr32.exe to silently register the DANABOT DLL (“create.dll”) with the command “regsvr32.exe -s create.dll” (Figure 4).
Figure 4: preinstall.bat – execution of “jsextension.exe” and “create.dll”
ua-parser-js has been targeted before
This is not the first time the NPM module “ua-parser-js" has been targeted. On Oct. 14, 2021, a malicious NPM module named “klown” was uploaded to “npmjs.org” (Figure 5). This module attempted to impersonate the legitimate “ua-parser-js" module by utilizing its branding, repository links, homepage, documentation and even leveraging the website “contrib.rocks” to collect an image of all of the contributors to the “ua-parser-js" repository, which was all in an attempt to appear legitimate. Prior to the removal from npmjs.org, the malicious package already had 23 downloads. Mandiant assesses with high confidence the threat actor responsible to be UNC3379 based on the large overlap in tactics, techniques and procedures (TTPs). Mandiant assesses that this module impersonation served as an opportunity to test the malware delivery before the compromise of the real package on Oct. 22.
Figure 5: The npmjs.org page for the “klown” package.
In this particular instance, the malicious package also deployed the same Monero miner (MD5: fc724eb2894f34a3aca4b952d2f816cd) which was downloaded from the URL “hxxp://185.173.36[.]219/download/jsextension.exe” from a script that was also named “preinstall.bat”.
Coa & rc Module Compromises
In another iteration of the attack, the NPM packages “coa” and “rc” were targeted in a fashion similar to that observed against “ua-parser-js". On Nov. 4, these popular libraries were subject to several updates containing malicious code designed to download and execute a slightly modified version of the DANABOT DLL seen earlier in the attack on Oct. 22, 2021. This time, the target OS was restricted to Windows. Mandiant assesses with high confidence the threat actor responsible to also be UNC3379 due to the overlap in TTPs. Following the discovery of the malicious packages, the NPM security team removed the compromised “coa” and “rc” versions of the packages.
Mandiant Managed Defense identified and responded to a compromise where these packages were leveraged. The malicious version of the package “rc” was present on the host as dependency of the “hint” NPM package, used in one of the victim’s projects (Figure 6).
Figure 6: Dependencies tree showing the relation between the package “hint” and the hijacked dependency package “rc” version 2.3.9
This is indicative of the fact that a malicious package can easily be delivered unbeknownst to the user, due to the recursive nature of dependencies used in NPM packages. A single application can have dozens of packages incorporated within its code as part of the application build process.
How to Check if the Malicious Packages Were Downloaded
The NPM command line tool can be used to check if a specific version of a package was previously downloaded. For the cases presented, the relevant malicious versions were, respectively:
- ua-parser-js versions 0.7.29, 0.8.0, 1.0.0
- coa versions 2.0.3, 2.0.4, 2.1.1, 2.1.3, 3.1.3
- rc versions 1.2.9, 1.3.9, 2.3.9
The command npm cache ls shows the history of the fetched packages, complete with the version:
# npm cache ls rc
make-fetch-happen:request-cache:https://registry.npmjs.org/rc
make-fetch-happen:request-cache:https://registry.npmjs.org/rc/-/rc-1.2.8.tgz
Additionally, to show a full tree of the dependencies used in a package, launch the command "npm ls –a" from the package directory.
Conclusion
Supply chain compromises are designed to abuse the trust in third party providers to indirectly gain access to a victim’s environment, which can be difficult to detect. By proactively and consistently monitoring our customers for threats resulting from supply chain compromises, Mandiant Managed Defense was able to find this type of evil and assist our customers on remediation where malicious packages were installed within their environments. As a result of this, Mandiant did not identify any further malicious activity following the initial compromise at any of our customers.
Prevention and Remediation
- Check for the presence in your environment of any of the mentioned packages.
- Make sure the installed “coa” package version is 2.0.2, latest stable at the time of writing.
- Make sure the installed “rc” package version is 1.2.8, latest stable at the time of writing.
- Make sure the installed “ua-parser-js” package versions are 0.7.30, 0.8.1 or 1.0.1, latest stable at the time of writing.
- Check for the existence on the environment of the malicious files detailed in this blog post and remove them (refer to the IOC section).
- Any secrets or credentials should be considered compromised on the infected host and changed.
- Consider locking version numbers of packages to prevent from auto-installing a new package that may be malicious
Malware Definitions
DANABOT
DANABOT is backdoor written in Delphi that communicates using a custom binary protocol over TCP. The backdoor implements a plug-in framework that allows it to add capabilities via downloaded plugins. DANABOT's capabilities include full system control using a VNC or RDP plugin, video and screenshot capture, keylogging, arbitrary shell command execution, and file transfer. DANABOT's proxy plugin allows it to redirect or manipulate network traffic associated with targeted websites. This capability is often used to capture credentials or payment data. DANABOT can also extract stored credentials associated with web browsers and FTP clients.
MITRE ATT&CK Mapping
IOCs
Acknowledgements
Special thanks to Andrew Rector, Bryce Abdo, Cian Lynch, Nader Zaveri and Yash Gupta for their assistance on the topic.