재진입 공격 취약점에 대한 심층적 이해
머리말
머리말
스마트 계약(영어: Smart contract)의 개념은 1995년 Nick Szabo가 처음 제안한 것으로 정보화된 방식으로 계약을 전파, 확인 또는 실행하도록 설계된 컴퓨터 프로토콜입니다. 그러나 스마트 계약은 안전하지 않습니다.Re-Entrance 공격 취약점은 이더리움의 공격 방법 중 하나입니다.이미 2016년 DAO 사건으로 이더리움의 하드 포크가 발생했습니다.
첫 번째 레벨 제목
취약점 개요
이더리움에서 스마트 계약은 다른 외부 계약의 코드를 호출할 수 있습니다.스마트 계약은 외부 계약을 호출하거나 Ether를 보낼 수 있기 때문에 이러한 작업에는 외부 호출을 제출하는 계약이 필요하므로 공격자가 이러한 외부 호출을 사용하여 공격을 일으킬 수 있습니다. 하이재킹은 공격을 허용합니다. 계약은 원래 코드의 제한을 우회하여 임의의 위치에서 재실행되므로 재진입 공격이 발생합니다. 재진입 공격은 본질적으로 프로그래밍의 재귀 호출과 유사하므로 계약이 알 수 없는 주소로 에테르를 보낼 때 발생할 수 있습니다.
간단히 말해서 재진입 공격 취약점이 발생하는 두 가지 조건이 있습니다.
외부 계약이 호출되고 계약이 안전하지 않습니다.

간단한 코드 스니펫 예제는 다음과 같습니다.
위의 코드 스니펫은 가장 간단한 인출 작업이며, 다음으로 재진입 공격의 원인을 자세히 분석합니다.
첫 번째 레벨 제목
취약점 분석
재진입 공격을 공식적으로 분석하기 전에 몇 가지 핵심 지식을 소개하겠습니다.
.transfer(),01 이체방법전송 작업 중에 재진입 공격이 전송되므로 Solidity에서 일반적으로 사용되는 전송 방법은 다음과 같습니다.- .send() 및
- .gas().call.vale()(), 세 가지 전송 방법이 아래에 설명되어 있습니다.
- .transfer(): 호출에 대해 2300 가스만 전송되며 전송이 실패하면 throw를 사용하여 롤백 작업을 수행하여 재진입 공격을 방지합니다.
.send(): 호출을 위해 2300 가스만 전송되며, 전송 실패 시 부울 값 false가 반환되어 재진입 공격을 방지합니다.
계약을 호출할 때 일치하는 함수가 없습니다.
폴백 기능: 폴백 기능은 각 계약에 이름이 없는 단 하나의 기능이며, 이 기능에는 아래와 같이 매개 변수와 반환 값이 없습니다.

폴백 기능은 다음과 같은 상황에서 실행됩니다.
계약을 호출할 때 일치하는 함수가 없습니다.
데이터가 전송되지 않습니다.
스마트 계약은 이더를 수신합니다(이더를 수락하려면 폴백 기능이 지불 가능으로 표시되어야 함).
데이터가 전송되지 않습니다.
스마트 계약은 이더를 수신합니다(이더를 수락하려면 폴백 기능이 지불 가능으로 표시되어야 함).

03 취약점 코드

다음 코드는 재진입 공격이 있습니다.공용 지갑과 유사한 계약을 구현합니다.모든 사용자는 deposit()을 사용하여 Reentrance 계약에 입금하거나,withdrawal()을 사용하여 Reentrance 계약에서 인출할 수 있습니다.물론 누구나 할 수 있습니다. balanceof()를 사용하여 계약에서 자신 또는 다른 사람의 잔액을 쿼리합니다.

먼저 계정(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4)을 사용하여 피해자 역할을 하고 Deploy 버튼을 클릭하여 Remix IDE에서 컨트랙트를 배포합니다.

컨트랙트를 성공적으로 배포한 후 VALUE 설정란에 5를 입력하고 단위를 이더로 변경한 후 입금을 클릭하면 5이더가 입금됩니다.


