智能合约安全审计入门篇——溢出漏洞慢雾科技
企业专栏
热度: 846
智能合约安全审计入门系列之溢出漏洞
By:小白@慢雾安全团队
背景概述
上周我们介绍了智能合约安全审计入门篇 —— 重入漏洞,本文则继续介绍另一种经典的漏洞 —— 溢出漏洞。
前置知识
我们先来了解一下溢出的概念:算术溢出(arithmetic overflow)或简称为溢出(overflow)分为两种:上溢和下溢。上溢指在运行单项数值计算时,当计算结果非常大,超过寄存器或存储器表示范围,会发生上溢。在 solidity 中,当使用 uint8 类型运算时计算结果超过 0-255 范围,就会发生上溢,这时计算结果为 0。下溢指计算结果非常小,低于表示范围。在 Solidity 中,当使用 uint8 类型计算 0-1 时,会发生下溢,这时计算结果为 255。智能合约中的溢出漏洞会导致计算结果与预期结果差别巨大,轻则损害合约逻辑,重则导致资金损失。溢出漏洞存在版本限制,在 Solidity < 0.8 时不会报错,而在 Solidity >= 0.8 时会报错,所以需要注意合约版本。
漏洞示例
本次漏洞示例为 TimeLock 合约,时间保险库。用户可以通过 deposit 函数存入代币,至少保管一周。用户可以通过 increaseLockTime 函数延长保管时间。withdraw 函数中检查了余额和锁定时间。当余额大于 0 且锁定时间已过一周时,用户的代币即可提取。
/SPDX-License-Identifier: MITpragma solidity ^0.7.6;
contract TimeLock { mapping(address => uint) public balances; mapping(address => uint) public lockTime;
function deposit() external payable { balances[msg.sender] += msg.value; lockTime[msg.sender] = block.timestamp + 1 weeks; }
function increaseLockTime(uint _secondsToIncrease) public { lockTime[msg.sender] += _secondsToIncrease; }
function withdraw() public { require(balances[msg.sender] > 0, Insufficient funds); require(block.timestamp > lockTime[msg.sender], Lock time not expired);
uint amount = balances[msg.sender]; balances[msg.sender] = 0;
(bool sent, ) = msg.sender.call{value: amount}(); require(sent, Failed to send Ether); }}
漏洞分析
我们可以