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
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 ofX
(which is a smart contract). In the video you linked to, that variable is calledx
(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 slot1
. For a dynamic array, that means the length is stored at slot1
, and the actual array data starts atkeccak256(uint256(1))
. You've computed that as0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6
. The second element of the array will be at0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf7
, etc. (adding 1 each time).Now the trick is to figure out what element of the array occupies the same storage as
target
. Becausetarget
is the first state variable in the contract, it's located at slot0
. Due to integer overflow, we can also find this at 2**256. So we take2**256 - 0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6
, and that gives us our offset (array index).