安装npm软件包后可能发生的12种奇怪的事情

几个月前,我启动了一个名为恶意程序包 (又名“恶意程序包”)的项目。 它监视npm存储库中的更新,下载所有新模块,然后检查它们是否具有虱子-搜索网络活动,对文件系统的可疑操作等。 即使是node.js上的小型项目也经常具有大型的依赖树,开发人员实际上无法对其进行全部测试。 这给攻击者提供了极大的机动空间,并且出现了一个问题-npm注册表的黑暗角落隐藏了多少讨厌的注册表? 180,000个托运行李之后,我得到了一个大概的答案。


图片


而这个答案-也许没有那么多。
[注意:本文有英文版,也由我撰写]


npm软件包对您的系统有什么作用?


该软件包有两种主要危害您的方法-安装/卸载和启动应用程序时。 让我们通过示例来看看这两个选项。


NPM脚本允许程序包在安装和卸载时执行任意命令。 这些包括preinstallinstallpostinstallpreuninstallpostuninstall ,它们由npm在软件包生命周期的适当时刻自动执行。 他们能做什么? 当前用户可以做的所有事情-例如,删除上次休假中的所有照片,或将您的浏览器历史记录合并到FBI中(尽管很可能他们已经拥有了)。 可以通过传递--ignore-scripts标志来禁用此行为,但是,首先,没有人这样做,其次,您可以破坏很多可靠的软件包。 通过脚本对ESLint进行了耸人听闻的攻击 ,这影响了eslint-scope (每周600万安装)和eslint-config-eslint (每周2000安装)的用户。


在初始化期间,该软件包有第二次机会使您的生活复杂化(通常在第一次调用require时发生)。 现在,他有机会修改全局变量和其他程序包,例如,从您的比特币钱包中窃取私钥 ,或者使crypto.randomBytes方法变得不那么随机


图片


检测到多少个恶意软件包?


好吧,这个列表不能令人印象深刻,总共发现了3个软件包,这些软件包是由npm安全团队的努力从npm存储库中删除的。 让我们来看一下:



尽管结果很少,但在分析所有可疑程序包的过程中(我查看了3000多个报告来找到这三颗珍珠),发现很多有趣的东西并不是您通常不会想到的(或仔细地尝试着不去考虑),方法是键入npm install 。 因此,假设您不小心从存储库中选择了许多软件包之一并进行安装。 可能出什么问题了?


1.一个包可以覆盖其他包中的方法(包括那些来自Node.js标准交付中的方法)


但是,如果您阅读了前面的几段内容,或者已经与javascript生态系统一起工作了一个多星期,那么这对您来说并不是什么新闻。 但是这场灾难的规模很可能会远离您。 因此,如果您的项目至少具有一些依赖性,则很可能您已经覆盖了fs.closeSync方法(并且可能不止一次)。 大量的软件包会修改其他人的API,但是只有少数软件包至少有一定的理由。 其中“ fraceful-fs ”属于“冠军”,每周安装1200万次, 从fs重新定义了数十种方法 。 还值得注意的是async-listener ,它重写了46种不同的方法 ,包括命运多crypto.randomBytes ,当我第一次发现它时,这使我有些困扰。


想象一下,如果查找由于层次结构中某些依赖项的这种覆盖而导致的错误,该怎么办。 但是,没有理由担心,因为...


2.程序包可以确定更改后的API以对其进行其他更正


图片


