BlockChain

Solidity 취약점 #2

부산대보금자리 2022. 1. 12. 17:59

1. Transfer forwards all gas

본적으로스는 트랜잭션을 호출한 sender 지불하도록 되어 있는데 이는 가지 공격 가능성을 열어둔다.

 

  1. 공격자가 트랜잭션을 보내도록 유도한다.
  2. 트랜잭션이 많은 가스를 소모하도록 유도한다.

 

 

Call 함수는 Caller 컨트랙트의 Fallback Function invoke하고 재진입 공격이 가능하다. 이는 번째 공격이 가능하게 하며 번째는 공격자의 트랜잭션에 포함되는 매개변수 또는 개발자의 잘못된 로직으로 인한 가스를 요하는 잦은 실행이 유도된다.

  재진입 공격과 유사하게 진행되며 예방 방법 또한 같은 선상에 있다.

 + (Supplement)

 

 

2. DOS

용자가 일정 기간 또는 영구적으로 컨트랙트를 실행할 없게 만드는 공격이다.

 

기본적으로 EVM 강제 종료를 통해 DOS공격으로부터 프로그램을 보호한다. EVM 실행 시작 가스를 할당하고 실행 단계에서 가스의 소모가 이루어지는데 남은 가스가 실행에 필요한 가스보다 적으면 스마트 컨트랙의 실행을 종료하여 부분 또는 전체 Rollback 유발한다

 

 

  1. Dos costly patterns and loops

 

인위적으로 부풀려질 있는 배열을 사용해서 배열 크기를 크게 만들면 for루프를 실행하는데 요구되는 가스가 가스 한도를 초과하게 된다. 그렇게 되면 함수가 원하는 대로 동작하지 않게 만들 있다.

 

1-1) arr manipulate하여 addr 추가하고 이를 통해 reverting 을 일으켜 DOS 유발

(Code Check 필)

 

1-2) 가변의 arr길이의 length로 for문이 돌기 때문에 매우 값으로 인한 gas cost 초과되고 이로 인해 DOS 유

 

// SPDX-License-Identifier:GPL-30

pragma solidity >=0.5.0 <0.9.0;

 

contract testLL{

    uint constant LARGEGAS = 100000;

    address payable addrArr;

    function LongList(uint256 memory nextV, uint[] memroy arr, address payable _addr) public{

        uint256 i = nextV;

        addrArr = _addr;

        for(;i<arr.length && gasleft() > LARGEGAS; i++){

            addrArr.send(arr[i]);

        }

    }

}

 

=> Arr라는 배열 변수를 외부로부터 입력받는다.

 

  • 문제 요인 해결

루프의 조건에 외부 사용자가 인위적으로 조작할수 있는 변수를 사용하였다.

때문에 외부로 부터 가변 길이의 변수를 받지 않는 쪽과 중요 로직에 외부 변수를 사용하지 않도록 점검과 수정이 필요하다.

 

 

  1. Dos by external contract

외부 호출을 기반으로 진행상태를 갖는 컨트랙트에서 발생할 있다.

 

// SPDX-License-Identifier:GPL-30

pragma solidity >=0.5.0 <0.9.0;

contract sender{

    address payable emperor;

    uint public rewardPrice = 500;

    function set_empr(address _addr) public{

        emperor = _addr;

    }

    function() external payable{

        require(msg.value >= rewardPrice);

        uint MCrownPrice = MfindCrownPrice();

        emperor.transfer(MCrownPrice);

        (bool success, ) = emperor.call.value(MCrownPrice)("");

        require(success);

        // After logic

    }

}

contract Receiver(){

    function() external payable{

        revert();

    }

}

 

Transfer또는 send 통해 컨트랙트에게 일정 금액을 전송하는 코드를 생각해 있다.

Transfer는 실패 자체적으로 에러를 일으키고 call의 경우 True,False를 입력 받아 exception Control한.

하지만 Receiver입장에서 이를 모두 revert시켜 버리면 Control Flow 틀어지지는 않지만 더이상 실행이 되지 않는 DOS공격으로 되돌아 온다.

 

  • 문제 요인 해결

외부 호출에 대한 의존성이 문제점이라 있다.

하지만 이러한 호출이 불가피한 경우도 존재할 것이기에 호출 이후의 검증 로직이 충분하지 못한 것이 원인이라 여겨진다.

Call의 경우 false 경우 lock time 걸어두거나 다른 로직을 실행하도록 수정한다면 좋을 것이다.

 

 

 

3. TimeStamp Dependency

 

BlockChain내의 블록에는 1) Timestamp, 2) Cryptographic hash, 3) Transaction Data 가지 정보가 포함되어 있다.

 

TimeStamp 채굴자가 작업 증명 퍼즐을 계산한 블록 모든 거래를 검증하는 시간을 나타낸다.

채굴자는 이러한 Block TimeStamp 조작할 있다.(= 900 이내 검증완료)

 

암호화 해시는 블록 데이터의 무결성을 확인하기 위한 해시값이다. 암호화 해시는 블록을 연결하는 종속적 의미를 가진다.

 

거래 데이터는 거래에 따라 다를 있지만 간단한 트랜잭션의 경우 발신자와 수신자의 SC계정 주소와 이더가 있다.

 

Ex>

 

// SPDX-License-Identifier:GPL-30

pragma solidity >=0.5.0 <0.9.0;

contract Lotto{

    uint pubic pastBlockTime;

    constructor() pubic payable{}

    function() public payable{

        require(msg.value == 10 ether);

        require(now != pastBlockTime); // 블록당 오직 하나의 트랜잭션만 가능

        pastBlockTime = now;

        if(now %15 ==0){

            msg.sender.transfer(address(this).balance);

        }

    }

}

 

코드는 복권을 스마트 컨트랙트로 만든 예시이다.

채굴자에 의해 생성된 pastBlockTime을 통해 당첨여부를 판단하게 되며 이는 하나의 트랜잭션만 허용한다.

이를 채굴하는 채굴자는 Timestamp 조정해 당첨을 유도할수 있다.

 

  • 문제 요인 해결

스마트 컨트랙트는 난수 생성을 위해 타임스탬프를 사용한다. 그렇다면 타임스탬프의 값을 설정하는 채굴자가 관여하기 때문에 타임스탬프는 소위 결정적 임의 값이 된다.

만약 복권 구현과 같은 컨트랙트에서 타임스탬프를 임의 값으로 사용한다면 이는 취약한 코드가 밖에 없다.

이에 대한 코드는 block.timestamp now 같이 사용된다.

 

이를 막기 위해선 블록 Timestamp 특정 조건 체크를 위한 요소로 사용하면 안된다.

하지만 시간과 관련된 조건이 필요한 경우가 있다. 예를 들어 컨트랙트가 해지되는 시간, 만기일 적용과 같은 시간 관련 조건이 있을 경우에는 블록의 타임스탬프를 사용하지 말고 block.number과 평균 블록 시간을 사용해서 설정하는 것이 좋다.

 

'BlockChain' 카테고리의 다른 글

Solidity 취약점 #4  (0) 2022.01.14
Solidity 취약점 #3  (0) 2022.01.13
Solidity 취약점 #1  (0) 2022.01.11
Solidity 취약점 카테고리화  (0) 2022.01.11
Solidity #5  (0) 2022.01.10