点击标题下「零时科技」可快速关注
Written by WeaponX@零时科技
本文所有过程均在本地测试节点完成
文章用到的所有代码均在 https://github.com/NoneAge/EOS_dApp_Security_Incident_Analysis
0x00背景
EOSDice
在2018年11月3日受到黑客攻击,根据EOSDice
官方通告,此次攻击共被盗2,545.1135 EOS
,约合 1.35 万美元(2018年11月4日价格 1 EOS ≈ 5.13 USD)。
0x01技术分析
由于EOSDice
被攻击是因为该游戏的的随机数算法被破解,而且使用的defer action
进行开奖。那我们具体分析一下EOSDice
因为EOSDice
的合约已经开源,我们从Github
上找到了EOSDice
的随机数算法:
https://github.com/loveblockchain/eosdice/blob/f1ba04ea071936a8b5ba910b76597544a9e839fa/eosbocai2222.hpp#L172
可以看到,EOSDice
官方的随机数算法为6个随机数种子进行数学运算,再哈希,最后再进行一次数学运算。EOSDice
官方选择的随机数种子为
-
tapos_block_prefix # ref block的信息
-
tapos_block_num # ref block的信息
-
account_name # 本合约的名字
-
game_id # 本次游戏的游戏id,从1自增
-
current_time # 当前开奖的时间戳
-
pool_eos # 本合约的EOS余额
其中随机数种子account_name
、game_id
、pool_eos
很容易获取到,那么如果需要预测随机数,必须要预测所有的随机数种子,也就是 说current_time
、tapos_block_prefix
、tapos_block_num
也要可以预测。
-
那么,首先分析
current_time
是否可以预测
根据EOS
官方的描述
其实返回的就是一个时间戳,由于EOSDice
开奖使用的是defer action
,因此,我们只需要知道下注的action
的时间戳再加上delay_sec
就可以算出开奖reval
的时间戳了。EOSDice
的delay_sec
为1秒,所以开奖时时间戳 = 下注时时间戳 + 1000000
。
-
接着,我们分析
tapos_block_prefix
和tapos_block_num
是否可以预测
其实,tapos_block_prefix
和tapos_block_num
均为开奖block
的ref block
的信息。EOS
为了防止分叉,所以每一个block
都会有一个ref block
也就是引用块。因为reveal
开奖的块在下注前并不知道,它的ref block
看似也不知道,所以貌似这两个种子是未来的值。不过,根据EOS
的机制,因为开奖采用的是defer action
,所以reveal
开奖块的ref block
为下注块的前一个块,也就是说tapos_block_prefix
和tapos_block_num
是在下注前可以获取到的!
至此,EOSDice
的随机数种子在下注前均可以获取,那就意味着我们可以在下注前预测到下注后的随机数,完全可以达到必中的效果。
下面是我们测试攻击的合约,完成的功能是根据EOSDice
的随机数算法来预测此次下注的随机数的值,然后选择roll
的值比预测值大一即可中奖。
EOSDice
开奖action
的tapos_block_prefix
和tapos_block_num
,发送给测试攻击的合约。
-
创建相关账户并设置权限
# 创建EOSDICE相关账户和权限
cleos create account eosio eosbocai2222 EOS6xKEsz5rXvss1otnB5kD1Fv9wRYLmJjQuBefRYaDY7jcfxtpVk
cleos set account permission eosbocai2222 active '{"threshold": 1,"keys": [{"key": "EOS6kSHM2DbVHBAZzPk7UjpeyesAGsQvoUKyPeMxYpv1ZieBgPQNi","weight": 1}],"accounts":[{"permission":{"actor":"eosbocai2222","permission":"eosio.code"},"weight":1}]}' owner -p eosbocai2222
# 创建攻击者相关账户机器权限
cleos create account eosio attacker EOS6xKEsz5rXvss1otnB5kD1Fv9wRYLmJjQuBefRYaDY7jcfxtpVk
cleos set account permission attacker active '{"threshold": 1,"keys": [{"key": "EOS6kSHM2DbVHBAZzPk7UjpeyesAGsQvoUKyPeMxYpv1ZieBgPQNi","weight": 1}],"accounts":[{"permission":{"actor":"attacker","permission":"eosio.code"},"weight":1}]}' owner -p eosbocai1111
-
给相关账户发送代币
cleos push action eosio.token issue '["attacker", "10000.0000 EOS", "memo"]' -p eosio
cleos push action eosio.token issue '["eosbocai2222", "10000.0000 EOS", "memo"]' -p eosio
-
编译相关合约并部署
# 编译攻击合约
eosiocpp -o attack.wast attack.cpp
eosiocpp -g attack.abi attack.cpp
# 部署攻击合约
cleos set contract ~/attack -p attack@owner
# 编译EOSDICE合约
eosiocpp -o eosdice.wast eosbocai2222.cpp
eosiocpp -g eosdice.abi eosbocai2222.cpp
# 部署EOSDICE合约
cleos set code eosbocai2222 eosdice.wasm -p eosbocai2222@owner
cleos set abi eosbocai2222 eosdice.abi -p eosbocai2222@owner
-
初始化
EOSDice
合约
cleos push action eosbocai2222 init '[""]' -p eosbocai2222
最后,我们来测试一下,我们可以很容易的获取到下次投注的game_id
,此次为109。
python script.py 109
我们看一下合约的执行结果,可以看出,攻击合约预测的随机数和EOSDice
的开奖action
算出来的完全一致!这样就可以达到每次必中!
0x02官方修复
官方修复其实很简单:
-
开奖的
action
由一次defer action
变成了两次defer action
https://github.com/loveblockchain/eosdice/commit/50a05dfb6c0d68b6035ed49d01133b5c2edaefdf
-
账户的余额用很多账户的总和加起来当成随机数种子
https://github.com/loveblockchain/eosdice/commit/3c6f9bac570cac236302e94b62432b73f6e74c3b
首先,开奖的action
由一次defer action
变成了两次defer action
,根据前面我们提到的内容,defer action
的ref block
为发起defer action
的前一个块。但是,在我们下注的时候这个块是无法预知的;其次,EOSDice
的账户余额用了很多账户的余额的总和来当种子,这个貌似也是无法预测变化的。不过这样真的安全了吗?很明显,不是的,仅在6天后EOSDice
再次受到随机数攻击,下篇文章我们会详细分析第二次攻击。
0x03推荐修复
如何得到安全的随机数是一个普遍的难题,但是在EOS
上尤其困难,因为EOS
并不提供随机数接口。所以随机数的种子必须得自己选择,选择种子的准则就是无法被提前预知。零时科技安全专家推荐参考EOS
官方的随机数生成方法来生成较为安全的随机数
0x04Refer
https://blog.csdn.net/TurkeyCock/article/details/84730045
https://igaojin.me/2018/11/04/EODIDEC-%E9%9A%8F%E6%9C%BA%E6%95%B0%E8%A2%AB%E6%94%BB%E7%A0%B4/
https://developers.eos.io/eosio-nodeos/reference#get_block
https://github.com/loveblockchain/eosdice/tree/f1ba04ea071936a8b5ba910b76597544a9e839fa
https://developers.eos.io/eosio-cpp/docs/random-number-generation
零时科技
NoneAge
深圳零时科技有限公司,专注于区块链安全领域。公司团队由从事安全技术研究和安全服务多年且经验丰富的高级网络安全专家组成,为客户提供专业的安全服务和安全解决方案。
原文始发于微信公众号(零时科技):EOS dApp 漏洞盘点-EOSDice弱随机数漏洞1
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论