Solidity – Handling Solidity Array Overflow

arraysoverflowsolidity

I'm trying to understand this array overflow attack on Solidity.
(https://www.youtube.com/watch?v=gUqHgFuSsqg)

In that video, the code is basically like this

pragma solidity ^0.4.17; 

contract ArrayOverflow{
    uint256 public target = 10;
    uint256[] public array = [9,8];

    function modifyArray (uint256 _index, uint256 _value){
        array[_index] = _value;
    }

    function popLength() public{
        // cause overflow
        array.length--;
    }

    function getLength() constant returns(uint256){
        return array.length;
    }

}

What he did is call popLength() three times to make the array overflowed.

After the above step, we can see the storage loaded is like this

enter image description here

So the 0xfffffff...fff is the length value.

Then we convert the hexadecimal value to address.

   web3.sha3('0x0000000000000000000000000000000000000000000000000000000000000001', {encoding: 'hex'})
// => 0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6

The following part is what I felt confused.

He exeuted the following command to find the address of target

perl -Mbigint -E 'say ((2**256 - 0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6 + 0)->as_hex)'

The output magically becomes the address of target, how does that happen?

Best Answer

I believe you mean the address of target, not the address of X (which is a smart contract). In the video you linked to, that variable is called x (lowercase).

https://programtheblockchain.com/posts/2018/03/09/understanding-ethereum-smart-contract-storage/ may help you understand the layout of storage.

array is the second state variable in the contract, so it's located at slot 1. For a dynamic array, that means the length is stored at slot 1, and the actual array data starts at keccak256(uint256(1)). You've computed that as 0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6. The second element of the array will be at 0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf7, etc. (adding 1 each time).

Now the trick is to figure out what element of the array occupies the same storage as target. Because target is the first state variable in the contract, it's located at slot 0. Due to integer overflow, we can also find this at 2**256. So we take 2**256 - 0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6, and that gives us our offset (array index).

Related Topic