KyberSwap 해킹에 대한 빠른 분석

이 기사는 기계로 번역되었습니다
원문 표시

감사 회사 Certik 의 분석에 따르면, 해커들은 KyberSwap의 일부 유동성 풀에 있는 아주 작은 허점까지도 이용하여 크로스 스왑을 악용하여 유동성 풀에서 막대한 자금을 빼내는 데 성공했습니다.

11월 22일 KyberNetwork는 여러 체인에 대한 플래시론 공격을 받아 약 4,700만 달러의 손실을 입었습니다. Certik에 따르면 이 기술을 사용하면 중앙 집중식 유동성 생성기가 어떻게 작동하는지 이해하는 것이 중요합니다.

자동화된 유동성 공급자는 기본적으로 모든 거래가 이루어지는 곳에 표준 상수 제품 곡선(x*y=k)을 배포합니다.

Certik은 가격 곡선이 더 엄격하게 제한된 풀을 만들면 유동성을 더 잘 활용할 수 있다는 사실을 발견했습니다. 좁은 가격 범위 내에서 많은 유동성을 지원하면 가격 하락 위험이 효과적으로 완화됩니다. 동일한 가격에 영향을 미치려면 거래 규모가 유동성 풀에 비례하여 증가해야 하기 때문입니다.

Uniswap v3에 의해 대중화된 중앙 집중식 유동성 공급자 모델을 통해 유동성 공급자(LP)는 선호하는 가격대에 유동성을 추가할 수 있습니다.

Certik은 이 설계의 결과로 풀의 유동성이 비교할 수 없게 되기 때문에 각 유동성 공급 포지션(LP)을 개별적으로 추적해야 한다는 점을 지적합니다. 가격 범위는 별개의 "틱"으로 나눌 수 있으므로 LP는 두 "틱" 사이에 유동성을 제공할 수 있습니다. i로 표시되는 틱 지수는 해당 가격의 로그 로 정의됩니다.

유동성 공급자의 순 유동성 및 기타 매개변수는 연결된 목록 데이터 구조에 저장됩니다.

실제로 이러한 각 포지션은 사용자 정의 가격 곡선을 생성합니다. 모든 다양한 포지션을 단일 가격 곡선으로 집계함으로써 단일 풀이 다양한 유동성 공급자(LP) 선호도를 지원할 수 있습니다.

틱 범위에 유동성을 추가하거나 제거할 때 유동성 풀은 이러한 틱이 교차할 때 추가되거나 해제된 가상 유동성의 양과 거래를 트리거하는 데 사용된 토큰 수를 기록해야 합니다. 토큰 0을 토큰 1로 바꾸면 현재 풀 가격과 현재 "틱"이 낮아지고, 토큰 1을 토큰 0으로 바꾸면 현재 풀 가격과 현재 "틱"이 올라갑니다. 스왑을 수행할 때 “틱”이 이 마진을 교차하여 좌우로 이동함에 따라 총 유동성량이 추가되거나 제거되는데, 이것이 공격이 발생하는 KyberSwap의 취약점입니다.

취약점

간단히 말해서, 이 취약점은 KyberSwap Elastic의 ComputeSwapStep() 구현에 존재합니다. 이 함수는 빼거나 더해야 할 트랜잭션의 실제 입력 및 출력 금액, 징수할 스왑 수수료 및 결과 제곱근 값을 sqrtP 함수로 계산하는 역할을 담당합니다.

이 함수는 처음에는 calcReachAmount() 함수라고 불리며, 해커의 거래가 틱 마진을 초과하지 않을 것이라고 가정했으나, “calcFinalPrice” 함수를 호출하여 계산한 targetSqrtP 보다 큰 가상 가격을 생성하여 실수가 발생했습니다. 결과적으로 유동성이 제거되지 않고 다음 공격으로 이어진다.

공격 흐름

이 예는 txhash가 0x396a83df7361519416a6dc960d394e689dd0f158095cbc6a6c387640716f5475 인 Ethereum 트랜잭션을 기반으로 합니다.

이 트랜잭션은 모두 동일한 방법을 사용하는 6가지 공격을 나타냅니다. 그래서 Certik은 USDC-ETHX 쌍에 대한 공격을 예로 들었습니다.

