Written by WeaponX@零时科技
本文所有过程均在本地测试节点完成
文章用到的所有代码均在 https://github.com/NoneAge/EOS_dApp_Security_Incident_Analysis
0x00 背景
零时科技监测到,EOSDice在2018年11月10日受到黑客攻击,根据EOSDice官方通告,此次攻击共被盗4,633 EOS,约合 2.51 万美元(2018年11月10日价格 1 EOS ≈ 5.42 USD)。
0x01 技术分析
2018年11月3日,也就是一周前,EOSDice因为dApp中存在可被预测随机数漏洞被黑客攻击,在前一篇文章中已经分析过了黑客的攻击手法《EOS dApp 漏洞盘点-EOSDice弱随机数漏洞1》。然而,上次的官方修复仍然存在问题,导致再次被黑客攻击。
我们再来分析一下EOSDice上次遭受攻击后官方的修复方法:
开奖action由一次defer改为两次defer
https://github.com/loveblockchain/eosdice/commit/50a05dfb6c0d68b6035ed49d01133b5c2edaefdf
我们做了一个示意图,
可以看到,通过两次defer action开奖的时候,开奖action的refer block为下注的block,下注前无法预测。
账户的余额用很多账户的总和加起来当成随机数种子
https://github.com/loveblockchain/eosdice/commit/3c6f9bac570cac236302e94b62432b73f6e74c3b
本次修改看似无懈可击,不过还有一点EOSDice官方没有想到。我们来看看eosio.token的转账代码。
可以看到,当A账户给B账户转账的时候,转账通知会先发送给A账户,再发送给B账户。那么,黑客可以部署一个攻击合约,当黑客通过此账号来进行游戏的时候,攻击合约肯定先于EOSDice官方合约收到转账通知。黑客可以同样做一个两次defer action来预测随机数
下图是利用攻击合约预测随机数。
可以看到,黑客完全可以通过攻击合约来预测随机数的结果。不过,问题来了由于使用了两次defer action进行开奖,那么这个结果是黑客无法在下注前得到的。因此,黑客要对EOSDice进行攻击只能另辟蹊径。
因为EOSDice中,随机数种子是很多账户余额的总和,黑客完全可以通过计算能让黑客稳赢的状态下这个余额的值,然后在给任意账户转账即可控制EOSDice的随机数结果。下面,我们 编写一个测试合约进行试验
在这个攻击合约里,我们模仿了EOSDice同样进行了两次defer action。在第二次defer action中,我们计算出随机数小于6的情况下,需要的总余额比原先的增加多少,然后利用一个inline action向eosbiggame44账户转账,因为攻击合约先于EOSDice官方合约执行,所以最终控制了EOSDice的随机数结果。
测试流程:
1.创建相关账户并设置权限
2.向相关账户充值
3.编译相关合约并部署
4.初始化EOSDice合约
5.进行游戏
然后,我们来看看测试结果
经过攻击合约多次计算,找到只需要余额比之前多0.0021 EOS即可让本次投注中奖,然后再向eosbiggame44转入了0.0021 EOS,最终中奖,获得了19.7000 EOS(投入1 EOS)。
可以看到,利用攻击合约来控制EOSDice的随机数,可以达到必中的效果!
0x02 官方修复
官方修复很简单,在随机数算法中将账户余额这个可控因子删除了。
上述的攻击合约便无法通过转账控制随机数的结果。
0x03 推荐修复
如何得到安全的随机数是一个普遍的难题,但是在EOS上尤其困难,因为EOS并不提供随机数接口。所以随机数的种子必须得自己选择,选择种子的准则就是无法被提前预知。零时科技安全专家推荐参考EOS官方的随机数生成方法来生成较为安全的随机数
https://developers.eos.io/eosio-cpp/docs/random-number-generation
0x04 REFER
https://developers.eos.io/eosio-cpp/docs/random-number-generation
https://github.com/loveblockchain/eosdice/tree/f1ba04ea071936a8b5ba910b76597544a9e839fa