eos源码解析(番外2):交易阻塞攻击之延时交易随机数漏洞详解

首先,我们来简要介绍一下dice合约。一轮游戏的过程大致如下:

1,用户调用transfer给dice转账,附带信息为自己的猜测数。

2,dice合约会创建一个start延时交易,交易的延时时间为1s。

3,执行start延时交易,在此交易中再创建一个bet延时交易,交易的延时时间为0s。

4,执行bet交易,在此交易中计算随机值。

在以上步骤中,合约自动发起了两次延时交易,随机数在第4步中产生。那么是依照什么产生随机数呢?

依照4个参数:

1,bet交易的id。

2,执行bet交易的时间。

3,bet交易的引用区块号。

4,bet交易的引用区块hash前缀。

也就是说,有了以上4个参数,我们便可知道合约产生的随机数是多少,便可知合约的开奖号码是多少。

所以说,这轮攻击的重点是:

1,提前预知系统的随机值。

2,在bet交易运行前发起阻塞攻击。

在这里,我们把dice合约的执行步骤加入时间轴来表示,假设在第100个区块中发起游戏。

dice漏洞.png

仔细观察上图,在第100个区块中发起交易。而随机数的产生在104个块。但是本质上,产生随机素的参数在102块出来时便已经知晓了。在104个块的时候我们来看看产生随机数的4个参数:

1,bet交易的id。bet交易的id取决于transaction_header:

   time_point_sec  expiration;  uint16_t        
   ref_block_num;  uint32_t       
   ref_block_prefix;  unsigned_int   
   net_usage_words;
   uint8_t          max_cpu_usage_ms;
   unsigned_int    delay_sec;

    其中, ref_block_num为102,ref_block_prefix为102的区块hash前缀。其余参数是可以计算得到。

2,执行bet交易的时间,这是可以预估的,应为每个块的时间都是固定的。

3,bet交易的引用区块号:102。

4,bet交易的引用区块hash前缀。即第102个块的hash前缀。

从以上分析可知,只要知道102个块的hash前缀,便可以知道最终的开奖结果。

我们在发起交易的第100个区块时,是无法预知第102个区块的hash前缀的,所以游戏的随机数是不可预知的。

但是,我们可以在104个块出来之前,快速获得102的hash前缀,自己求得随机值,如果随机值不是期望,则在104块时发起阻塞攻击。这样,bet的执行将会延后,从而影响产生随机数的参数2即执行bet的交易时间,进而控制整个开奖结果。

Eos.win在1月14号的时候更新了合约,去掉了bet交易执行时间即即参数2的影响。

[图片上传失败...(image-46b887-1548309101350)]

这样,看上去,随机数唯一受第102块的的hash前缀影响。但不要忘了,start交易本身是一个延时交易,我们可以对它进行影响,从而影响bet的引用区块hash前缀,这就是对start进行阻塞。

由于延时交易在区块内部是先于正常交易执行的,所以必须在start之前得到hash并更具随机结果进行阻塞。这个时候在第103区块发起交易是不能阻塞start的。

阻塞手法是:

在第100个区块构建一个1s的多个延时交易,使这些延时交易在103个区块时先于start执行。在这些延时交易的内部计算随机结果,如果随机结果不如期望,则进行死循环,从而阻塞start。

dice漏洞2.png

所以,建议在编写合约的时候充分考虑阻塞的问题。对此,笔者提出两种可行方案:

1,合约自行保存记录或者第三方导入一段时间的区块hash前缀。

2,固定随机值生成的区块高度,若随机值不在此规定区块高度生成,则按照游戏出错处理。

你可能感兴趣的:(eos源码解析(番外2):交易阻塞攻击之延时交易随机数漏洞详解)