最新消息:本站技术交流 QQ 群:28124927

数学溢出攻击演练与防范

区块链/比特币 exchen 1382浏览 0评论

数学溢出攻击演练与防范

一个数字在内存中是有范围的,如果超出这个范围就会溢出,比如 uint256 是无符号的整数,范围是256位,最大的数字范围是 2的256次方减1,最小的范围是 0,如果超过范围是上溢,低于范围是下溢。

(1) 已知 uint256 最大的范围是2的256次方减1,即 2**256-1,如果比这个数大1,发生上溢1,会回到数值0,如果上溢2,会回到数值1,以此类推。

(2) 一个数字小于0,出现下溢,比如 -1 会回到 2**256-1,-2 会回到 2**256-2,以此类似,这个数会是一个巨大的数。

数学溢出攻击的示例代码:https://solidity-by-example.org/hacks/overflow

具体代码

合约 A 的功能是一个时间锁,名称是 TimeLock,有三个函数,第一个函数是存币 deposit,在这个方法里给用户增加完余额后会记录用户的锁定时间,锁定时间是当前时间加上一周。第二个函数是增加锁定时间 increaseLockTime,有一个参数是增加的时间,如果攻击者给出一个小于零的数(负数)造成下溢,此时锁定时间就被减少,而不是增加。第三个函数是取币 withdraw,会判断锁定时间,当前时间必须大于用户的锁定时间才能取币。

下面是合约B,名称是 Attack,用于攻击测试,主要是4个函数,deposit 用于存币,withdraw 用于取币,attack 用于攻击,它会调用增加锁定时间的函数,先获取当前合约地址在 TimeLock 合约里的锁定时间,再给这个时间置为负数,实现下溢,一个正数加上他对应的负责等于0,这样实现了修改锁定时间。

演练过程

布署完两个合约之后,Attack 先调用 deposit 存一个币,再使用 withdraw 取币,发现提示错误,因为锁定了一周时间,要一周之后才能取,如下图所示:

可以再看一下在 TimeLock 合约里看到锁定时间为 1657272481,如下图所示:

我们调用 attack 函数增加锁定时间,参数给一个负数,正数减去对应的负数结果为 0,再查看 lockTime 为 0,再点击 withdraw 就可以取币,如下图所示。

防范

为了防止数学溢出,可以使用 OpenZeppelin 里的 SafeMath,再调用加法的时候,使用 add 函数,代码修改如下:

这时我们再次尝试攻击,存币后,再取币就会提示溢出,无法完成取币操作,如下图所示:

我们来看一下 SafeMath 里如何实现 add 函数的,代码里可以看出,会验证相加后的结果是否大于或等于原来的数,如果相加的结果反而比原来的小,那说明产生的溢出。

转载请注明:exchen's blog » 数学溢出攻击演练与防范

发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址