SWC-124/写入任意存储位置
智能合约的数据(例如,存储合约的所有者)被永久存储在EVM的某个存储位置。合约负责确保只有 授权的用户或合约帐户才能写入敏感的存储位置。如果攻击者能够写入合约的任意存储位置,则可以 很容易地规避授权检查。这可能使攻击者破坏存储;例如,通过覆盖存储合约所有者地址的字段。
CWE漏洞分类
整改方案
作为一般性建议,鉴于所有数据结构共享相同的存储(地址)空间,应确保对一个数据结构的写入 不会无意间覆盖另一数据结构的条目。
参考文献
合约示例
random_location_write_simple.sol
pragma solidity ^0.4.25;
contract Wallet {
uint[] private bonusCodes;
address private owner;
constructor() public {
bonusCodes = new uint[](0);
owner = msg.sender;
}
function () public payable {
}
function PushBonusCode(uint c) public {
bonusCodes.push(c);
}
function PopBonusCode() public {
require(0 <= bonusCodes.length);
bonusCodes.length--;
}
function UpdateBonusCodeAt(uint idx, uint c) public {
require(idx < bonusCodes.length);
bonusCodes[idx] = c;
}
function Destroy() public {
require(msg.sender == owner);
selfdestruct(msg.sender);
}
}
random_location_write_simple.yaml
description: Simple variant of write to arbitrary storage location
issues:
- id: SWC-124
count: 1
locations:
- bytecode_offsets:
'0x4d778370f4fe1789bc427ab08efc768fcb4c6c8b68d2ee41178340423445bd45': [294]
line_numbers:
arbitrary_location_write_simple.sol: [26]
random_location_write_simple_fixed.sol
pragma solidity ^0.4.25;
contract Wallet {
uint[] private bonusCodes;
address private owner;
constructor() public {
bonusCodes = new uint[](0);
owner = msg.sender;
}
function () public payable {
}
function PushBonusCode(uint c) public {
bonusCodes.push(c);
}
function PopBonusCode() public {
require(0 < bonusCodes.length);
bonusCodes.length--;
}
function UpdateBonusCodeAt(uint idx, uint c) public {
require(idx < bonusCodes.length); //Since you now have to push very codes this is no longer an arbitray write.
bonusCodes[idx] = c;
}
function Destroy() public {
require(msg.sender == owner);
selfdestruct(msg.sender);
}
}
random_location_write_simple_fixed.yaml
description: Simple variant of write to arbitrary storage location
issues:
- id: SWC-124
count: 0
locations: []
mapping_write.sol
pragma solidity ^0.4.24;
//This code is derived from the Capture the Ether https://capturetheether.com/challenges/math/mapping/
contract Map {
address public owner;
uint256[] map;
function set(uint256 key, uint256 value) public {
if (map.length <= key) {
map.length = key + 1;
}
map[key] = value;
}
function get(uint256 key) public view returns (uint256) {
return map[key];
}
function withdraw() public{
require(msg.sender == owner);
msg.sender.transfer(address(this).balance);
}
}
mapping_write.yaml
description: Write to arbitrary storage location using dynamic arrays
issues:
- id: SWC-124
count: 1
locations:
- bytecode_offsets:
'0xb3f8b66f8449fff6ee9ba17ae5534dfb2d8f4c4281c8a9ad56c1354a55c389d3': [395]
line_numbers:
mapping_write.sol: [14]