Back to Blog

#3: KyberSwap 사건: 극도로 정교한 계산을 통한 반올림 오류의 완벽한 악용

Code Auditing
February 10, 2024
6 min read

2023년 11월 23일, KyberSwap을 대상으로 한 일련의 공격이 발생했습니다. 이 공격들로 인해 총 4,800만 달러 이상의 손실이 발생했습니다. 근본적인 문제는 KyberSwap의 재투자 과정에서 발생한 잘못된 반올림 방향에서 비롯되었습니다. 이로 인해 부적절한 틱 계산이 이루어졌고, 궁극적으로 유동성의 이중 계산이 발생했습니다.

저희는 "또 하나의 정밀도 손실 비극: KyberSwap 사건의 심층 분석"이라는 포괄적인 보고서를 발표했으며, 이 보고서는 사건의 세부 사항을 심층적으로 다루고 있습니다. 더 깊은 이해를 위해 전체 분석을 참고하시길 권장합니다. 아래에서는 이 사건을 2023년 10대 보안 사고 중 하나로 소개하는 간략한 개요를 제공합니다.

배경

KyberSwap은 분산형 자동화 시장 조성자(CLAMM) 플랫폼입니다. 집중 유동성에 대한 시장 수요를 충족하기 위해 KyberSwap Elastic은 Uniswap V3를 기반으로 출시되었으며, 유동성 공급 수익의 자동 복리를 가능하게 하는 재투자 곡선을 포함한 여러 개선 사항이 적용되었습니다.

1. 틱과 제곱근 가격

Uniswap V3 유형의 CLAMM에서 Tick은 LP가 전체 범위 대신 고정된 범위 내에서 유동성을 제공할 수 있도록("집중"이라는 용어가 여기서 유래) 가격을 이산적인 방식으로 표시하는 데 사용됩니다.

유동성은 임의의 두 틱 사이의 범위(인접할 필요 없음), 즉 틱 인덱스 쌍(하위 틱과 상위 틱)에 배치될 수 있습니다. 구체적으로, 각 틱의 가격(정수 인덱스 i에서)은 다음과 같이 정의됩니다:

실제로는 제곱근 가격(sqrtP 또는 sqrtPrice로 표기)이 사용됩니다:

현재 제곱근 가격을 기반으로 현재 틱을 계산하는 것도 가능합니다:

명백히, 주어진 틱에 대해 하나의 제곱근 가격만 계산되지만, 여러 제곱근 가격이 동일한 틱을 가리킬 수 있습니다. 더 자세한 설명은 Uniswap V3 및 KyberSwap의 문서를 참고하십시오.

2. 재투자 곡선

Uniswap V3 기반 CLAMM은 LP 수수료의 풀 활용도 문제와 재투자에 필요한 상당한 가스 비용 문제를 겪고 있습니다. 이에 따라 KyberSwap은 이 문제를 해결하기 위해 재투자 곡선을 채택했습니다.

재투자 곡선의 핵심은 각 스왑에서 수집된 수수료가 무한한 범위 내에서 재투자 유동성으로서 풀에 추가 유동성으로 누적된다는 것입니다. 재투자 토큰은 LP에게 발행되며 누적된 재투자 유동성은 그에 따라 LP에게 할당됩니다. 또한, 재투자 유동성은 스왑 및 가격 계산 과정에도 참여합니다.

위에서 소개한 계산에 해당하는 코드는 해당 의 다음 코드 스니펫에서 computeSwapStep 함수에 나타나 있습니다.

이 함수에서 재투자 유동성으로 인해 liquidity는 두 가지 구성 요소의 합임을 주목해야 합니다: 기본 유동성을 위한 baseL과 재투자를 위한 누적 유동성인 reinvestL.

3. KyberSwap에서의 스왑

앞서 논의한 KyberSwap 풀의 swap 함수 구현은 아래 다이어그램으로 추상화할 수 있습니다:

