Blog

Dependency hijacking: Dissecting North Korea’s new wave of DeFi-themed open source attacks targeting developers

/
10 mins read
/
Sep 10, 2024
/ Subscribe

Executive Summary

Over recent days, Stacklok has identified a new wave of malicious NPM package activity from DPRK-aligned threat actors targeting developers and jobseekers in the cryptocurrency, NFT, and Web3 sectors. These packages are a key early stage component of a complex, layered attack chain designed to harvest cryptocurrencies and establish persistent access to compromised developer machines.

These objectives are achieved by embedding a cross-platform JavaScript information stealer and loader known as BeaverTail within copies of legitimate NPM packages. BeaverTail fetches InvisibleFerret, a multi-component Python payload responsible for further sensitive data exfiltration and remote control capabilities.

The attack chain is triggered when unsuspecting job applicants, often lured through fake recruitment efforts, are directed to clone GitHub repositories that include the malicious NPM packages as a dependency. This general form of social engineering via fake job interviews is a common initial access vector associated with North Korean threat actors, typically using LinkedIn to establish contact.

The TTPs and attack infrastructure involved are consistent with a continuation of the campaign previously dubbed Contagious Interview by PaloAlto Unit42 last year.

The threat actors behind the ongoing operation have recently experimented with delivering BeaverTail and InvisibleFerret via a MacOS disk image (dmg) imitating MiroTalk, a video call application.

However, this set of packages is largely in line with the earlier JavaScript-based attack variants, apart from utilizing different styles of obfuscation when compared to previous samples.

Malicious NPM packages detected

Technical Details

Trusty Package Detection

Stacklok’s package analysis platform, Trusty, alerted us to three suspicious npm packages without a verified claim to a source repository. All three were published by the same author, richard_dev. Our static code analysis system had also flagged the presence of obfuscated JavaScript code within all 3 of the packages.

Starjacking Legitimate Repositories

The three identified malicious NPM packages were designed to mimic popular NodeJS packages:

  1. ethersscan-api falsely claimed to be associated with the legitimate etherscan-api repository, likely to typosquat unsuspecting users in the Ethereum community.

  2. eslint-module-conf linked itself to eslint-plugin-import, a package with over 22 million weekly downloads.

  3. eslint-scope-util claimed to be connected to eslint-scope, which had been deprecated in favor of a monorepo.

All three contained an additional, heavily obfuscated JavaScript source code file, sometimes hidden within subdirectories such as lib to evade detection.

Social Engineering

Pivoting from the npm packages we discovered, we were able to find an example of a GitHub repository utilized in sophisticated social engineering attacks involving job interviews in the DeFi or Web3 space. The threat actors will encourage targeted developers to clone a repository as part of a coding challenge or technical assessment, which will either directly contain malicious code or be dependent upon a malicious package.

The NFT_Marketplace project lists an earlier version of ethersscan-api (0.0.3, published 23rd August) as a dependency for the private NodeJS package nuron-nextjs. Although newer versions of ethersscan-api have since been released, the core functionality of the  package remains largely unchanged. Hence it is assumed that this case is still relevant as an illustration of possible malware delivery through dependencies in open source projects.

Hidden within /backend/utils/apiFeatures.js is a call to a function from the malicious NPM package.

Nothing looks egregiously out of place here, but checking the source code of the dependency package, we see that inside init.js, hash-blob.js is pulled in with require and used as an argument in the exported function.

By contrast, the legitimate package does not contain such an import, and does not pass a hash parameter.

This means that whatever is contained in the injected code, hash-blob.js, will be executed when the victim of the fake job process runs the Node project after cloning it from GitHub. This level of layering helps evade detection.

BeaverTail Stealer & Loader

All three of the analyzed packages contain almost identical variants of BeaverTail distributed as heavily-obfuscated JavaScript. Taking the most recent package uploaded as an example, resolve.js (view in full in our Jail repo), the following obfuscation techniques are evident:

  • Self-invoking functions (IIFE)

  • Hexadecimal encoding

  • Control flow obfuscation

  • String manipulation

These methods are characteristic of obfuscation via javascript-obfuscator, a more basic option than those employed in earlier BeaverTail variants.

