CTF-EKO-Phoenixtto
author:Thomas_Xu
从今天开始更新CTF-EKO系列,这貌似是ethernaut
靶场的研发团队举办的一个CTF。
题目链接:https://www.ctfprotocol.com/tracks/eko2022/phoenixtto
先来看第一个题:
在跨界世界中,有一个特殊的跨界世界,口袋妖怪、哈利波特和 solidity 的宇宙交织在一起。在这个交叉中,在邓布利多的凤凰之间创造了一个混合生物,一个野生的同上,因为我们在固体宇宙中,这个生物是一个合同。我们称它为 Phoenixtto,它有两个重要的能力,一个是在它被破坏后从它的灰烬中重生,另一个是复制另一个字节码的行为。
如果可以,请尝试捕获 Phhoenixtto…
这个题目描述还挺有意思,不过也给了我一点思路,灰烬中重生``复制字节码
听上去很有意思,难道和selfdestroy
有关?
还是先来看代码
1 | // SPDX-License-Identifier: MIT |
粗略一读代码,这里出现了Create2和selfdestruct,结合题目的暗示,我估计玄机就在此处。
但?这二者有什么联系吗?
先不管了,看看Factory吧,因为Factory能看到判题标准,我们目标才能更明确。
1 | function deploy(address _player) external payable override returns (address[] memory ret) { |
这里只帖出来deploy
和isComplete
就够了,从Factory我们可以了解到这个题只需要isCaught
返回true即可。
也就是说要Phoenixtto的owner变为我们自己。那很自然而然地,唯一显式修改owner的地方在capture里。
1 | `function capture(string memory _newOwner) external { |
这里要进入要修改owner的判断,其实并不复杂。
先来看看这个newOwner倒是是个啥吧:address newOwner = address(uint160(uint256(keccak256(abi.encodePacked(_newOwner)))));
如果熟悉以太坊账户的生成流程的话,应该很快就能看出来这里就是一个公钥到地址的一个转换,取了公钥哈希的最后20个字节。
那这个题就太简单了,只需要把自己公钥传进去就解题了。
这个点可能是EKO故意出的一个“签到题”,但其实这个题深入研究的话,还有一个真正的漏洞。
不难发现reBorn函数是比较关键的,我们重点分析:
1 | function reBorn(bytes memory _code) public { |
第一部分是Create,从Factory的调用可知,这里创建了Phoenixtto实例。该地址随后存储在状态变量中getImplementation
第二部分是个Create2,emmm这里用一串十六进制数重新赋值了code,看上去像是操作码,而Create2使用了这段操作码来初始化合约?这让我陷入短暂迷惑。
必须是一些有效的字节码,否则操作create2
会失败,对吧?
但是,这些字节码究竟是什么意义?我在EVM playground上模拟了一下,这一串字节码节码如下:
1 |
|
这里其实是有关Metamorphic Contracts的应用,相关链接:
0age变质合约的承诺与危险
在Jason Carver 的下一次以太坊升级中抵御“狂野魔法”
Metamorphic —由 0age创建变形(即可重新部署)合约的工厂合约
来自 a16zcrypto 的 Michael Blau 的检测变形智能合约的工具
这个概念背后的想法是能够更改合约中的代码并使其变形为其他东西。这利用了这样一个事实,即给定相同的输入,CREATE2 将始终将字节码部署到相同的地址。需要注意的一件重要事情是,使用的字节码是参数的一部分,也是用于生成地址的公式的一部分。因此,如果它发生变化,结果地址将因此发生变化。
所有的magic都是由部署的字节码中的内容完成的(始终相同)5860208158601c335a63aaf10f428752fa158151803b80938091923cf3
:. 只需几句话,它就会查询调用者,询问哪个是执行合约的地址,用作要部署的智能合约的源。
通过这样做,虽然部署的合约是动态的,但生成的地址始终是相同的。
而这里create2其实是使用的getImplementation的creationcode来部署的合约。应用此方法,Create2可以将不同的代码部署在一个地址上,从而实现“升级”。前提是旧合约必须被自毁,这样Create2再次在这个合约地址部署合约的时候才不会报错。
分析到这里,解题思路已经很清晰了,就是利用这个“升级”漏洞,把该地址变为我们自己的攻击合约。
Exploit
1 | // SPDX-License-Identifier: MIT |
true
...
...
This is copyright.