是的,某些软件包使用杂技的奇迹(例如/graceful-fs/.test(fs.closeSync.toString()) )来这样做(大多数情况下是针对相同的graceful-fs /graceful-fs/.test(fs.closeSync.toString()) 。 因此,如果您突然在标准库中遇到难以理解的问题,请尝试仅安装几个随机的npm软件包。 或者只是关闭计算机,然后在最近的公园中散步,生活太短了,无法理解所有这些。


3.他可以发送分析数据


如果控制台中发生任何事情,Adblock不会保护您,某些软件包的作者成功使用了此功能。 有些发送最基本的信息,例如ecdsa-csr


 // POST https://api.therootcompany.com/api/therootcompany.com/public/ping { "package":"ecdsa-csr", "version":"1.1.1", "node":"v10.14.2", "arch":"x64", "platform":"linux", "release":"4.9.125-linuxkit", "action":"install", "ppid":"eDSeYr9XUNRi9WhWli5smBNAvdw=" } 

有些人不太害羞。 例如,此处是无服务器报告的一部分(原始报告大2倍):


 // POST https://tracking.serverlessteam.com/v1/track { "userId":"0e32cba0-14ef-11e9-9f89-b7ed4ca5dbba", "event":"framework_stat", "properties":{ "version":2, "general":{ "userId":"0e32cba0-14ef-11e9-9f89-b7ed4ca5dbba", "context":"install", "timestamp":1547135257977, "timezone":"GMT+0000", "operatingSystem":"linux", "userAgent":"cli", "serverlessVersion":"1.35.1", "nodeJsVersion":"v10.14.2", "isDockerContainer":true, "isCISystem":false, "ciSystem":null } } } 

幸运的是, jquery不会发送任何统计信息,因此您仍然可以从所有人那里秘密安装它。 暂时。


4.您的计算机可以代替CI / CD服务器使用


如果用户在安装过程中可以这样做,为什么还要编译软件包? 如果仅指定所需编译器的主要版本,例如typescript@3 ,则可以获得额外的收获。 来自微软的有识之士的一个希望,他们知道如何做正确的事。


有可能走得更远吗? 当然可以


 "postinstall": "eslint --ext .js,.vue --fix src" 

现在,您可以安然入睡了-所有用户都将收到包裹格式正确的源。


5.他可能会吓scar你。


图片


如果您观看了所有系列的话,先生。 机器人,但仍然没有足够的动力去阅读计算机网络并做一些真正令人印象深刻的事情,那就是一个简单的解决方案-在postinstall脚本中通过几行向世界展示您的技能。 这正是Pizza- Pasta的作者所做的(同时向我展示了KDPV)。


 { "name": "pizza-pasta", "author": "Zeavo", "scripts": { "install": "mkdir -p ~/Desktop/hacked && touch ~/Desktop/hacked/pwnddddd && wget https://imgur.com/download/KTDNt5I -P ~/Desktop/hacked/", "postinstall": "find ~/.ssh | xargs cat || true && printf '\n\n\n\n\n\nOH HEY LOOK SSH KEYS\n\n\n\nHappy Birthday! Youve been h4ck0red\n\n\n'" } } 

6.包可以加载和执行bash脚本


您是否听说过curl|bash 不是一个好主意 ? 如果不是,那么您很可能是ORESoftware的一名员工,在postinstall脚本中拥有一堆包含相似行 软件包


 curl --silent -o- https://raw.githubusercontent.com/oresoftware/realpath/master/assets/install.sh | bash 

到目前为止,此脚本中没有任何犯罪...现在。 我希望每个有权使用oresoftware/realpath都是非常诚实和体面的人。


7.可能会要求您输入密码


magicleap的作者提出了一种非常不寻常的方式来通过公共存储库分发私有软件包。 他的项目包括一个加密的归档文件和用于解密它的实用程序-但MAGICLEAP是您将正确的密钥放在MAGICLEAP环境MAGICLEAP


 // : https://github.com/modulesio/magicleap/blob/master/decrypt.js var key = process.env['MAGICLEAP']; console.warn('Decrypting magicleap module with MAGICLEAP environment variable'); const ws = fs.createReadStream(path.join(__dirname, 'lib.zip.enc')) .pipe(crypto.createDecipher('aes-256-cbc', Buffer.from(key, 'base64'))) .pipe(fs.createWriteStream(path.join(__dirname, 'lib.zip'))); 

8.软件包可能会在安装过程中自行打补丁


fake-template的作者没有时间将测试与即时代码分开,特别是因为通过在测试行的末尾添加特殊注释很容易做到:


 // : https://github.com/framp/fake-template/blob/master/index.js const template = (string, tag=defaultTag) => { if (mode !== 'literal') throw new Error('Invalid template') return (context={}) => tag(literals, ...expressions.map(evalInContext(context))) } assert.equal(template('')(), ``) // TEST assert.equal(template('abc')(), `abc`) // TEST const dog = 'Orlando' // TEST assert.equal(template('abc ${dog} lol ${cat}')({dog}), `abc ${dog} lol ${cat}`) // TEST 

然后通过sed删除它们:


 "postinstall": "sed -i '/\\/\\/ TEST/d' index.js" 

简洁大方!


9.程序包可能会更改npm设置


在我的拙见中, package-json.lock是一件很棒的事情, package-json.lock其他开发人员的疏忽引起的一系列问题。 但是, 一些反对这种想法的人反对以下观点:


 "preinstall": "npm config set package-lock false" 

10.他可以在Nicolas Cage的照片上更改桌面的背景


图片


这是一个链接,以防万一-https://www.npmjs.com/package/cage-js 。 可能值得将此软件包注册为恶意软件包。


11.包裹可以让你翻身


ember-data-react就是这样做的 ,在安装过程中打开了著名的视频 。 不幸的是,在它的帮助下,不可能将任何数据从Ember传输到React-其中没有一行JavaScript代码。


12.它可能根本无法安装。


图片
不存在的依赖项,错误指定的版本,已被遗忘的私有存储库-您无法从npm存储库中安装所有软件包的约0.6%。


而不是结论


NPM软件包可能会对您的系统产生奇怪的影响,并且您没有太多选择可以防止这种情况发生。 使用package-lock.json可以避免突然的更新(并确保没有人在您不知情的情况下将其断开),在前端配置CSP ,以使第三方模块中的后门程序至少不能将数据合并到其作者。 并备份您的照片,以防万一。


如果您觉得自己有足够的力量将自己沉浸在npm软件包的奇妙世界中,则可以在这里找到所有资源: https : //github.com/malicious-packages/core 。 该实用程序充满了hack和非最佳解决方案,但是可以应付其任务。 存储库中还有一个MongoDB转储,其中包含超过18万个软件包的分析结果,最重要的是,不要忘记添加过滤器{'reports.status': 'unverified'} 。 由于时间紧迫,我不打算再开发此项目,但是我将尝试解决所有问题。


照顾好自己和您的应用程序!

Source: https://habr.com/ru/post/zh-CN436132/


All Articles