지갑을 클릭하여 계약 잔액을 확인하고 잔액이 5ether임을 확인하여 입금이 완료되었음을 나타냅니다.

다음 코드는 위의 취약한 계약에 대한 공격입니다.

다른 계정(0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2)을 사용하여 공격자 역할을 하고 취약한 계약 주소를 Deploy 설정 상자에 복사한 다음 Deploy를 클릭하여 위의 공격 계약을 배포합니다.


배포에 성공한 후 먼저 wallet() 함수를 호출하여 공격 계약의 잔액이 0인지 확인합니다.

해당 컨트랙트의 지갑 기능을 다시 호출하여 취약한 컨트랙트의 잔액을 확인하고 6이더가 되었음을 확인합니다.

공격자(0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2)는 공격하는 컨트랙트의 공격함수를 호출하여 공격을 모사한 후, 공격받은 컨트랙트의 지갑함수를 호출하여 컨트랙트의 잔고를 확인하고 0으로 돌아간 것을 확인합니다. 공격 컨트랙트로 돌아가서 잔액을 확인하고, 공격받은 컨트랙트에서 6이더가 공격자의 컨트랙트로 모든 자금이 인출되어 재진입 공격이 발생함을 확인합니다.
04 소스코드 분석

첫 번째 레벨 제목
관련 사례
텍스트

2016년 6월 17일 TheDAO 프로젝트는 재진입 공격을 받아 3백만 개 이상의 이더리움이 TheDAO 자산 풀에서 분리되었으며 공격자는 TheDAO 스마트 계약의 splitDAO() 기능을 사용하여 자신의 DAO 자산을 재사용했습니다. 진입 공격, TheDAO 프로젝트의 자산 풀에서 DAO 자산을 지속적으로 분리하고 자신의 계정으로 이체합니다.

다음 코드는 부모 DAO에서 자식 DAO로 토큰을 전송하는 TokenCreation.sol에 소스 코드가 있는 splitDAO() 함수의 일부입니다. 잔액 배열 uintfundToBeMoved = (balances[msg.sender] * p.splitData[0].splitBalance) / p.splitData[0].totalSupply는 이동할 토큰의 양을 결정합니다.

PaidOut[_account] += reward 업데이트된 상태 변수는 문제 코드에서 payOut 함수 호출 후에 배치됩니다.

_recipient에게 .call.value 호출을 발행하고 _amount Wei를 전송하면 .call.value 호출은 기본적으로 현재 남아 있는 모든 가스를 사용합니다.
해결책
위의 재진입 공격 분석을 통해 우리는 재귀 호출이 순환 전송 작업을 수행하도록 하기 위해 자신을 콜백하는 폴백과 같은 기능을 사용하는 것이 재진입 공격 취약점의 핵심임을 알 수 있으므로 다음과 같은 해결 방법이 있습니다. 재진입 공격 취약점.
보조 제목

01 다른 전송 기능 사용
이더리움 전송을 외부 주소로 보낼 때 Solidity의 내장 transfer() 함수를 사용하십시오. transfer()는 다른 계약을 호출하기에 충분하지 않은 2300 가스만 호출에 보내기 때문에 transfer()를 사용하여 원본을 다시 작성하십시오. ) 계약 내용은 다음과 같습니다.

02 상태변수를 먼저 수정
이 방법은 상태 변수의 수정이 전송 작업, 즉 Solidity에서 공식적으로 권장하는 checks-effects-interactions 모드(checks-effects-interactions)보다 먼저 이루어지도록 하기 위한 것입니다.

03 뮤텍스 사용
공식 OpenZeppelin 라이브러리에는 특히 재진입 공격에 대한 보안 계약이 있습니다.
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol




참조
첫 번째 레벨 제목
https://zhuanlan.zhihu.com/p/111446792
참조
https://blog.csdn.net/henrynote/article/details/82119116
1. Ethereum의 여러 하드 포크:
https://blog.csdn.net/Flyhps/article/details/83095036