틱 계산과 관련된 핵심 로직은 파란색 사각형으로 강조된 스와핑 while 루프 내에 있습니다. 구체적으로, 주요 로직은 computeSwapStep 함수와 _updateLiquidityAndCrossTick 함수로 구성됩니다. 전자는 주어진 스왑에 대한 입출력 금액 및 nextSqrtP와 같은 주요 상태를 계산하고, 후자는 크로스틱이 발생할 때의 경우를 처리합니다.

전통적으로 가격이 상승할 때 틱이 오른쪽/위쪽으로 이동한다고 하며, 반대의 경우 틱이 왼쪽/아래쪽으로 이동한다고 합니다.

나중에 논의될 취약점을 더 잘 이해하기 위해서는 다음 그림에 나타난 computeSwapStep 함수의 관련 코드 로직을 살펴보는 것이 필수적입니다:

구체적으로, calcReachAmount 함수는 목표 가격 targetSqrtP에 필요한 입력 토큰을 계산합니다(50-57번 줄). usedAmountspecifiedAmount보다 크면 틱이 넘어가지 않으며, nextSqrtPdeltaL(즉, 델타 유동성, 59-62번 줄)로부터 계산됩니다. deltaLestimateIncrementalLiquidity 함수를 사용하여 결정되고, 최종 가격 nextSqrtPcalcFinalPrice 함수로 계산됩니다(70-79번 줄). 필요한 입력이 더 적으면 nextSqrtP는 다음 틱의 가격으로 설정되지만, 이 경우는 공격에서 사용되지 않습니다.

위에서 설명한 단계들로 보면, 틱이 넘어가지 않는 경우 computeSwapStep이 반환하는 nextSqrtP는 다음 틱의 sqrtP보다 크지 않아야 합니다. 그러나 유동성(기본 유동성과 델타 유동성)에 대한 가격 의존성과 정밀도 손실로 인해, 공격자는 틱이 넘어가지 않는 상태에서 nextSqrtP를 더 크게 조작할 수 있습니다.

취약점 분석

근본 원인은 SwapMath 컨트랙트(computeSwapStep 함수에 의해 호출됨)의 델타 유동성 계산(즉, estimateIncrementalLiquidity 함수) 내에서 잘못된 반올림 방향으로 인한 결함 있는 틱 계산에 있습니다. 이는 차례로 이후의 틱 계산에 부적절하게 영향을 미칩니다.

흥미롭게도, 188번 줄의 주석(파란색 사각형으로 강조)을 살펴보면, deltaLnextSqrtP를 내림하기 위해 올림 처리되어야 함을 알 수 있습니다. 그러나 189번 줄에서 mulDivFloor 함수를 사용함으로써 deltaL이 잘못되게 내림 처리됩니다. 결과적으로 nextSqrtP는 부정확하게 올림 처리됩니다.

공격 분석

공격자들은 여러 공격 트랜잭션을 시작했으며, 각 트랜잭션은 여러 풀을 드레인했습니다. 간단하게 설명하기 위해 다음 논의는 공격 트랜잭션 내의 첫 번째 공격을 기반으로 합니다.

핵심 공격 로직은 다음 여섯 단계로 구성됩니다:

  1. AAVE에서 플래시 론을 통해 2,000 WETH를 차용합니다.

  2. 피해자 풀 0xfd7b에서 6.850 WETH를 6.371 frxETH로 스왑합니다. 이 단계는 현재 틱과 currentSqrtP를 현재 유동성이 없는 위치로 밀어 넣는 데 사용됩니다.

  • currentSqrtP는 공격자가 무작위로 선택한 것처럼 보이며, 스왑은 이 가격에서 정확히 멈춥니다.
  • 이 단계 이후 기본 유동성(baseL)은 0이지만 재투자 유동성(reinvestL)은 0이 아닙니다.
  1. 풀에 유동성을 추가한 다음 유동성의 일부를 제거합니다. 이 단계는 범위와 총 유동성을 원하는 양으로 제어하는 데 사용됩니다.
  • 틱 범위는 currentSqrtP를 기반으로 선택됩니다.
  • 공격에 필요한 유동성은 틱 범위에서 도출될 수 있지만, 해당 계산 로직에는 추가 탐색이 필요합니다.
  1. 풀에서 387.170 WETH를 0.06 frxETH로 스왑합니다. 이 단계는 **nextTick == currentTick**이 되도록 현재 틱을 조작하는 데 사용됩니다. 구체적으로, 4단계의 스왑은 교묘하게 풀을 속여 틱 111,310이 넘어가지 않았다고 믿게 만듭니다. 그러나 실제로 currentSqrtP는 틱 111,310의 sqrtP보다 큽니다.
  1. 풀에서 0.06 frxETH를 396.244 WETH로 스왑합니다. 스왑 방향이 이전 단계와 반대임에 유의하십시오. 이 단계에서는 스왑을 수익성 있게 만들고 결과적으로 풀을 드레인하기 위해 유동성이 이중으로 계산됩니다.
  1. 플래시 론을 상환하고 6.364 WETH와 1.117 frxETH를 수확합니다.