Removing the initial layers of obfuscation, the functionality of the script becomes more apparent. 

The dual-purposes of stealing and loading subsequent stages were sufficiently visible enough to avoid fully deobfuscating the script.

Information Stealing

After gathering some basic system information, the BeaverTail script dives into its cross-platform infostealing capabilities, targeting sensitive browser database files for credentials, and enumerating the machine’s browsers for cryptocurrency wallet extensions.

Extension ID

Extension Name

nkbihfbeogaeaoehlefnkodbefgpgknn

Metamask Wallet (Chrome)

ejbalbakoplchlghecdalmeeeajnimhm

Metamask Wallet (Edge)

fhbohimaelbohpjbbldcngcnapndodjp

Binance Wallet

hnfanknocfeofbddgcijnmhnfnkdnaad

Coinbase Wallet

ibnejdfjmmkpcnlpebklmnkoeoihofec

TRON Wallet

bfnaelmomeimhlpmgjnjophhpkkoljpa

Phantom Wallet

aeachknmefphepccionboohckonoeemg

Coin98 Wallet

hifafgmccdpekplomjjkcfgodnhcellj

Crypto.com Wallet

jblndlipeogpafnldhgmapagcccfchpi

Kaia Wallet

acmacodkjbdgmoleebolmdjonilkdbch

Rabby Wallet

dlcobpjiigpikoobohmabehhmhfoodbb

Argent X - Starknet Wallet

aholpfdialjgjfhomihkjbmgjidlcdno

Exodus Web3 Wallet

It includes checks for MacOS-specific targets such as Solana ID files and iCloud Keychain.

The harvested files are then exfiltrated to a known North Korean C2 server, 95.164.17[.]24:1224. This server has been associated with state-sponsored operations for several months.

The blob posted to the C2 is prepended with the campaign ID and the machine hostname.

Loader

The more critical aspect of the BeaverTail script is its ability to download and execute additional payloads.

In this case, a Python script with the extension .npl is downloaded from a remote server with a URL of the format http://<c2>:1224/client/<campaign_ID> (e.g., 3/525 here) and saved directly into the user’s home directory (referenced by the variable _0x10e868).

This is the first component of the multistage Python malware known as InvisibleFerret.

Execution of the script is ensured by the download of a Python binary if it is not already installed.

InvisibleFerret

InvisibleFerret is a Python-based malware delivered in multiple stages:

  • Stage 1: Downloads and executes subsequent payloads based on the host OS.

  • Stage 2: Implements RAT (Remote Access Trojan) capabilities, including keylogging and system fingerprinting.

  • Stage 3: Executes browser-stealing operations, targeting stored credentials and sensitive data in the victim's browser.

Initial Installer

This first script, .npl, is again heavily obfuscated. 

It consists of an anonymous function that takes a single argument __. It:

  1. Reverses the string __.

  2. Decodes the reversed string from base64 format using base64.b64decode.

  3. Decompresses the base64-decoded data using zlib.decompress.

Knowing this, we can iteratively extract the argument string and follow this decoding and inflation pattern to unwind 50 layers of encoding and compression, leaving us with the underlying script.

Once fully deobfuscated, the script fetches additional components from the attacker's C2 server and executes them, depending on the host operating system.

For all operating systems, http://<c2_server>/payload/<campaign_id> is fetched and written to a hidden path, .n2/pay under the home directory, before being executed with subprocess.Popen.

If the OS is Darwin (MacOS), the script then exits after the first stage. For all other OS, a tertiary payload is retrieved from the /brow/ path, saved to .b2/bow, and executed.

RAT Capabilities and Backdoor

The second component, .n2/pay, contains the core RAT-like functionality of InvisibleFerret.

  • Machine fingerprinting

  • Keylogging and clipboard logging

  • Remote command execution

  • Executing a tertiary component

  • Downloading AnyDesk

  • Regular check-ins with C2 server

The same compression and encoding routine used in the earlier stage has been applied here and can be removed in a similar fashion to extract the unobfuscated Python payload for analysis.

Fingerprinting

InvisibleFerret gathers detailed information on the local host OS and hardware attributes, along with the geographic location associated with the IP address, in order to fingerprint the victim.

The fingerprint is then crafted into JSON format and uploaded to the C2 server.

