재진입 공격의 클러치에서 스마트 계약을 탈출하는 방법? PlatoBlockchain 데이터 인텔리전스. 수직 검색. 일체 포함.

재진입 공격의 클러치에서 스마트 계약을 탈출하는 방법?

읽기 시간: 6

우리가 가장 큰 암호화폐 해킹과 그들이 잃어버린 눈에 띄는 수치를 면밀히 살펴보면 코딩 결함에 뿌리를 두고 있을 것입니다.

이러한 일반적인 보안 취약점 중 하나는 재진입 공격입니다. 그러나 잘못 처리된 재진입으로 인해 발생하는 파괴적인 효과는 공격 자체를 시작하는 것처럼 간단하게 들리지 않을 수 있습니다.

친숙하고 잘 알려진 문제임에도 불구하고 스마트 계약에서 재진입 버그의 출현은 항상 불가피합니다. 

지난 몇 년 동안 해커가 Reentrancy 취약점을 얼마나 자주 악용했습니까? 어떻게 작동합니까? 스마트 계약이 재진입 버그로 인한 자금 손실을 방지하는 방법은 무엇입니까? 이 블로그에서 이러한 질문에 대한 답을 찾으십시오.

머지않아 메모리에서 가장 큰 재진입 공격에 대해 살펴보겠습니다. 

가장 악명 높은 실시간 재진입 해킹 중 일부 

프로젝트에 가장 치명적인 영향을 미쳤던 재진입 공격은 결국 이 둘 중 하나 또는 둘 다 수행했습니다. 

  • 스마트 계약에서 Ether를 완전히 배출합니다.
  • 스마트 계약 코드에 몰래 들어가는 해커

이제 몇 가지 재진입 공격 사례와 그 영향을 관찰할 수 있습니다. 

2016 월 XNUMX : DAO 공격 – 3.54M 또는 $150M 이더

2020 월 XNUMX 일 : Uniswap/Lendf.Me 해킹 – $25M

May 2021: BurgerSwap 해킹 – $7.2M

2021월 XNUMX일: CREAM FINANCE 해킹 – $18.8M

3 월 2022 : 올라 파이낸스 – $3.6M

2022월 XNUMX일: OMNI 프로토콜 – $1.43M

재진입 공격이 유행을 타지 않은 것은 분명합니다. 다음 구절에서 이에 대한 깊은 통찰을 얻어봅시다. 

재진입 공격 개요

재진입(Reentrancy)이라는 이름에서 따온 말인데, 이는 "계속해서 재진입"을 의미합니다. 재진입 공격에는 피해자 계약과 공격자 계약의 두 가지 계약이 포함됩니다. 

공격자 계약은 피해자 계약의 재진입 취약성을 악용합니다. 이를 달성하기 위해 인출 기능을 사용합니다. 

공격자 계약은 피해자 계약의 잔액이 업데이트되기 전에 반복 호출을 통해 피해자 계약에서 자금을 빼기 위해 인출 기능을 호출합니다. 피해자 계약은 잔액을 확인하고 자금을 보내고 잔액을 업데이트합니다. 

그러나 자금을 보내고 계약의 잔액을 업데이트하는 시간 프레임 내에 공격자 계약은 자금을 인출하도록 지속적으로 호출합니다. 결과적으로 공격자 계약이 모든 자금을 고갈할 때까지 피해자 계약에서 잔액이 업데이트되지 않습니다.

재진입 익스플로잇의 심각성과 비용은 스마트 계약 감사 그러한 오류를 간과할 가능성을 배제합니다. 

재진입 공격의 설명 보기

아래의 단순화된 그림에서 재진입 공격의 개념을 이해해 봅시다. 

다음은 취약한 계약과 해커 계약의 두 가지 계약입니다.

해커 계약은 취약한 계약에서 철회하도록 요청합니다. 전화를 받으면 취약한 계약은 해커 계약의 자금을 확인한 다음 자금을 해커에게 전송합니다. 

해커는 자금을 받고 취약한 계약에서 잔액이 업데이트되기 전에 취약한 계약을 다시 호출하는 폴백 기능을 구현합니다. 따라서 동일한 작업을 반복하여 해커는 취약한 계약에서 자금을 완전히 인출합니다. 

재진입 공격의 클러치에서 스마트 계약을 탈출하는 방법?

공격자가 사용하는 Fallback 기능의 특징 

  • 외부에서 호출할 수 있습니다. 즉, 작성된 계약 내에서 호출할 수 없습니다.
  • 명명되지 않은 함수
  • fallback 함수는 내부에 임의의 로직을 포함하지 않습니다.
  • ETH가 주변 스마트 계약으로 전송되고 receive() 함수가 선언되지 않으면 폴백이 트리거됩니다.

기술적 관점에서 재진입 공격 분석 

샘플 계약을 통해 재진입 공격이 어떻게 발생하는지 살펴보겠습니다.

악의적인 계약

contract Attack {
    DepositFunds public depositFunds;

    constructor(address _depositFundsAddress) {
        depositFunds = DepositFunds(_depositFundsAddress);
    }

    // Fallback is called when DepositFunds sends Ether to this contract.
    fallback() external payable {
        if (address(depositFunds).balance >= 1 ether) {
            depositFunds.withdraw();
        }
    }

    function attack() external payable {
        require(msg.value >= 1 ether);
        depositFunds.deposit{value: 1 ether}();
        depositFunds.withdraw();
    }


}

공격자가 2ETH를 예치하는 공격자 계약입니다. 공격자는 취약한 계약에서 철회 기능을 호출합니다. 취약한 계약에서 자금을 받으면 폴백 기능이 트리거됩니다. 

폴백은 인출 기능을 실행하고 취약한 계약에서 자금을 빼냅니다. 이 주기는 취약한 계약에서 자금이 완전히 소진될 때까지 계속됩니다.

취약한 계약

contract DepositFunds {
    mapping(address => uint) public balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw() public {
        uint bal = balances[msg.sender];
        require(bal > 0);

        (bool sent, ) = msg.sender.call{value: bal}("");
        require(sent, "Failed to send Ether");

        balances[msg.sender] = 0;
    }


}

취약한 계약에는 30ETH가 있습니다. 여기서 인출() 함수는 공격자에게 요청된 금액을 보냅니다. 잔액이 업데이트되지 않기 때문에 반복적으로 토큰이 공격자에게 전송됩니다. 

재진입 공격의 유형

  • 단일 기능 재진입 
function withdraw() external {
   uint256 amount = balances[msg.sender];
   require(msg.sender.call.value(amount)());
   balances[msg.sender] = 0;
}

msg.sender.call.value(amount)()는 잔액[msg.sender] = 0이 업데이트되기 전에 공격자 계약 폴백 함수가 withdraw()를 다시 호출한 후 자금을 이체합니다.

  • 교차 기능 재진입
function transfer(address to, uint amount) external {
   if (balances[msg.sender] >= amount) {
       balances[to] += amount;
       balances[msg.sender] -= amount;
   }
}
function withdraw() external {
   uint256 amount = balances[msg.sender];
   require(msg.sender.call.value(amount)());
   balances[msg.sender] = 0;
}

교차 기능 재진입은 식별하기가 훨씬 더 복잡합니다. 여기서 차이점은 fallback 함수는 철회를 호출하는 단일 함수 재진입과 달리 전송을 호출한다는 것입니다.

재진입 공격 방지

확인-효과-상호작용 패턴: Checks-effects-interactions 패턴은 기능을 구조화하는 데 도움이 됩니다. 

조건을 먼저 확인하는 방식으로 프로그램을 코딩해야 합니다. 검사를 통과하면 계약 상태에 대한 영향이 해결되어야 하며 그 후에 외부 함수를 호출할 수 있습니다. 

function withdraw() external {
   uint256 amount = balances[msg.sender];
   balances[msg.sender] = 0;
   require(msg.sender.call.value(amount)());
}

여기서 재작성된 코드는 checks-effects-interactions 패턴을 따릅니다. 여기에서 외부 호출을 하기 전에 잔액이 XNUMX이 됩니다. 

수식어 사용

함수에 적용된 수정자 noReentrant는 재진입 호출이 없도록 합니다. 

contract ReEntrancyGuard {
    bool internal locked;

    modifier noReentrant() {
        require(!locked, "No re-entrancy");
        locked = true;
        _;
        locked = false;
    }
}

끝에서

가장 효과적인 단계는 QuillAudits와 같은 선도적인 보안 회사로부터 스마트 계약 감사를 받는 것입니다. 여기서 감사자는 코드 구조를 면밀히 주시하고 폴백 기능이 어떻게 수행되는지 확인합니다. 연구된 패턴을 기반으로, 문제가 있는 것으로 보이는 경우 코드 재구성에 대한 권장 사항이 제공됩니다. 취약한 행동

손실이 발생하기 직전에 자금의 안전이 보장됩니다. 

자주 묻는 질문

재진입 공격이란 무엇입니까?

재진입 공격은 취약한 계약의 기능이 신뢰할 수 없는 계약을 호출할 때 발생합니다. 신뢰할 수 없는 계약은 자금이 완전히 고갈될 때까지 취약한 계약을 재귀적으로 호출하는 공격자의 계약입니다. 

재진입이란 무엇입니까?

재입력 행위는 코드 실행을 중단하고 프로세스를 처음부터 다시 시작하는 것을 의미하며, 이를 재입력이라고도 합니다.

재진입 가드 란 무엇입니까?

Reentrancy Guard는 함수가 반복적으로 호출되는 것을 방지하는 수정자를 사용합니다. reentrancy guard에 대한 예제를 찾으려면 위의 블로그를 읽으십시오.

스마트 계약에 대한 공격에는 어떤 것이 있습니까?

스마트 계약은 재진입, 타임스탬프 의존성, 산술 오버플로, DoS 공격 등과 같은 수많은 취약점에 노출되어 있습니다. 따라서 계약의 논리를 무너뜨리는 버그가 없는지 확인하려면 감사가 필수입니다.

69 조회수

타임 스탬프 :

더보기 퀼해시