심층적인 검토를 위해서는 계산 및 그림을 포함한 더 많은 세부 정보가 담긴 저희의 종합 분석을 참고하십시오.

요약

이 사건의 근본적인 문제는 KyberSwap의 재투자 과정에서 발생한 잘못된 반올림에서 비롯되었으며, 이로 인해 부정확한 틱 계산과 궁극적으로 유동성의 이중 계산이 발생했습니다. 이 사건은 DeFi 프로토콜 내 정밀도 손실 문제의 복잡하고 파악하기 어려운 특성을 부각시키며, 전체 커뮤니티에 심각한 도전을 제기합니다.

2023년의 이 공격은 매우 복잡하고 섬세한 계산이 특징이며, 커뮤니티를 크게 시험한 많은 정밀도 관련 보안 사고의 대표적인 사례로 꼽힙니다. 또한, 당국과의 광범위한 협상 끝에 공격자는 도발적인 어조의 메시지를 공개하여 프로토콜에 대한 완전한 통제권을 요구했습니다.

이 시리즈의 다른 글 읽기:

Sign up for the latest updates
~$410만 손실: Taiko, SecondFi 익스플로잇 | BlockSec 위클리
Security Insights

~$410만 손실: Taiko, SecondFi 익스플로잇 | BlockSec 위클리

이 주간 블록체인 보안 리포트는 2026년 6월 22~28일 발생한 주요 사건 2건을 다루며, 이더리움과 카르다노에서 약 410만 달러의 피해가 확인됐습니다. Taiko 브릿지 공격은 노출된 SGX 서명 키와 디버그 엔클레이브를 거부하지 못한 증명 정책 결함을 이용해 악성 증명자를 등록하고 L2 상태 증명을 위조했습니다. SecondFi 지갑은 Ed25519 논스 도출 시 비밀 입력이 제거되는 결함으로 공개 트랜잭션 데이터만으로 개인 키 복구가 가능했습니다.

~$18M 손실: jaredFromSubway, Aztec 등 | BlockSec 위클리
Security Insights

~$18M 손실: jaredFromSubway, Aztec 등 | BlockSec 위클리

이 주간 블록체인 보안 보고서는 2026년 6월 15일~21일을 다루며, 이더리움과 BNB 체인에서 3건의 주요 사고가 발생해 약 $18.3M의 손실이 발생했습니다. jaredFromSubway 사건은 MEV 봇이 차익거래를 위해 신뢰할 수 없는 제3자 컨트랙트에 자산을 승인한 역방향 승인 공격으로, 가짜 래퍼 토큰과 스왑 풀을 이용해 약 $15M 손실이 발생했습니다. Aztec은 이스케이프 해치 ZK 회로의 제약 누락으로 공격자가 가짜 머클 트리로 온체인 검증을 통과했습니다.

Web3 컴패니언: 오픈소스 보안 에이전틱 지갑

Web3 컴패니언: 오픈소스 보안 에이전틱 지갑

BlockSec가 Web3 Companion을 오픈소스로 공개했습니다. 이 보안 중심의 에이전트 지갑은 자체 AI 에이전트를 신뢰하지 않는 방식으로 설계되었으며, 키 격리, 강력한 정책, Passkey를 활용해 온체인 자산을 보호합니다.

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit