
1. 摘要
【本文目標(biāo)】
(1)通過本文分析,了解Fomo3D游戲第一輪結(jié)束的交易攻擊流程及具體地址;
(2)介紹“拒絕服務(wù)攻擊”(Denial of Service,DoS)的原理。
2. Fomo3D游戲規(guī)則
Fomo3D 是近一個(gè)多月以太坊上最火爆的應(yīng)用,也是個(gè)資金盤賭博游戲,本文的目的是做技術(shù)分析,所以這里只介紹其結(jié)束的設(shè)定:
- 游戲啟動(dòng)后從 24 小時(shí)開始倒計(jì)時(shí);倒計(jì)時(shí)結(jié)束時(shí),最后一個(gè)夠買 key 的玩家將獲得獎(jiǎng)池中 48% 的獎(jiǎng)金;
- 每有一個(gè)玩家購買 key,倒計(jì)時(shí)會(huì)增加 30 秒。
所以,獲勝條件實(shí)際上很簡單:在自己購買 key 之后到游戲倒計(jì)時(shí)結(jié)束,不再有其他人購買 key。在現(xiàn)實(shí)世界中,要做到這點(diǎn)不那么容易,除非所有玩家都沒錢了;但在區(qū)塊鏈的世界中,具體到以太坊上,是可以通過“技術(shù)手段”做到不讓其他人購買的(也就是不讓其他人的“購買交易”得到“網(wǎng)絡(luò)確認(rèn)”)。這就是大家耳熟能詳?shù)摹熬芙^服務(wù)攻擊”(Denial of Service,DoS)。
3. Fomo3D的3分鐘交易攻擊過程
從Eetherscan去看看最后的30秒究竟發(fā)生了什么。Eetherscan上的數(shù)據(jù)表明,問題不僅是出在最后30秒,而是最后3分鐘——在這個(gè)時(shí)間以秒記的游戲里,整整3分鐘沒有下一個(gè)玩家出現(xiàn)。
交易圖顯示,在2點(diǎn)48分之前和2點(diǎn)51分之后,每一分鐘都會(huì)有多個(gè)玩家買入Fomo3D,但獨(dú)獨(dú)在48分和51分之間,交易完全停止了。

以太坊在這3分鐘發(fā)生了什么?
2點(diǎn)48分,0xa169買key的交易完成,支付0.0055 eth,支持區(qū)塊高度是6191896(該筆交易信息:https://etherscan.io/tx/0x7a06d9f11e650fbb2061b320442e26b4a704e1277547e943d73e5b67eb49c349);3分鐘后,2點(diǎn)51分,下一筆Fomo3D交易產(chǎn)生,區(qū)塊高度6191909,但這筆交易來的太遲,永遠(yuǎn)錯(cuò)過了Fomo3D第一輪的競爭。
在區(qū)塊6191896和區(qū)塊6191909之間,是死亡三分鐘,也是所有問題的答案。
3.1 區(qū)塊的秘密
區(qū)塊6191896,一切正常,0xa169的這筆交易也赫然在列。區(qū)塊6191897在6秒之后被挖出,基本正常。

但在下一個(gè)區(qū)塊,6191898,出現(xiàn)了一個(gè)0x18e1b664c6a2e88b93c1b71f61cbf76a726b7801的地址,有2筆交易與其有關(guān)。
緊接著,區(qū)塊6191899中,3筆交易與其有關(guān);區(qū)塊6191900中,3筆;區(qū)塊6191901中,2筆;區(qū)塊6191901中,2筆;區(qū)塊6191902中,4筆;區(qū)塊6191903中,2筆。

接下來,區(qū)塊6191904,該區(qū)塊一共只打包了3筆交易,全部來自0x18e;區(qū)塊6191905中,全部7筆交易中的3筆;區(qū)塊6191906中,全部的3筆交易。

區(qū)塊6191907中,全部4筆交易中的3筆;區(qū)塊6191908中,全部5筆交易中的4筆。

終于,到了區(qū)塊6191909,0x18e消失了。
(查看各個(gè)區(qū)塊的信息可以變更以下地址的區(qū)塊號(hào):https://etherscan.io/block/6191909 )
擺脫0x18e的區(qū)塊一口氣打包了166筆交易,多筆與Fomo3D相關(guān)的交易包含其中,但它們被耽擱的太久,游戲結(jié)束了。

0x18e有什么特別?為何死亡三分鐘里以太坊上所有的區(qū)塊都包含與它有關(guān)的2到4條交易?原因就出在它對gas的消耗上。
0x18e的一筆交易需要耗費(fèi)360萬或420萬的gas,兩筆交易加起來是780萬gas,而ETH一個(gè)區(qū)塊目前能容納的gas總量是800萬左右。
這樣一樣,因?yàn)?x18e總gas費(fèi)高,會(huì)被優(yōu)先選擇打包,又因?yàn)樗嫉膅as量大,所以兩筆交易就能填滿整個(gè)區(qū)塊,容不下其他的交易。

