As with other programming languages such as C and Java, arithmetic overflow and underflow are vulnerabilities resulting from a shortage of space.
Their impact mostly depends on the context in which they are found. In this blog post, we will go through a vulnerability that allows an attacker to bypass security measure which was intended to prevent investors to withdraw their deposits before certain date/time.
Vulnerability
Imagine a smart contract that allows you to make a deposit of ether that you can receive only after 1 week.
As we can see, the smart contract implements deposit
, increaseLockTime
and withdraw
functions, the purpose of which is self-explanatory.
During the call of the deposit
function, we are added to the lockTime
property that maps our deposit address and associates it with the current timestamp + 1 week.
Now let's take a closer took at the withdraw
function, we can see that on line 19 the smart contract checks whether the current timestamp is greater than the one assigned to us during the deposit, i.e. whether one week has passed since the last deposit. If it is, the contract will send us our funds.
require(block.timestamp > lockTime[msg.sender], "Lock time not expired");
Also, the smart contract implements a function to increase the time of holding money, but not to decrease it, which would mean that we can only extend the time of locking the funds. As we see that the smart contract does not use the Safemath library, which would prevent overflow and underflow, and uses Solidity older than version 0.8.0 (in which we would receive an exception in case of overflow/underflow), it means that we are ready for an attack.
function increaseLockTime(uint _secondsToIncrease) public {
lockTime[msg.sender] += _secondsToIncrease;
}
Attack
In order to successfully exploit this vulnerability, we wrote an attacking smart contract that will first make a deposit, make use of the overflow vulnerability and withdraw funds without waiting for 1 week.
After we make the deployment of attack contract and call the attack function with the value for the deposit (2 ETH), we can see that the transaction went successfully and the balance of the attack smart contract is equal to 2 ETH, which confirms our attack.
Conclusion
In this blog post, we have covered a practical application of an overflow attack. Important parameters to remember that make a smart contract vulnerable to exploitation are using a solidity compiler version older than 0.8.0 without an explicit overflow/underflow check like the Safemath implementation.