我的位置 首页  >  新闻动态  >  国内新闻

空手套白狼?USDT 假充值逻辑缺陷漏洞利用分析

来源:科技成果转化中心时间:2018-07-11
      

前言

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)。

Omni Layer(原名 Mastercoin)

Omni Layer 也属于染色币,其核心思想是将 Omni Protocol 层的数据用某种方式写入比特币区块链中,目前在协议定义中有三种,Class AClass 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交易的定义。

Simple Send 是一项将 Omni Layer 层中特定的数字资产从原地址转移到目标地址的操作,注意原地址和目标地址均使用比特币的地址。

可以看到上面的交易并没有任何的余额信息,这就是说,原地址的 Omni Layer 层数字资产,由 Omni Core 自己维护一个额外的账本并校验

Omni core 的实现是遍历交易,自己维护一个 tally map,下图所示是 Omni core 正在逐笔扫描并构建账簿。

以随机抽取的某笔交易为例(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 浏览器的内容一致。

而 Omni 浏览器 中的 Raw Data,则是由 Omni Core 自己根据扫描比特币区块链并重新构筑账本后输出的内容,这其中就有我们今天的主角 valid了。

2. 漏洞分析及实操

从背景知识中我们可以看出,实际上对于余额的校验是通过客户端来进行的,但很遗憾的是,与比特币不同,Omni Layer 并没有 UTXO 机制,这也就导致了无效交易也能被广播。

正常的转账流程如下:

用户发起 USDT 转账行为。

Omni Layer 的一个正常实现客户端生成交易。

客户端广播交易。

比特币区块链确认交易。

交易所确认交易数足够。

入帐交易所。

恶意攻击流程如下:

黑客发起一笔恶意转账行为。

黑客重新编译客户端,绕过余额检查,或采用其他方式生成恶意交易。

黑客广播恶意交易。

比特币区块链确认交易。

交易所确认交易数足够,没有校验交易合法性。

入帐交易所。

黑客提走资产。

以下几种情况均会导致交易状态不合法:

地址被冻结。

交易类型不允许。(目前只有当 property = 0 ,即为比特币时会出现这种情况)

交易金额超限,或小于零。

交易资产无效。

余额不足。

对交易合法性的定义在 omnicore/src/monicore/tx.cppCMPTransaction::logicMath_SimpleSend中。

下面我们亲自来构建一笔恶意交易。

为了方便起见,使用的是 Electrum 轻节点钱包。准备工具:

1. 一个有一点余额的比特币钱包

2. 一笔 Simple Send 的原始 tx

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

步骤:

先使用 Electrum 发送一笔交易,目标地址随便写一个。

点击预览交易,将未签名的原始交易复制。

打开工具3

把原始交易粘贴上去,复制 JSON 交易。

out中 添加如下字段

然后把 JSON 粘贴回去,原始交易粘贴回来,签名广播(工具->加载交易->从文本),搞定。

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

凭空产生的 USDT。

当然,之后这笔交易会被判定为 invalid。

3.总结与反思

本文首先对 USDT 进行了基础建设上的分析,然后讨论了这次漏洞出现的原因,最后,本文复现了被攻击场景。

实际上,这个逻辑漏洞的主要原因还是在交易所方面没有做好处理,面对这种涉及到金钱的事情,小心一些总是好的。

Tether 公司在以太坊上也发行了基于 ERC20 的 USDT,不知道会不会也出现类似的问题。

*本文原创作者:umiiii,本文属FreeBuf原创奖励计划,未经许可禁止转载

       (科技成果转化中心供稿)