合约地址
0x421DbB4ca0Fdb1872e5780BD95743085357CD7B8
源代码
pragma solidity ^0.4.23;
contract Trans{
string flag;
mapping(address => uint256) balances;
constructor () public {
flag = WHAT_YOU_WANT;
}
function getBalance() public returns (bool){
balances[msg.sender] = 100;
return true;
}
function showBalance() public view returns (uint256){
return balances[msg.sender];
}
function Transfer(address[] _addr, uint256 _value) public returns (bool){
uint times = _addr.length;
uint256 amount = uint256(times) * _value;
require(_value > 0 && balances[msg.sender] >= amount);
require(times > 0 && times < 10);
balances[msg.sender] -= amount;
for(uint i = 0; i < times; i++){
balances[_addr[i]] += _value;
}
return true;
}
function getFlag() public view returns (string){
require(balances[msg.sender] > 9999999);
return flag;
}
}
这道题目就是一个整数溢出类型的漏洞
题目分析
首先通过分析getFlag
我们知道,我们的账号的余额必须大于9999999
getBalance
函数只是初始化账户为100
我们必须通过Transfer
函数来控制余额,首先是这个函数允许一个地址数组和一个uint256
整数值
相当于我们有一个账号,现在只有一百元,给10个账号发钱,然后发出去的钱从自己账号中扣除
但是整个过程中的操作都是用符号操作而没有用 safeMath
,再加上合约没有判断 amount 是否会溢出
uint256 类型能表示的范围是 0 ~ ((2 ** 256) - 1)
,因此我们可以让 amount
大于 ((2 ** 256) - 1)
。
payload:
["0x00E7aC6a5614Bcc4e131872B8Ae055D9ccFE4110","0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c"]
57896044618658097711785492504343953926634992332820282019728792003956564819968
第一个地址为自己的地址,第二个地址随便填就行(前提是合法的地址)
第二个值为2的255次方,由于是两个账号,所以总共扣除的值是2的256次方,大于最大值,使得溢出,则自己的账号不会扣钱
操作流程
这个简单描述一个整个过程,对于第一次接触的人来说,肯定会有很多坑
-
先在谷歌浏览器下载一个
METAMASK
插件
我分享一下百度网盘吧~~
链接:https://pan.baidu.com/s/1MBoPsDE7IPRtRY7z7hT_UA
提取码:wan9 -
然后就是常规的注册账号
-
选择测试网络
- 点击存入
-
点击测试水管
-
多点几下
然后你的账户就会由0变为1
-
访问这个http://remix.ethereum.org(有时需要科学上网)
当然这个可以自己本地搭建,但是我总是莫名其妙的问题,我就放弃了 -
选择环境
-
编译题目代码
-
配置题目合约
上面At Address
填入题目给的地址,然后下面就会出现几个按钮,这几个按钮就是对应代码的几个方法,只是相当于UI化了而已
接下来的工作就是审计代码,找出漏洞了,good lucky~