抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

前言

📌 在做 damn defibackdoor挑战时,关于如何才能让 proxy合约给 hacker执行 approve授权操作,引发的深思。

我们知道,delegatecall是很特殊的调用方式,委托调用,代码是在逻辑合约 Proxy中执行。

如果我们通过这种方式执行 Caller --call--> Proxy --delegatecall--> Logic1 --delgatecall--> Logic2

Logic2来说,如若其函数体呢有 msg.senderaddress(this)变量的话,

易知,此时的 msg.sender = address(Caller), address(this) = address(Proxy)

📌 但是,如果在 delegatecall传递链上出现了call那么就很离谱了。

1. 多重传递

按如下传递链进行函数的调用。

Caller --call--> Proxy --delegatecall--> Logic1 --delgatecall--> Logic2 --call--> Logic3

关键看 Logic3msg.senderaddress(this)的变化。

2. 代码演示

代码是不能正常运行的,不过不重要,我只要函数的调用过程即可。

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
76
77
78
79
80
81
82
83
84
85
86
87
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "hardhat/console.sol";

/**
Caller --call--> Proxy --delegatecall--> Logic1 --delgatecall--> Logic2 --call--> Logic3

request: find Logic3's msg.sender is or not address(proxy)
*/

contract Caller{
address public proxy;

constructor(address proxy_){
proxy = proxy_;
}

function delegatecall_approve(address _logic2, address _logic3) external returns(bool , address) {
console.log("Caller_address= ", address(this));
(bool success , bytes memory data) = proxy.call(abi.encodeWithSignature("funLogic1(address,address)", _logic2, _logic3));
return (success, abi.decode(data,(address)));
}

}

contract Proxy {

address public implementation;

constructor(address implementation_){
implementation = implementation_;
}

fallback() external payable {
_delegate();
}

function _delegate() public {
address _implementation;
console.log("Proxy_address= ", address(this));
assembly {
_implementation := sload(0)
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), _implementation, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 {
revert(0, returndatasize())
} default {
return(0, returndatasize())
}
}
}
}

contract Logic1 {

address public implementation;

function funLogic1(address _logic2, address _logic3) external {
console.log("Logic1_msg.sender= ", msg.sender);
console.log("Logic1_address= ", address(this));
_logic2.delegatecall(abi.encodeWithSignature("funLogic2(address)",_logic3));
}
}

contract Logic2 {

address public implementation;

function funLogic2(address _logic3) external {
console.log("Logic2_msg.sender= ", msg.sender);
console.log("Logic2_address= ", address(this));
_logic3.call(abi.encodeWithSignature("funLogic3()"));
}
}

contract Logic3 {

address public implementation;

function funLogic3() external {
console.log("Logic3_msg.sender= ", msg.sender);
console.log("Logic3_address= ", address(this));
}
}

3. 运行结果

image-20230726164349143

📌 由结果不难看出,对 Logic3来说,ta 的调用者已成为了 Proxy合约,且address(this)也是ta本合约的地址了,我之前做题的时候想破脑袋都不知道怎么做到让 代理合约给 Hack 合约授权,因为我最开始认为,在 Logic2中执行 call,相对于Logic3来说 调用者应该是 Logic2才对,想了一天实在受不了了,只能实践出真知了。md。。。。结果真的是出乎我的认知。

评论



政策 · 统计 | 本站使用 Volantis 主题设计