1. 먼저, 해커는 Uniswap에서 500 ETHx를 플래시론하고, 과도한 양의 ETHx를 교환하여 2.8 ETHx만 있던 KS2-RT 풀((KyberSwap v2 Reinvestment Token)을 조작했습니다. 해커는 246,754 ETHx를 32389.63 USDC로 교환하여 유출되었습니다. 유동성을 풀고 currentTick을 305,000으로 늘립니다.

스왑 후 풀에는 249.5 ETHX와 13.2 USDC가 남습니다.

해커는 처음에 500 ETHX를 USDC로 교환하려고 했지만 246,754 ETHx로 32,389.63 USDC를 얻고 currentTick을 305,000으로 늘리기에 충분했습니다. 당시 해커가 교환할 수 있는 305,000틱 마진 이상으로 사용할 수 있는 유동성이 없었음을 의미하며 이는 진공 상태로 간주되었습니다.

2. 그런 다음 해커는 KyberSwap: Elastic Anti-Snippingposition Manager 계약에서 mint() 함수를 호출하여 16 USDC 및 5.87e-3 ETHX로 새로운 유동성 풀을 생성합니다. "틱"은 305,000에서 305,408 사이의 좁은 범위에 배치되었습니다. 이는 해커가 "틱"을 305,000에서 추적하기 위해 자신의 유동성 풀을 만들었다는 의미입니다.

그런 다음 해커는 유동성의 일부를 제거했지만 305,000에서 305,408까지의 틱 범위에 일부 유동성을 남겨 두었습니다.

3. 해커는 ETHX에서 USDC로 두 번째 스왑을 수행합니다. 그들은 305,000의 진드기 마진으로 244.08 ETHX를 교환하여 13.6 USDC를 받고 진드기 마진을 305,408로 늘렸습니다.

표면적으로는 해커가 305,000에서 305,408 사이의 유동성을 제공하는 유일한 사람이었기 때문에 이는 이상한 스왑처럼 보이지만 이것이 다음 단계의 전제입니다.

4. KyberSwap은 거래가 틱 간격을 초과하는지 확인하기 위해 계산 SwapStep() 함수를 사용합니다. 함수의 일부는 다음과 같습니다.

여기서는 calcReachAmount() 함수에 중점을 둡니다. 이 함수는 currentSqrtP (현재 제곱근 가격)가 targetSqrtP 에 도달하는 경우 거래에 필요한 토큰 수를 계산합니다.

Cerik은 이 거래에서 UsedAmount 의 값은 244080034447360000000이고, 해커가 교환을 위해 입력한 ETHx의 양은 244080034447359999999로, UsedAmount 값보다 하나 적다고 밝혔습니다. ComputeSwapStep() 함수는 이 거래가 현재 틱 범위의 유동성을 소진하기에 충분하지 않으며 다른 틱 범위로 변경할 필요가 없다고 판단합니다. nextSqrtP 가 targetSqrtP 로 업데이트되지 않음을 의미합니다.

그런 다음 calcFinalPrice 함수가 호출되어 다음 nextSqrtP 값을 계산합니다. 여기서 중요한 부분은 계산 중에 스왑 수수료가 유동성에 포함된다는 것입니다. nextSqrtP 의 최종 가격은 실제로 초기 예상보다 높으며, 특히 "틱" 범위인 305,408의 가격보다 높습니다.

위의 교환 함수로 돌아가서 Certik은 sqrtPnextSqrtP 의 값을 비교하여 틱 진폭을 교환해야 하는지 결정한다고 말합니다. 여기의 조건은 sqrtP가 nextSqrtP 와 '동일'한지 여부만 결정하고, 일치하는 경우에만 하위 함수 updateLiquidityAndCrossTick()이 호출되어 유동성( swapData.baseL )을 추가하거나 빼고 마진 "틱"을 전달합니다.

이 시점에서 sqrtP 는 이제 nextSqrtP 보다 큽니다. 이는 해커가 현재 가격이 틱 범위 상한선을 넘은 상황을 만들었으나, 유동성을 감소시키는 updateLiquidityAndCrossTick() 함수를 실행하지 않아 가짜 유동성이 존재하게 된 것을 의미한다.

5. 마지막으로 해커는 역거래를 수행하여 USDC를 ETHx로 교환하여 "틱" 범위인 305,408보다 약간 높은 가격을 인하했습니다. 이는 해커가 제공한 유동성 범위의 상한(305,000에서 305,408까지)을 틱 범위보다 약간 아래로 낮췄습니다. 가격은 "틱" 범위인 304,982입니다.

가격이 해커가 유동성을 제공한 305,000 – 305,408의 "틱" 범위에 진입했을 때 305,408보다 약간 높은 수준 에서 updateLiquidityAndCrossTick() 함수가 호출되었습니다. 305,000~305,408 '틱' 범위 내의 유동성에 가짜 유동성을 더해 실제 유동성 대비 '틱' 범위 값 사이의 유동성을 높인다. 그런 다음 해커는 이 가격대 내에서 493,638 ETHx를 27,517 USDC로 전환했습니다(305,000 – 305,408틱 범위에 포함되지 않은 약 250 ETHx 포함). 그 결과, 이전 비용은 복구되었고 동시에 유동성 풀은 모든 USDC를 잃었다고 Certik은 결론지었습니다.

6. 대출금을 빠르게 반납하고 공격을 완료하세요.

이 프로세스는 여러 블록체인에 걸쳐 KyberSwap 프로토콜의 여러 거래 쌍에 대해 반복되었으며 결과적으로 다음과 같은 손실이 발생했습니다.

폴리: 1,180,097 USD; ETH: 7,486,868 USD; 영업이익: 15,504,542 USD; 기본: 318,413 USD; ARB: 16,833,861USD; AVAX: 23,526달러.

Certik이 확인한 공격은 세 가지 다른 이더리움 주소(EOA)에서 발생했으며 주소 0x502가 대부분의 자산을 차지합니다. 처음에는 주소 0x502에서 프로젝트에 연락하여 일정 기간 휴식 후 협상하겠다고 알렸습니다. KyberSwap 팀은 11월 25일 오전 6시(UTC)까지 10% 보상을 제안하기 위해 연락했습니다.

출처
면책조항: 상기 내용은 작자의 개인적인 의견입니다. 따라서 이는 Followin의 입장과 무관하며 Followin과 관련된 어떠한 투자 제안도 구성하지 않습니다.
라이크
1
즐겨찾기에 추가
코멘트