Recovery
1. 题目要求
1.1 合约创建者构建了一个非常简单的代币工厂合约。 任何人都可以轻松创建新代币。 在部署了一个代币合约后,创建者发送了
0.001
以太币以获得更多代币。 后边他们丢失了合约地址。如果您能从丢失的的合约地址中找回(或移除),则顺利通过此关。
1.2 题目代码
1 | // SPDX-License-Identifier: MIT |
2. 分析
tips: 参考博客
2.1合约地址是确定性的,可以从合约的部署者地址和来自部署者的部署交易的随机数中得出。
在这种情况下,我们从一开始就有这些信息:
- 合同部署者地址(我们的例子,在我的例子中
0xc03f501C5987CAaC9e4470849f13eEA338b76E9f
) - 部署第一个 SimpleToken 的随机数(1 如练习所述)
因此,我们可以轻松计算出第一个 SimpleToken 部署的合约地址,结果为
0xa26D4caf289D657F24f8d2D26f0DFe99a0B312db
.从技术上讲,这里很容易作弊,因为通过检查实例合约的内部交易,很容易在区块浏览器上看到我们要排空的合约的合约地址。然而,练习的目的是我们自己推导出地址。
有了这些信息,我们现在要做的就是调用
destroy()
SimpleToken 合约中的函数,并将其中的资金定向到任何地址,以便将练习标记为已完成。- 合同部署者地址(我们的例子,在我的例子中
2.2 做法:
一旦我们有了这两个细节(部署地址,随机数),就像我在解决方案中描述的那样,我们就可以在 python 中(或直接在 solidity 中)编写一个函数来获取地址。作为一个足智多谋的开发人员,即使我知道如何计算它,我仍然决定去 StackExchange 中找到一个现成的解决方案以跳过这个:
# compute address of a given contract to be deployed from # the deployer address + nonce, as stated in the Section 7 # of the Ethereum yellowpaper for contracts created using CREATE def mk_contract_address(sender: str, nonce: int) -> str: """Create a contract address using eth-utils. # Modified from Mikko Ohtamaa's original answer which was later # edited by Utgarda # Obtained from https://ethereum.stackexchange.com/questions/760/how-is-the-address-of-an-ethereum-contract-computed """ sender_bytes = to_bytes(hexstr=sender) raw = rlp.encode([sender_bytes, nonce]) h = keccak(raw) address_bytes = h[12:] return to_checksum_address(address_bytes)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- 然后,我们可以插入这些值并找到第一个 SimpleToken 部署的地址:
- > first_simpletoken_contract_address = mk_contract_address(recovery.address, 1)
- 连接到这个合约并调用`destroy()`函数,将资金发送到我的地址。
- > simpletoken.destroy(acc.address, _**from**)
- 攻击合约来自 [参考视频](https://www.youtube.com/watch?v=K8AFyNiuTXs)
```solidity
contract Dev {
function recover(address sender) external pure returns (address) {
address addr = address(uint160(uint256(
keccak256(abi.encodePacked(
bytes1(0xd6), bytes1(0x94), sender, bytes1(0x01)
))
)));
return addr;
}
}
3. 解题
- 3.1 获取实例地址:0x7802095a90641cd76543bc7df683d24D4bdd4436
- 3.2 部署Dev合约,调用合约中的recover() 函数,传入的形参为关卡实例
- 3.3 将调用recover() 函数 返回的地址带到区块链浏览器上查看交易
- 3.3 使用recover() 函数 返回的地址获取部署的SimpleToken合约,并将调用SimpleToken合约中的destroy() 函数,传入的形参为自己 的钱包地址
- 3.4 执行destroy() 函数之后,到区块链浏览器中再去查看地址的余额为0
- 3.5 提交案例
- 3.6 成功!!!!