Two NPM packages masquerading as legitimate javascript libraries were published to the NPM registry this week.
The packages were published by a user named “kamations” and target the marked-js ecosystem. Two of the packages appear to be carbon copies of the legitimate marked npm package.
The two malicious packages are marked-ps and marked-cs. You can find them here: https://www.npmjs.com/~kamations
TIP: Scroll to the bottom for IOCs
What is marked-js?
Marked-js is a popular Javascript library that allows developers to use, embed and edit Markdown in a browser. It’s a handy library and if you’ve ever edited Markdown in a web app, you were probably using marked-js.
Marked-js is a legitimate, popular and actively maintained Javascript library that was originally published 13 years ago. It’s NPM package is named simply “marked” and you can find it at https://www.npmjs.com/package/marked
There are 187 versions of the package and more than 8600 other NPM packages depend on marked-js. The marked NPM package is downloaded more than 8 million times a week! Suffice it to say, it is one of those very popular Javascript libraries that bad guys love to target!
Very confusingly, the legitimate project is named “marked-js” but the NPM package is simply named “marked”. Bad guys are taking advantage of these slight differences to deploy lookalike packages.
Malicious actors are copying the marked-js NPM packages
Threat actors have published two malicious packages marked-ps and marked-cs. I know, its confusing right? Marked and marked-js are legit, but marked-cs and marked-ps are not. Anyhow, these two malicious packages are very similar in how they deploy their malicious payloads. I will focus on the marked-cs package which is the more popular of the two packages.
I’m including screenshots of the two malicious packages marked-cs and marked-ps so you can see how similar they are to the real marked package. Marked-cs can be found at https://www.npmjs.com/package/marked-cs
The legitimate package, marked can be found at https://www.npmjs.com/package/marked
The threat actor has copied the real README file from the legitimate package and used it for both of their malicious packages. Honestly, if you didn’t know that marked-cs and marked-ps were malicious I could see someone installing these packages thinking they were the real thing.
How did I initially find these threats?
I was originally alerted to these marked lookalike packages by my GitHax tool. It analyzes every new package published to NPM looking for unique signals that the package is malicious.
These two malicious packages marked-ps and marked-cs are very similar in how they deploy their malicious payloads. I will focus on the marked-cs package which is the more popular of the two packages.
NPM stats can be faked
One of the biggest problems with the NPM ecosystem is that it’s easy for malicious actors to fake some of the details in their malicious package uploads. For example, in the image to the right which was taken from one of the malicious packaages, the repository and homepage list the legitimate marked-js information. It’s the same with the Issues and Pull Request statistics at the bottom. These fields are pulled from the GitHub repository you list in the package metadata, which can be anything you want to put there.
The problem with that is that NPM doesn’t verify that you own the GitHub repository, so what threat actors do is include a legitimate GitHub repo in their malicious package metadata to “piggyback” off the reputation of the original, legitimate GitHub repo.
This helps their malicious package appear more legitimate and is a common technique that malicious actors use to hide in plain sight.
Watching the attack evolve
Marked-cs was first published on January 7th, and the author has been actively working on it . They’ve published 13 versions of the package in that time which has given me an excellent opportunity to watch their attack evolve over those three days.
The marked-cs NPM package has had over 700 downloads over the last three days. This is worrying as the package deploys malware so those 700 downloads represent some number of potential victims.
Let’s inspect the package files
If you inspect the package files, either by downloading the package tarball, or browsing in the web UI, you’ll see that there is a tarball in the package/lib directory. Threat actors use this common technique: nesting a second tarball, or compressed archive, inside the main NPM package tarball.
Amongst the package files, there is also a marked.vbs file. This file is a Visual Basic Scripting edition script, also known as VBScript. These scripts are an older Microsoft scripting language that predates Powershell. VBScript is deprecated and support for the scripting language will be removed from Windows operating systems between 2025 and 2027. Some threat actors use VBScript to bypass Powershell detection rules in security scanning tools.
The package.json file is the file that defines how the Javascript in the NPM package is executed. Once the package is installed locally, the postinstall script is called, which runs npm run dev, which in turn runs node ./main.cjs.
If you inspect the main.cjs file it really only does one thing: it executes the marked.vbs script.
VBS script
The VBScript file does a number of things integral to the deployment of the malware in this package:
- It disables the Windows Defender endpoint and detection response tool so that Windows can’t detect what’s going to happen next.
- It disables push notifications so that administrators won’t know that anything is happening.
- It unzips the tarball and then runs the marked.exe file that was in that tarball.
- It adds the marked.exe file to the Windows registry. This will run the marked.exe after the system is restarted.
- Finally, the VBScript removes the files that deployed the malware and hides the marked.exe file.
The different versions of the marked-cs packages deploy different payload files, which you can see in this screenshot. You can browse all the versions of the package at https://www.npmjs.com/package/marked-cs/v/2.1.0?activeTab=versions
The malware payload
The latest version of the marked-cs package deploys a file marked.exe as its payload. Earlier versions of marked-cs and the other package marked-ps instead drop a file named marked.scr.
Let’s start with the marked.exe file. If you scan this file with Virustotal, it identifies the file as malicious.
What does the malware do?
Virustotal has confirmed that marked.exe is malicious, but what does it do? To find that out, let’s run the file in a sandbox. I’ll use the Any.Run sandbox, but there are others like Joe’s sandbox and Recorded Futures Triage.
When I execute the marked.exe file in Any.run, the sandbox watches what it does, what it downloads, and what IP addresses or domains it talks to.
In this case, the malware analyzed the local system to learn about its environment, and then it reached out to a command and control (c2) server at 43.134.113.193 on port 8000.
Any.Run identified that the malware was an all-purpose malware variant named Purplefox.
Will source code or package scanning tools protect you from these malicious packages?
Okay, so we’ve verified that these packages are malicious. Even worse, they drop active malware onto any hosts that install the NPM packages which then connects to a C2 server and takes control of the infected host. Sounds like something that security scanning tools should pick up right?
Well guess what? Software composition analysis (SCA) tools are not very good at identifying known malicious packages. So even if GitHub Security Advisory or OpenSSF’s OSV mark the package as malicious SCA tools typically don’t report this fact to paying customers.
I scanned the marked-cs package with Snyk and it didn’t find anything wrong with it.
I tried the same thing with Socket. It was a little better and at least identified that the marked-cs file ran shell commands, but the reality is that half the legitimate packages in NPM registry run shell commands and the vast majority of packages have install scripts.
That’s hardly detecting genuine malicious behaviour. My guess is that this is what Socket reports for 99% of public NPM packages. Not encouraging.
Indicators of Compromise (IOCs)
Based on my research these two NPM packages marked-cs and marked-ps have very similar, but slightly different behaviours:
Files:
marked.vbs – sha256 hash: 24dacbd59519a976a313dd1dc21f92ddd309719abcf230b3a98ff7f338a79fe6
marked.exe – sha256 hash: 9d8621a7190ee4015efbc7a093387279a8b6adf06e0b7fc3869a894a9484c864
marked.scr – sha256 hash: 3c3c638aecdd17cc243ee51137ee3240be37ce0a9e1ffdd9d78a6ae7e4e764fa
main.tar.gz – sha256 hash: c24ff7dd833a0ef30a60edb24131935d8b6cf600713f87a3d6870d33fe08274d
C:\Users\admin\AppData\Roaming\DYA_RFVEFSPQPULUKLRTH\1.0.0\Data\dya.dat
IP addresses:
43.134.113.193 TCP port 8000
What can you do?
I’ve alerted NPM but these packages haven’t been marked as malicious yet, so no security tool could protect you from these malicious packages. Unfortunately, that’s how most software supply chain security tools work: you have to know that a package is malicious before the tool can protect you.
But in general, it’s a good idea not to install NPM packages blindly. If you know what to look for, there are definite signals that these packages are dodgy. All of these packages have just two files: package.json and index.js (or main.js). This is one of several flags that you can use to determine if a package is legit or not.
Hopefully, NPM will remove these packages soon.