于是,在交易消失的3分鐘里,在區(qū)塊6191896與區(qū)塊6191909之間,所有的節(jié)點(diǎn)都在打包與0x18e相關(guān)的交易(雖然這些交易全因gas超量失敗了,也就是說0x18e并沒有真正的為這些交易付費(fèi))。
而所有與Fomo3D有關(guān)的交易,同以太坊上其他的交易一起,被留在了交易池排隊(duì)等候。
3分鐘很短,但足夠結(jié)束一個(gè)以30秒為倒計(jì)時(shí)的游戲。
3.2 詭異的0xa169與0x18e
在0xa169買入最后一個(gè)key后,0x18e“堵塞”了以太坊3分鐘。是巧合嗎?不是。
0x18e在8月18號(hào)被創(chuàng)建,晚0xa169地址3天,之后兩者頻繁互動(dòng),應(yīng)該是在測試攻擊模型。
8月21號(hào),兩者間的互動(dòng)結(jié)束,8月22號(hào),0xa169發(fā)起了最后一役,它主攻,0x18e掩護(hù)。

看看0x18e掩護(hù)0xa169的時(shí)間點(diǎn)。
在最后一次攻擊中,0xa169在6點(diǎn)48分22秒完成交易,0x18e在6點(diǎn)48分43秒至6點(diǎn)52分01秒之間發(fā)起攻擊,堵塞網(wǎng)絡(luò)。
但這不是他們第一次配合,0xa169曾在5點(diǎn)50分42秒發(fā)起一筆交易,0x18e在5點(diǎn)51分10秒至5點(diǎn)52分57秒之間發(fā)起攻擊;在此之前,0xa169在5點(diǎn)35分46秒發(fā)起交易,0x18e在5點(diǎn)36分49秒至5點(diǎn)37分28秒間發(fā)起攻擊。
0x18e為0xa169爭取到最多時(shí)間的一次,就是它們成功的一次。在0xa169拿走獎(jiǎng)金之后,0x18e這個(gè)地址再無任何動(dòng)作。
所以,如果你真以為有人用0.8個(gè)ETH贏了Fomo3D,未免天真。這是一場投入技術(shù)、金錢,被精心策劃、全力以赴的戰(zhàn)役。
3.3 錯(cuò)失勝利的人
不過,如果說這場勝利完全與幸運(yùn)無關(guān)也不全對。因?yàn)?xa169能拿走獎(jiǎng)金還跟它的對手,一個(gè)倒霉的人有關(guān)。
簡單講講這個(gè)運(yùn)氣不好的家伙。地址是0x32ad247B94E46bB75caC37B81e6CB53173002370,就是0xa169上方的這一位。
0x32ad是個(gè)狠角色,因?yàn)樵谶@個(gè)地址上,它總共就出手一次,而且?guī)捉晒ΑT摴P交易的地址信息為https://etherscan.io/tx/0x5e7309de3aab2a36286fc04aebcfadec627bcb4aa89af4dad82001a5993d1be1 。

它算準(zhǔn)在最后的時(shí)刻出擊,用極高的gas單價(jià)被選中進(jìn)入?yún)^(qū)塊打包(單個(gè)交易,gas費(fèi)551美金),它也是整個(gè)死亡3分鐘內(nèi)唯一闖入?yún)^(qū)塊打包環(huán)節(jié)的Fomo3D交易(區(qū)塊6191907)。

但它失敗了,緣于一個(gè)有趣的不幸。它設(shè)置的Gas Limit是379000,但交易耗費(fèi)的gas超過了379000。

