慢雾深度解析 Bitfinex 天价手续费转账:BUG+显示错误「酿成大错」

撰文:Thinking@慢雾安全团队

事件背景

分析源自一笔转账金额10wUSDT,手续费却高达7,676枚ETH的天价手续费交易。https://etherscan

声音 | 慢雾余弦:未来加密货币是绝对的刚需存在:慢雾余弦今日在微博上表示,未来虚拟世界是绝对的独立智慧体,加密世界是绝对的大势,加密货币是绝对的刚需存在,虽然这个未来还有不少距离。[2020/1/4]

将int转成Hexhttps://github

判断是否可以被2整除,如果不行需要在字符开头添加一个0,这里主要是为了能够成功的将数据2个1组写入到buffer。https://github

if(a

returna;}

以出错的示例数据:33974229950.550003进行分析,经过intToBuffer函数中的intToHex和padToEven处理后得到7e9059bbe.8ccd,这部分浏览器js和nodejs的结果都是一致的。

动态 | 慢雾 TradingView 0day 漏洞预警:据 Joinsec 情报及慢雾安全团队的深入分析,通用 K 线展示 JS 库 TradingView 再次发现两个 0day 漏洞,可绕过 Cloudflare 及浏览器 CSP 防御机制,并且不会在 Web 服务上留下日志。第一个 0day 漏洞如果被利用成功会导致用户帐号权限被盗、交易恶意操作等,从而造成资产损失;第二个 0day 漏洞可以实施钓鱼攻击盗取用户账号密码,也可在特殊场景下绕过目标 Web 服务的 CSRF 防御。TradingView 在数字货币交易等平台被非常广泛地应用,属于商业软件,版本分布未知。鉴于历史披露及新发现的 0day 漏洞相关场景来看,我们强烈建议使用 TradingView 的项目方保持警惕,注意用户的异常反馈。细节我们会在合适时机下披露。[2019/3/1]

不一致的地方是在newBuffer的操作:

newBuffer(padToEven(hex.slice(2)),'hex');

处理方式分析:浏览器js

通过webpack打包好js文件并对文件进行引用,然后在浏览器上进行调试分析。

首先输入的示例字符33974229950.550003会进入到intToBuffer的函数中进行处理。

声音 | 慢雾科技余弦:盗挖Webchain跟CoinIMP平台零手续费有关:慢雾科技创始人余弦刚刚在微博表示:难怪最近利用Drupal漏洞植入恶意挖矿脚本的行为里,除了挖门罗币,还在挖Webchain,这是一条我之前没关注过的隐私币(挖矿方面也是基于CryptoNight哈希算法)。原来这与CoinIMP这个挖矿平台有关,0%手续费呀。[2019/2/27]

同步分析intToBuffer的处理过程,这部分和」关键代码分析「部分的代码逻辑是一样的,处理转换部分得到的结果是7e9059bbe.8ccd。

接下来分析如何将转换后的字符填充进入的buffer中,通过这步可以得到buffer的内容是126,144,89,187,14,140,205对应的是7e,90,59,bb,e,8c,cd。

>0x7e->126>0x90->144>0x59->89>0xbb->187>0xe->14>0x8c->140>0xcd->205

这里发现e.这部分的小数点消失了,于是开始解小数点消失之迷,追踪到hexWrite这个函数,这个函数会将得到的数据2个一组进行切分。然后用了parseInt对切分后的数据进行解析。

然而parseInt('e.',16)->14===parseInt('e',16)->14消失的小数点被parseInt吃掉了,导致最终写入到buffer中的数据发生了错误,写入buffer的值是7e9059bbe8ccd。

处理方式分析:nodejs

由于浏览器上出问题的是7_**__**_e9059bbe.8ccd在写入buffer的时候小数点被parseInt吃掉了导致数据出错,但是经过分析,node的数据也是错误的,且产生错误的原因是和浏览器的不一样。

首先我们先看下如下的示例:

node三组不同的数据填充到buffer得到的结果居然是一样的,经过分析node的buffer有个小特性,就是2个一组切分后的数据,如果没法正常通过hex解析的,就会把那一组数据以及之后的数据都不处理了,直接返回前面可以被正常处理的那部分数据。可以理解为被截断了。这部分可以参考node底层的buffer中node_buffer.cc中的代码逻辑。

>newBuffer('7e9059bbe','hex')>newBuffer('7e9059bbe.8ccd','hex')>newBuffer('7e9059bb','hex')

执行结果的比较

node由于会将原始数据7e9059bbe.8ccd中的e.及之后的数据进行截断,所以最终错误的值是7e9059bb,相比正确的值07e9059bbe小。

node的执行结果:

浏览器由于会将原始数据7e9059bbe.8ccd中的.吃掉,所以最终错误的值是7e9059bbe8ccd,相比正确的值07e9059bbe大很多。

浏览器的执行结果:

问题的原因

ethjs-util的intToBuffer函数不支持浮点型的数据,且在这个函数中没有判断传入的变量类型,来确保变量类型是预期内的。由于ethereumjs的toBuffer引用了ethjs-util的intToBuffer进行处理,也没有对数据进行检查。导致了这次事件的发生,所幸最终善良的矿工归还了「天价手续费7626ETH」。

吸取的教训

从第三方的库的角度来看,在编码过程中应该要遵循可靠的安全的编码规范,在函数的开头要对传入的数据进行合法性的检查,确保数据和代码逻辑是按照预期内执行。

从库的使用者的角度来看,使用者应该要自行阅读第三方库的开发文档和对接文档,并且也要对代码中接入第三方库的逻辑进行测试,通过构造大量的数据进行测试,确保业务上能够正常按照期望执行,保证高标准的测试用例的覆盖率。

参考资料:https://github.com/ethereumjs/ethereumjs-monorepo/issues/1497https://blog.deversifi.com/23-7-million-dollar-ethereum-transaction-fee-post-mortem/https://www.chainnews.com/news/611706276133.htm

郑重声明: 本文版权归原作者所有, 转载文章仅为传播更多信息之目的, 如作者信息标记有误, 请第一时间联系我们修改或删除, 多谢。

银河链

[0:15ms0-1:667ms