Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

被污染的 npm 包:event-stream #4851

Merged
merged 6 commits into from
Dec 20, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 19 additions & 19 deletions TODO1/compromised-npm-package-event-stream.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,28 @@
> * 原文作者:[Thomas Hunter II](https://medium.com/@tlhunter?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/TODO1/compromised-npm-package-event-stream.md](https://github.com/xitu/gold-miner/blob/master/TODO1/compromised-npm-package-event-stream.md)
> * 译者:
> * 校对者:
> * 译者:[CoderMing](https://github.com/coderming)
> * 校对者:[格子熊](https://github.com/KarthusLorin), [caoyi](https://github.com/caoyi0905)

# Compromised npm Package: event-stream
# 被污染的 npm 包:event-stream

![](https://cdn-images-1.medium.com/max/800/1*OB_BwZtUSGuM15X6xFsrWw.png)

Ownership of a popular npm package, `[event-stream](https://github.com/dominictarr/event-stream)`, was transferred by the original author to a malicious user, [right9ctrl](https://github.com/right9ctrl). This package receives over [1.5mm](https://www.npmjs.com/package/event-stream) weekly downloads and is depended on by nearly 1,600 other packages. The malicious user was able to gain the trust of the original author by making a series of meaningful contributions to the package. The first publish of this package by the malicious user occurred on September 4th, 2018.
一个著名的 npm 包 [`event-stream`](https://github.com/dominictarr/event-stream) 的作者,将其转让给了一个恶意用户 [right9ctrl](https://github.com/right9ctrl)。这个包每个月有超过 [150 万](https://www.npmjs.com/package/event-stream) 次下载,同时其被 1,600 个其它的 npm 包依赖。恶意用户通过持续地向这个包贡献代码来获得了其原作者的信任。这个 npm 包由恶意用户发布的第一个版本时间是 2018 年 9 月 4 日。

The malicious user modified `event-stream` to then depend on a malicious package, `[flatmap-stream](https://github.com/hugeglass/flatmap-stream)`. This package was specifically crafted for the purposes of this attack. That package contains a fairly simple `index.js` file, as well as a minified `index.min.js` file. The two files on GitHub appear innocent enough. However, in the published npm package, the minified version of the file has additional code injected into it. There is no requirement that code being uploaded in an npm module is equivalent to the code stored publicly in a git repository.
恶意用户修改了 `event-stream`,让其依赖了一个恶意 npm 包 [`flatmap-stream`](https://github.com/hugeglass/flatmap-stream)。这个 npm 包是专门针对这次攻击所制作的。它包括了一个相当简单的 `index.js` 文件,同时也有一个压缩版的 `index.min.js` 文件。在 GitHub 上,这两个文件看起来完全没问题。然而,在 npm 上发行的代码并没有被要求与 git 仓库中所存储的代码相同。

The addition of the malicious package to the list of `event-stream` dependencies came to light on November 20th and is documented heavily in [dominictarr/event-stream#116](https://github.com/dominictarr/event-stream/issues/116#issuecomment-441759047). This issue was made over two months after the compromised package was published. One of the many benefits of open source software is that code can be audited by many different developers. However, this isn’t a silver bullet. An example of this is OpenSSL, which is an open source project receiving some of the highest scrutiny but is still affected by serious vulnerabilities such as Heartbleed.
这个被插入到 `event-stream` 中的恶意 npm 包在 10 月 20 日被其他用户发现并在 [dominictarr/event-stream#116](https://github.com/dominictarr/event-stream/issues/116#issuecomment-441759047) 中曝光。这个 issue 在恶意 npm 包发布两个月后才被创建。开源软件的一大好处是能够集众多开发者之力,但这并不是毫无坏处的。例如 OpenSSL,这个开源项目有着几乎最严格的代码审查,但是其仍然有许多不足之处,例如 Heartbleed 漏洞(译者注:可参考 http://heartbleed.com/)。

### What does the package do?
### 恶意 npm 包做了什么?

The package represents a highly targeted attack. It ultimately affects an open source app called [bitpay/copay](https://github.com/bitpay/copay). According to their README, _Copay is a secure bitcoin wallet platform for both desktop and mobile devices._ We know the malicious package specifically targets that application because the obfuscated code reads the `description` field from a project’s `package.json` file, then uses that description to decode an **AES256** encrypted payload.
该恶意 npm 包是一种针对性很强的攻击。它最终会对一个开源 App [bitpay/copay](https://github.com/bitpay/copay) 发起攻击。该 App 的 README 中提到:**Copay 是一个支持桌面端和移动端的安全比特币钱包平台**。我们知道恶意 npm 包只针对这个应用是因为其会读取项目 `package.json` 文件中的 `description` 字段,并用其去解码一个 **AES256** 加密的代码段。

For projects other than copay, the description field won’t properly match the key used for encryption, and the operation fails silently. The [description field for bitpay/copay](https://github.com/bitpay/copay/blob/90336ef9fb4cc3a90a026827be27a32348d3615c/package.json#L3), which is `A Secure Bitcoin Wallet`, is the key required to decrypt this data.
对于其他项目,`description` 字段不能够用于给加密代码段解密,之后 hack 操作将会悄悄终止。而 [bitpay/copay的 description 字段](https://github.com/bitpay/copay/blob/90336ef9fb4cc3a90a026827be27a32348d3615c/package.json#L3),也就是 `A Secure Bitcoin Wallet`,是解密这些数据(加密代码段)的 key

The package `flatmap-stream` contains encoded data cleverly hidden in a `test` directory. This directory _is not_ available in the GitHub repository but _is available_ in the raw `[flatmap-stream-0.1.1.tgz](https://registry.npmjs.org/flatmap-stream/-/flatmap-stream-0.1.1.tgz)` package. The encoded data is stored as an array of parts. Each of these parts are minified/obfuscated and also encrypted to various degrees. Some of the encrypted data includes method names which could alert the malicious behavior to static analysis tools, such as the string `_compile`, which is a method on `require` for creating a new module. I’ve done my best to clean-up the files and make them human readable in the following two code samples.
`flatmap-stream` 这个包巧妙地将数据隐藏在了 `test` 文件夹中。这个文件夹在 GitHub 不可见但却出现在了实际的 [`flatmap-stream-0.1.1.tgz`](https://registry.npmjs.org/flatmap-stream/-/flatmap-stream-0.1.1.tgz) 包中。这些加密的数据以一个数组的形式存储,数据的每一部分都被压缩及混淆过,同时也以不同的参数进行了加密。一部分加密的数据包括了一些会被静态数据统计工具警告为恶意行为的方法名,例如 `_compile` 这个在 `require` 中意味着创建一个新 Module 的字符串。在下面两段示例代码中,我尽我所能去清理了这些文件让代码更易读。

Here is the first part. It isn’t as interesting and mostly appears to be a bootstrap function to load the second part. It appears to work by modifying a file name `ReedSolomonDecoder.js` from a submodule. If the file has already been modified, which is known to have happened if `/*@@*/` appears in the file, then it does nothing. If it hasn’t been modified it not only modifies the file but also replaces the access and modified timestamps to be the original values. That way if you glance at the file on disk you would not immediately notice it had been modified.
这是第一部分。它不怎么有意思,最有可能出现于一个 bootstrap 内的函数来用于引入第二段代码。它看起来是通过修改子模块中的一个名为 `ReedSolomonDecoder.js` 的子模块来使用的。如果该文件中已经有了 `/*@@*/` 这个字符串,那么它就什么都不做。如果尚未对其进行修改,那么它不仅会修改文件,还会将访问权限和修改后的时间戳替换为原来的值。这样做的话,当你看你磁盘中的文件时,你就不会注意到它已经被修改了。

```
/*@@*/
Expand Down Expand Up @@ -54,7 +54,7 @@ module.exports = function (e) {
};
```

And here is the more interesting second part. Some superfluous pieces have been removed to make the original intent more obvious.
第二部分就更有趣了。我将一些多余的代码段被删掉了,来凸显出其原意图:

```
/*@@*/
Expand Down Expand Up @@ -182,19 +182,19 @@ window.cordova
: doBadStuff()
```

This file monkey-patches functionality from the `bitcore-wallet-client` package, specifically the `getKeys` method of the `Credentials` class. It backs up the original function, then inserts code to transmit the credentials for a wallet to a third party server. That server is located at `111.90.151.134`. These credentials can likely be used to gain access to users accounts and allow an attacker to steal money from the original owner.
这个文件像是个 `bitcore-wallet-client` 包打了猴子补丁,特别是 `Credentials` 类的 `getKeys` 方法,它备份了原有函数,然后将钱包内的凭证传到第三方服务器。这个服务器位于 `111.90.151.134`。这些凭证可能被用来获取用户账户的访问权限,然后允许攻击者从原账户主那里窃取资金。

The package makes several attempts to avoid detection. For example, it doesn’t run when using a test Bitcoin network, identified as `testnet`. Instead it only runs on the live Bitcoin network, named `livenet`. This could help avoid detection if an affected app runs acceptance tests against the test network. It also only appears to run the bootloader when a release build is being generated. It does so by looking at the first argument in `process.argv` and testing it against the regular expression `/build\:.*\-release/`, and returning if a match isn’t made. This argument is likely provided by some sort of build server.
这个 npm 包在企图避免侦测上做了很多事情。例如,它不会在使用测试的比特币网络即 `testnet` 上运行,它只会在实际的比特币网络 `livenet` 中运行。如果受感染的应用在做网络测试,这将会避免其被发现。它同时只会在被打包成 release 版本时运行安装引导程序(译者注:即上文中第一段代码,加载恶意代码)。它通过查看 `process.argv` 中的第一个参数来使用正则表达式 `/build\:.*\-release/` 进行匹配,如果没有匹配到,那这次流程就可能是被某类 build server 运作的。

### How could this attack have been prevented?
### 如何防御这次攻击?

It may be tempting to rely on tools which scan npm packages by way of static analysis. This particular attack encrypts the malicious source code to avoid detection. To protect against such an attack a different approach must be taken…
通过使用静态分析工具来扫描 npm 包可能是个很棒的想法。但此次攻击对恶意的源代码进行了加密以避免被检测到。为了防止这种攻击,我们必须采取其他的的方法...

This particular attack appears to run in both a normal webpage as well as an application built with Cordova — a tool for converting web apps into mobile apps. The attack could have been prevented by making use of [CSP (Content Security Policy)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP). This is a standard for specifying which URLs a webpage can communicate with and is specified via web server headers. Cordova even has its own [mechanism](https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-whitelist/index.html#navigation-whitelist) for specifying which third party services can be contacted. However, the [Copay application appears to have disabled this feature](https://github.com/bitpay/copay/blob/72a9e176c12c77b5dfc4590c88de73f28fa301b7/app-template/config-template.xml#L121).
这次特定攻击看起来可以同时在传统 web 页面和通过 Cordova(一个将 web App 打包成移动端 App 的工具)构建的 App 中运行。我们已经发现了这次攻击可以通过使用 [CSP (Content Security Policy)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) 来阻止。这是用来指定页面可以与哪些 url 通信并将这些设定通过 web 服务器响应头来指定的标准。Cordova 甚至有其自身的方法 [mechanism](https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-whitelist/index.html#navigation-whitelist) 来指定哪些第三方服务可以使用。然而,[Copay App 似乎禁用了这个特性](https://github.com/bitpay/copay/blob/72a9e176c12c77b5dfc4590c88de73f28fa301b7/app-template/config-template.xml#L121)

CSP is a great tool for securing frontend applications. However, such a feature is not built into Node.js itself. [Intrinsic](https://intrinsic.com/) is a Node.js package which provides the ability to whitelist which URLs an application can communicate with— much like CSP—however it can do much more powerful things as well. Intrinsic can be used to whitelist filesystem access, child process access, sensitive `process` attributes, TCP and UDP connections, and even fine-grained database access. These whitelists are specified on a per-route basis, making Intrinsic far more powerful than a firewall.
CSP 可以有效地保证前端页面的安全。然而,这个特性没有被内置在 Node.js 中。[Intrinsic](https://intrinsic.com/) 这个 Node.js 包提供了让你可以设定你 App 通信 URL 白名单的功能——这很像 CSP ——而且其可以干更多事情。Intrinsic 可以被用来设置文件系统白名单、子进程白名单、`process` 的细分节点、TCP UDP 连接甚至是细粒度的数据库访问。这些白名单是建立在每条请求路由的,这使得其比防火墙更加强大。

Interestingly, this attack on `event-stream`, wherein the attacker monkey-patches a sensitive function with a malicious one which makes outbound HTTP requests to an evil server, is _exactly_ what we warned against in our previous post: [The Dangers of Malicious Modules](https://medium.com/intrinsic/common-node-js-attack-vectors-the-dangers-of-malicious-modules-863ae949e7e8). These supply-chain attacks are only going to become more and more prevalent with time. Targeted attacks, like how this package specifically targets the Copay application, will also become more prevalent.
有趣的是,这次在 `event-stream` 中发生的攻击中,攻击者用猴子补丁的方式修改了系统关键函数来实现其向恶意服务器发送 HTTP 请求的目的,这正好是我们之前的这篇文章中所警示的:[The Dangers of Malicious Modules](https://medium.com/intrinsic/common-node-js-attack-vectors-the-dangers-of-malicious-modules-863ae949e7e8)。随着时间的推移,这些基于代码依赖链的攻击只会越来越频繁。这种高针对性的攻击(例如这次针对 Copay 的)也会变得越来越普遍。

> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。

Expand Down