Keylogging and Clipboard Monitoring

The libraries pyHook and pyperclip are utilized to continually log keystrokes and clipboard content upon copy and paste operations.

Browser Stealer

The other script downloaded by the first stage, bow, is executed using the ssh_run function.

C2 Commands

The Shell class, a snippet of which can be seen below, defines many functions to allow the operator to interact with the agent. 

The backdoor waits for instructions from the C2 server, which are JSON formatted and contain one or more of the 8 available arguments.

  1. Command execution

  2. Closing the beaconing client session

  3. Sending the logged keystrokes and clipboard data

  4. Running the browser stealer

  5. File upload to FTP

  6. Kill browser processes

  7. Download AnyDesk

  8. Exfiltrate specific user folders

It uploads the results of these commands in JSON over a socket connection.

Cross-Platform Browser Stealer

Whilst the tertiary component, .n2/bow, is only downloaded if the host OS is not MacOS, the script itself contains comprehensive cross-platform support. Unlike earlier Python payload files, this final script was not hidden behind a compression routine, and is largely unobfuscated.

It consists of almost 500 lines of meticulous, documented data extraction functionality for Chrome, Edge, Brave, Opera, and Yandex browsers. It interacts directly with browser databases using sqlite3, implementing password decryption tailored for each operating system.

Another key feature is the retrieve_web function, which queries the browser databases for credit card information.

Reporting

After we confirmed all 3 NPM packages to be malicious, we reported our findings to the NPM Security team and the OSV malicious packages database on 7th September. By 9th September they were removed from the NPM registry.

During the period they were live, the packages were downloaded a combined 341 times:

Package

Download count

ethersscan-api

91

eslint-module-conf

107

eslint-scope-util

143

It is likely a significant proportion of these downloads will have been from security tooling and automated tools, seeing as we expect the attacks to be reasonably targeted, but we cannot confirm this. As such, the full extent of the compromise remains uncertain.

Conclusion

During this investigation Stacklok uncovered a new variation of the combined BeaverTail and InvisibleFerret tooling used by DPRK-aligned threat actors in attacks abusing the open source supply chain.

The delivery mechanism - embedding JavaScript malware as a NodeJS dependency within a seemingly legitimate GitHub repository - highlights the vulnerability of open-source ecosystems to such attacks. The additional malicious code which kicked off the infection chain was abstracted away from inspection by the user and, in many cases, automated security tools.

While this incident involved the relatively simple case of a direct dependency - the complexity and resultant risk increases exponentially when considering transitive dependencies - indirect dependencies pulled in by third-party libraries. These nested dependencies increase the difficulty of identifying and mitigating security threats, expanding the attack surface.

Threat actors are increasingly exploiting this web of complexity. The security of the open-source supply chain relies on maintaining visibility and trust across every layer of the development process.

IOCs

File

Name

SHA256

ssdeep

.npl

b8a68c5c25e586319481603ddab11276f66965a4701f89abc181308edc1bdb53

96:I7XQcKxhwlRPKDU09c7RDXSi1z6V3821GppAqNMU00ELB:gXHKxKld50ed1z6Vd4rAquU01

pay

2b7c7df496c6aff2f4339ad6b9dcc5bb43c81898d29332fd5378874f896a73dd

384:mBQ4EMdjMqJvfZbjLTjcamTfSioCph5ZX2hmzc2h1pGNKKfNpjoNCEsY:meHMmqVBjL/YTfRpbZX2YIUGxfN9A3

bow

d141bc9b5664a906ec501781edf7b7af2f8640b067fd90c7f36876cba764807b

192:HymQjtIkGN5V2kbeDA9rRbWfgjvG+LcIzfJ78pnS35lCz4218kG42RtnkLjVpiKt:WIk85VyAJs4jvG+/epSpMmtkXVpT

Network

C2 Server: 95.164.17[.]24:1224

Related Posts

Cross-platform RAT deployed by weaponized 'requests' clone

Luke Hinds / Poppaea McDermott /
Aug 30, 2024
Continue Reading

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

Poppaea McDermott /
Jul 11, 2024
Continue Reading

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

Edward Thomson /
Mar 3, 2024
Continue Reading