USDT 漏洞利用分析

6月28日,慢霧科技發佈了一條針對 USDT 的預警和漏洞分析,提醒各大交易所儘快暫停 USDT 充值功能,並自查代碼是否存在該邏輯缺陷。全文如下:

#預警# #漏洞分析# 交易所在進行 USDT 充值交易確認是否成功時存在邏輯缺陷,未校驗區塊鏈上交易詳情中 valid 字段值是否為 true,導致“假充值”,用戶未損失任何 USDT 卻成功向交易所充值了 USDT,而且這些 USDT 可以正常進行交易。

很遺憾,經過筆者的一番查找發現,網上的很多資料都傾向於描述 USDT 的資本意義,而對於技術上原理的文章卻寥寥無幾。於是經過一些調查,筆者發現這個漏洞實際上並不能歸因於 USDT 本身,而是交易所一方的問題導致。這種漏洞起因可以說非常簡單,但一旦利用成功,造成的後果卻難以估算。區塊鏈開發中,各種低級錯誤,諸如大小寫拼錯導致的智能合約漏洞也是數不勝數(如:http://www.freebuf.com/vuls/175904.html),僅以本文拋磚引玉。本文將回答以下問題:

USDT 是什麼?USDT 的轉賬是怎麼實現的?USDT 的轉賬/提現手續費給了誰?

這次漏洞是怎麼回事?受害者是誰?怎麼防禦?

1. 背景知識

染色幣

ETH 在近一年來因為智能合約系統而受到了廣泛地關注,大家可以用 5 分鐘時間就發出自己的第一個代幣,而代幣的發行、轉賬則都依賴於智能合約,底層則是由 ETH 公鏈承載。事實上,遠在 ETH 誕生之前,大家就想用比特幣主鏈做點啥。其中,一個重要的概念被提出來了:染色幣。具體來說,染色幣是指在普通的比特幣交易中附上一些信息,藉助比特幣底層基礎設施來記錄。然而,比特幣官方開發組(Core)對這種方式頗有爭議,將用於存儲信息的 OP_RETURN字段從 80 字節驟然縮小到了 40 字節( https://github.com/bitcoin/bitcoin/pull/3737)。

USDT 漏洞利用分析

Omni Layer(原名 Mastercoin)

Omni Layer 也屬於染色幣,其核心思想是將 Omni Protocol 層的數據用某種方式寫入比特幣區塊鏈中,目前在協議定義中有三種,Class A、Class B和 Class C 。

1. Class A - 這種方法是利用了比特幣每個地址本質上都是大小為 20 bytes 的二進制字符串。先將數據分割成 20 bytes 為一組的數據塊,然後使用 Base58 編碼作為目標地址發送即可。當然這些被髮送的 UTXO 將永遠丟失。使用這項技術的還有 cryptograffiti。

2. Class B - 這種方法利用了比特幣的 multisig ,即多籤特性。發送一筆 1 of n的多重簽名交易(即,n 個地址中,任何一個地址簽名即可花費這筆 UTXO)。當前版本的 Omni Layer 協議中最大支持 n = 3。

3. Class C - 這種方法則利用了OP_RETURN操作碼儲存數據,目前來看,基本上所有的 Omni layer 層的交易都採用了這種方式。使用這項技術的還有 CoinSpark 。

Omni Protocol 能讓用戶發行自己的數字資產,其中資產編號為 31 的就是被廣泛使用的

USDT 。而日常中,發送 USDT 使用的交易類型是 Simple Send。

下面是對 Simple Send交易的定義。

USDT 漏洞利用分析

Simple Send 是一項將 Omni Layer 層中特定的數字資產從原地址轉移到目標地址的操作,注意原地址和目標地址均使用比特幣的地址。

可以看到上面的交易並沒有任何的餘額信息,這就是說,原地址的 Omni Layer 層數字資產,由 Omni Core 自己維護一個額外的賬本並校驗

Omni core 的實現是遍歷交易,自己維護一個 tally map,下圖所示是 Omni core 正在逐筆掃描並構建賬簿。

USDT 漏洞利用分析

以隨機抽取的某筆交易為例(b364bea8e4a9c9aeefda048df6f71dd62dc39d07a2286340e7c83c19b7ffd895):

輸入 (1) 0.00500000 BTC

1NJdUJGCJgZ4YEwthHD1skdHPsr5TxHbpq 0.00500000

源地址輸出 (3) 0.00498879 BTC

地址解析失敗 - (解碼) 0.00000000

1FoWyxwPXuj4C6abqwhjDWdz6D4PZgYRjA 0.00000546 轉賬目標

1NJdUJGCJgZ4YEwthHD1skdHPsr5TxHbpq 0.00498333 找零

其 OP_RETURN 字段為 6f6d6e69000000000000001f0000001ac68eac4b

6f6d6e69 0000 0000 0000001f 0000001ac68eac4b

6f6d6e69 => omni

0000 => 版本:0

0000 => 交易類型:Simple Send(0)

0000001f = 31 => 貨幣:USDT

0000001ac68eac4b = 115000388683 = 1150.00388683 => 轉賬金額

與 Omni 瀏覽器的內容一致。

USDT 漏洞利用分析

而 Omni 瀏覽器 中的 Raw Data,則是由 Omni Core 自己根據掃描比特幣區塊鏈並重新構築賬本後輸出的內容,這其中就有我們今天的主角 valid了。

USDT 漏洞利用分析

2. 漏洞分析及實操

從背景知識中我們可以看出,實際上對於餘額的校驗是通過客戶端來進行的,但很遺憾的是,與比特幣不同,Omni Layer 並沒有 UTXO 機制,這也就導致了無效交易也能被廣播。

正常的轉賬流程如下:

用戶發起 USDT 轉賬行為。

Omni Layer 的一個正常實現客戶端生成交易。

客戶端廣播交易。

比特幣區塊鏈確認交易。

交易所確認交易數足夠。

入帳交易所。

惡意攻擊流程如下:

黑客發起一筆惡意轉賬行為。

黑客重新編譯客戶端,繞過餘額檢查,或採用其他方式生成惡意交易。

黑客廣播惡意交易。

比特幣區塊鏈確認交易。

交易所確認交易數足夠,沒有校驗交易合法性。

入帳交易所。

黑客提走資產。

以下幾種情況均會導致交易狀態不合法:

地址被凍結。

交易類型不允許。(目前只有當 property = 0 ,即為比特幣時會出現這種情況)

交易金額超限,或小於零。

交易資產無效。

餘額不足。

對交易合法性的定義在 omnicore/src/monicore/tx.cpp的CMPTransaction::logicMath_SimpleSend中。

下面我們親自來構建一筆惡意交易。

為了方便起見,使用的是 Electrum 輕節點錢包。準備工具:

1. 一個有一點餘額的比特幣錢包

2. 一筆 Simple Send 的原始 tx

3. https://brainwalletx.github.io/#tx

步驟:

先使用 Electrum 發送一筆交易,目標地址隨便寫一個。

點擊預覽交易,將未簽名的原始交易複製。

USDT 漏洞利用分析

打開工具3

把原始交易粘貼上去,複製 JSON 交易。

在out中 添加如下字段

USDT 漏洞利用分析

然後把 JSON 粘貼回去,原始交易粘貼回來,簽名廣播(工具->加載交易->從文本),搞定。

https://www.omniexplorer.info/tx/6791b04ff752bffc9251910fa58bda5c85f28dabb4f2651dd1b9830037a2c1da

USDT 漏洞利用分析

憑空產生的 USDT。

當然,之後這筆交易會被判定為 invalid。

USDT 漏洞利用分析

3.總結與反思

本文首先對 USDT 進行了基礎建設上的分析,然後討論了這次漏洞出現的原因,最後,本文復現了被攻擊場景。

實際上,這個邏輯漏洞的主要原因還是在交易所方面沒有做好處理,面對這種涉及到金錢的事情,小心一些總是好的。

Tether 公司在以太坊上也發行了基於 ERC20 的 USDT,不知道會不會也出現類似的問題。


分享到:


相關文章: