整数溢出
2018年4月,BeautyChain(BEC)代币上发生了一起涉及整数溢出漏洞的重大事件。 该漏洞使攻击者能够凭空生成大量的BEC代币,导致了巨额财务损失,并削弱了该代币的价值。
有关BeautyChain事件的更详细信息,您可以访问以下资源:
- An overview of the vulnerability can be found on the CVE-2018-10299 page at Tenable.
- Detailed discussions of the event and its implications on smart contract security are available on PeckShield's blog and in a Medium article.
These sources provide a comprehensive look at how such vulnerabilities can be exploited and the profound impacts they can have on digital assets.
Integer overflow vulnerability (Arithmetic Over/Under Flows) is a classic issue in programming that became less common in Solidity starting from version 0.8 due to the integration of the SafeMath library.
The Ethereum Virtual Machine (EVM) sets fixed sizes for integers, thus they can only represent numbers within a specific range. For example, a uint8
can only represent numbers within the range of [0,255]. Assigning the value 257
to a uint8
type variable results in an overflow, changing the value to 1
; similarly, assigning -1
results in an underflow, changing the value to 255
.
Attackers can exploit this vulnerability: imagine a hacker with a balance of $0
spends $1
, their balance could suddenly turn to $2^256 - 1
.
Vulnerable Contract Example
This example is a simple token contract inspired by the Ethernaut
contracts. It features 2
state variables: accounts
records each address's balance, supplyCap
represents the total token supply.
It includes 3
functions:
constructor()
: Initializes the total token supply.send()
: Function for transferring tokens.getBalance()
: Function to check balance.
The vulnerability in the send()
function occurs because the check require(accounts[msg.sender] - _amount >= 0);
always passes due to integer overflow, allowing users to transfer unlimited tokens.
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
contract Asset {
mapping(address => uint) accounts;
uint public supplyCap;
constructor(uint _startingSupply) {
accounts[msg.sender] = supplyCap = _startingSupply;
}
function send(address _recipient, uint _amount) public returns (bool) {
require(accounts[msg.sender] - _amount >= 0);
accounts[msg.sender] -= _amount;
accounts[_recipient] += _amount;
return true;
}
function getBalance(address _owner) public view returns (uint balance) {
return accounts[_owner];
}
}
预防策略
-
Before Solidity
0.8.0
, use the SafeMath Library in contracts to throw an error in case of integer overflow. -
After Solidity
0.8.0
, SafeMath is built in, making such issues rare. However, developers sometimes use theunchecked
block to save gas by temporarily disabling integer overflow checks. For additional information on this technique and its implications for gas optimization, refer to the Gas Optimization - Unchecked guide. Always ensure there is no potential for integer overflow vulnerabilities when using this approach.