本题目是一个以太坊智能合约题目
首先需要进行evm的逆向,逆向出整体程序功能
首先我们想要payforflag,需要有10w余额
function payforflag(string b64email) public {
require(balanceOf[msg.sender] >= 100000);
emit SendFlag(b64email);
}
可以逆向出一个存钱函数和一个空投函数
function deposit() payable{
uint geteth=msg.value/1000000000000000000;
balanceOf[msg.sender]+=geteth;
}
function profit() {
require(gift[msg.sender]==0);
gift[msg.sender]=1;
balanceOf[msg.sender]+=1;
}
还有一个betgame
function betgame(uint secretguess){
require(balanceOf[msg.sender]>0);
balanceOf[msg.sender]-=1;
if (secretguess==secret)
{
balanceOf[msg.sender]+=2;
isbet[msg.sender]=1;
}
}
只要能够猜对secret 我们就可以用1个token bet出来2个token
Secret可以通过直接读取链上信息获得,也可以利用如下漏洞进行修改
function Bet() public{
owner = msg.sender;
}
这里存在构造函数失控问题,通过执行Bet方法可以修改owner
修改owner后可以执行set secret方法
function setsecret(uint secretrcv) only_owner {
secret=secretrcv;
}
然后我们使用profit可以获得1个token 接下来执行betgame方法,可以获得两个token 并且把msgsender的isbet标志位变为1
因为我们已经是owner了 所以可以执行doublebetgame方法,在这里如果我们只有1个token的话,可以通过故意bet失败的方式,实现整形溢出
function doublebetgame(uint secretguess) only_owner{
require(balanceOf[msg.sender]-2>0);
require(isbet[msg.sender]==1);
balanceOf[msg.sender]-=2;
if (secretguess==secret)
{
balanceOf[msg.sender]+=2;
}
}
但是因为isbet标志位的问题,我们现在有两个token,所以我们可以再次执行一次betgame并故意输掉1个token,让我们的token数量保持在1从而执行doublebetgame实现溢出。最后payforflag
以太坊智能合约题目,首先需要对evm进行逆向。
目标是执行payforflag。
首先有一个空投函数:
function profit() public{
require(gift[msg.sender]==0);
gift[msg.sender]=1;
balanceOf[msg.sender]+=1;
}
然后我们向合约的转账会变成我们的余额
function hfvote() public payable{
uint geteth=msg.value/1000000000000000000;
balanceOf[msg.sender]+=geteth;
}
漏洞在ubw函数中:
function ubw() public payable{
if (msg.value < 2 ether)
{
node storage n = node0;
n.nodeadress=msg.sender;
n.nodenumber=1;
}
else
{
n.nodeadress=msg.sender;
n.nodenumber=2;
}
}
函数中的第二个分支不存在初始化,n在执行的时候会形成未初始化漏洞,那么只要我们进入第二个分支就会修改storage中的第一个值为我们的地址,第二个值为2
address secret;
uint count;
address owner;
第一个值为secret 因此通过未初始化漏洞我们可以执行onlySecret修饰的 fate函数,fate函数中存在整形溢出漏洞
require(balanceOf[msg.sender]-value>=0);
balanceOf[msg.sender]-=value;
balanceOf[to]+=value;
通过整形溢出,我们可以获得大量余额,然后payforflag即可获得flag:
function payforflag(string b64email) public {
require(balanceOf[msg.sender] >= 100000);
balanceOf[msg.sender]=0;
owner.transfer(address(this).balance);
emit SendFlag(b64email);
}