DeFi 플랫폼 Opyn 스마트 계약 취약점에 대한 자세한 설명: 공격자의 빈손
PeckShield
2020-08-06 06:32
本文约1846字,阅读全文需要约7分钟
교활한 공격자는 먼저 자신에게 위장된 거래를 시작하고 이 ETH의 재사용 가능한 기능을 사용하여 판매자의 사용자에게 다시 전송을 시작함으로써 저당 디지털 자산의 판매자를 속입니다.

2020년 8월 5일 베이징 시간, DeFi 옵션 플랫폼 Opyn의 Opyn ETH Put 스마트 계약이 해킹되어 약 370,000달러의 손실이 발생했습니다.

Opyn은 올해 2월 보험 플랫폼으로 탈바꿈한 일반 옵션 계약으로, oToken을 통해 DeFi 플랫폼에 거래 가능한 ETH 풋 옵션을 제공하여 ETH 시장 가격을 고정하고 변동성이 높은 DeFi 시장에 상대적 안정성을 제공합니다.

Opyn 플랫폼이 공격을 받았다는 사실을 알게 된 후 PeckShield 보안 팀은 신속하게 문제의 핵심 포인트를 찾았습니다.

공격자는 Opyn 스마트 컨트랙트 실행(exercise) 인터페이스가 수신된 ETH 처리에 일부 결함이 있고 해당 컨트랙트가 거래자의 실시간 거래 금액을 확인하지 않아 공격자가 실제 거래를 개시할 수 있음을 발견했습니다. 그 후 가짜 거래를 삽입하여 판매자의 저당 디지털 자산을 속인 다음 빈손을 실현하십시오.

간단히 말해서, Opyn ETH Put 스마트 계약의 운동 기능 exercise()는 거래자의 ETH에 대한 실시간 검증을 수행하지 않기 때문입니다. Opyn 플랫폼의 비즈니스 논리에 따라 풋 옵션의 구매자는 해당 ETH의 가치를 판매자에게 전송하여 판매자가 저당하는 디지털 자산을 얻습니다. 교활한 공격자는 먼저 자신에게 위장된 거래를 시작하고 이 ETH의 재사용 가능한 기능을 사용하여 판매자의 사용자에게 다시 전송을 시작함으로써 저당 디지털 자산의 판매자를 속입니다.

보조 제목

취약점 상세 프로세스 분석

먼저 Opyn 플랫폼의 비즈니스 논리에 대해 이야기하겠습니다. 사용자가 Opyn 계약을 사용하여 운동, 즉 선물을 사고 팔 때(운동) 구매자는 해당 금액의 ETH 또는 ERC20 토큰을 플랫폼으로 전송해야 합니다. 판매자, 그리고 계약은 구매자의 해당 oToken을 파괴하고 구매자는 판매자가 담보로 한 재산을 얻습니다.

이미지 설명

그림 1. 전달된 저장소 주소 목록은 exercise() 함수에서 반복됩니다.

이미지 설명

그림 2. 계약에 전달된 ETH를 재사용하여 담보 자산 획득

함수가 ERC20 토큰을 처리할 때 대부분의 DeFi 프로젝트와 마찬가지로 코드의 1882행에 표시된 대로 transferFrom()을 사용하여 msg.sender에서 address(this)로 돈을 이체합니다.

하지만 함수에 의해 처리되는 자산이 ETH인 경우에는 처리 방식이 완전히 다릅니다. Solidity에서 msg.value는 payable 인터페이스를 호출할 때 컨트랙트의 호출자가 컨트랙트에 전송한 ETH의 양을 의미하므로 컨트랙트 코드 1879행에서 msg.value == amtUnderlyingToPay를 확인합니다. 계약이 실제로 amtUnderlyingToPay 금액의 ETH를 받았는지 확인하고 msg.value 값에 영향을 주지 않습니다.

그러나 위에서 언급했듯이 _exercise() 함수는 exercise()에서 주기적으로 호출되므로 컨트랙트가 실제로는 ETH를 한 번만 받지만 루프 중에 재사용할 수 있습니다.

이미지 설명

그림 3. 공격 트랜잭션 분석

그림 3에서는 Bloxy 브라우저에 표시되는 호출 프로세스를 통한 공격 프로세스를 보여줍니다. 공격자가 많은 주문을 소비했기 때문에 공격 논리를 보여주기 위해 거래 중 하나를 예로 들겠습니다.

1. 공격자는 Uniswap에서 75oETH를 먼저 구입하여 추가 콜 기능 실행을 준비했습니다.

2. 공격자는 옵션 매도자로서 Vault 주소를 생성하고 24,750 USDC를 저당잡아 75 oETH를 발행했지만 해당 옵션을 매도하지 않았으므로 75 ETH를 동시에 330 가격에 매도할 수 있는 권리를 매수한 것입니다. ;

보조 제목

수리 제안

PeckShield 보안 팀은 Solidity에서 컨트랙트가 로컬 변수 msgValue를 사용하여 수신된 ETH(즉, msg.value의 값)를 저장할 수 있다고 제안합니다. 이와 같이 후속 단계에서 msgValue를 조작함으로써 ETH가 얼마나 사용되었는지 정확하게 표시할 수 있으므로 자산이 재사용되는 것을 방지할 수 있습니다. 또한 address(this).balance를 사용하여 msg.value가 재사용되는 위험을 피하기 위해 계약 잔액을 확인할 수도 있습니다.

PeckShield
作者文库