在Fomo3D中,幾乎沒有g(shù)as超過379000的交易,但這一次,最重要的一次,偏偏就超了。
4. 原理總結(jié)
在目前成熟的 Web 服務(wù)技術(shù)里,制造 DoS 攻擊一般是通過大量的并發(fā)請求和/或大數(shù)據(jù)量的獨(dú)立請求,將 Web 服務(wù)的帶寬/服務(wù)資源占滿,而使其無法再相應(yīng)正常的數(shù)據(jù)請求。在以太坊中,則可以通過制造大量的“垃圾合約調(diào)用”來達(dá)到同樣的效果。
這里需要來講一個(gè)機(jī)制了:交易池(transaction pool)。在礦工/礦池節(jié)點(diǎn)上,通常都會(huì)有一個(gè)交易池,網(wǎng)絡(luò)上廣播的所有新的交易都會(huì)被首先加入這個(gè)“池”,而后再由礦工/礦池選擇那些“經(jīng)濟(jì)性更好”的交易優(yōu)先打包確認(rèn)。這里說的“經(jīng)濟(jì)性”,即由交易發(fā)送者在交易數(shù)據(jù)中指定的 gasPrice,gasPrice 越高,執(zhí)行交易所附帶的合約代碼的執(zhí)行費(fèi)用也就越高,而這些費(fèi)用通常是會(huì)作為手續(xù)費(fèi)支付給礦工的。所以,礦工/礦池會(huì)從交易池中選取那些 gasPrice 明顯高于其他交易的交易來優(yōu)先打包執(zhí)行(確認(rèn))。并且,礦工并不能從技術(shù)上判斷一個(gè)交易中附帶的程序代碼是否是“垃圾合約調(diào)用”(它們也沒有這個(gè)“責(zé)任”),它們僅僅選取那些執(zhí)行費(fèi)用更高的交易來優(yōu)先執(zhí)行?;谶@個(gè)原理,就允許了攻擊者通過調(diào)高包含了“垃圾合約調(diào)用”的交易的 gasPrice,來在短時(shí)間內(nèi)用這些“無效交易”占用區(qū)塊的可用 gas,以使其他“正常交易”無法被打包進(jìn)區(qū)塊。
這里還有幾個(gè)基礎(chǔ)知識(shí)需要科普一下:
- 以太坊中的區(qū)塊可包含的交易(計(jì)算量)是由區(qū)塊的 gasLimit 來控制的,而并不是像比特幣那樣用數(shù)據(jù)大小來限制;以太坊中目前區(qū)塊的 gasLimit 上限是 800 萬 gas,礦工可以做 5% 以內(nèi)的上下浮動(dòng);區(qū)塊內(nèi)能包含多少交易,是看這些交易執(zhí)行所消耗的總 gas 是否達(dá)到這個(gè)區(qū)塊的 gasLimit;
- 以太坊中執(zhí)行交易的費(fèi)用,是用交易基礎(chǔ)執(zhí)行費(fèi)用的 21000 gas,加上交易中附加的代碼的字節(jié)大小的費(fèi)用(這里有一個(gè)折算公式,不詳細(xì)講了)以及實(shí)際執(zhí)行代碼所消耗的 gas 的總和乘以交易中指定的 gasPrice 來計(jì)算的;這個(gè)交易費(fèi)用,會(huì)從交易發(fā)送者賬戶中自動(dòng)扣除;如果交易發(fā)送者賬戶余額不足,交易不會(huì)被打包進(jìn)區(qū)塊;
以太坊中的交易的實(shí)際執(zhí)行所要消耗的 gas 是可以根據(jù)交易執(zhí)行時(shí)的“世界狀態(tài)”明確知道的,也就是這個(gè)交易的實(shí)際執(zhí)行費(fèi)用是明確知道的,礦工就是據(jù)此來判斷打包交易的“經(jīng)濟(jì)性”。
在 Fomo3D 游戲的后期(即獎(jiǎng)池金額已經(jīng)很高),大多數(shù)玩家都會(huì)選擇在倒計(jì)時(shí)的最后數(shù)分鐘內(nèi)才去購買 key,以讓游戲能繼續(xù)下去。這時(shí),如果有一個(gè)機(jī)會(huì),在攻擊者自己購買了 key 之后(這只會(huì)給剩余時(shí)間增加 30 秒),能在其后數(shù)分鐘內(nèi)讓網(wǎng)絡(luò)不再確認(rèn)其他人的購買交易,攻擊者就可以讓游戲結(jié)束從而贏得大獎(jiǎng)。
加入輝哥知識(shí)星球,可以獲得Fomo3D全套代碼,包含前端頁面。

5. 參考
1) Fomo3D 游戲的第一輪是如何結(jié)束的
2) Fomo3D死亡3分鐘:黑客用0.8ETH贏下了10000個(gè)ETH