Back to Blog

인덱스드 파이낸스 보안 사고 분석

Code Auditing
October 22, 2021
6 min read

0x.1 배경

2021년 10월 15일 02:38(UTC+8)에 내부 모니터링 시스템이 의심스러운 플래시론 트랜잭션을 감지했습니다:

내부 모니터링 시스템
내부 모니터링 시스템

조사 결과, Indexed Finance를 대상으로 한 가격 조작 공격임을 확인했습니다. 구체적으로, 공격자는 이 프로젝트에서 가격을 계산하는 데 사용되는 결함 있는 수식을 악용하여 공격을 감행했으며, 1,600만 달러의 수익을 올렸습니다.

소셜 미디어에서 이미 일부 논의가 이루어지고 있으며, 프로젝트 측에서도 공식 사후 분석 보고서(Indexed Attack Post-Mortem)를 공개했습니다. 그러나 기존 분석들은 이 보안 사고에 대한 완전한 이해를 제공하지 못하고 있습니다. 따라서 본 블로그에서는 프로젝트의 메커니즘, 취약점, 공격 방법 및 수익을 포함한 종합적인 분석을 제공하고자 합니다.

0x1.1 관련 컨트랙트 주소

  • MarketCapSqrtController: 0x120c6956d292b800a835cb935c9dd326bdb4e011

  • DEFI5: 0xfa6de2697d59e88ed7fc4dfe5a33dac43565ea41

  • CC10: 0x17ac188e09a7890a1844e5e65471fe8b0ccfadf3

0x1.2 공격 트랜잭션

  • 공격 TX-I: 0x44aad3b853866468161735496a5d9cc961ce5aa872924c5d78673076b1cd95aa

  • 공격 TX-II: 0xbde4521c5ac08d0033019993b0e7e1d29b1457e80e7743d318a3c27649ca4417

0x2. Indexed Finance의 메커니즘

취약점 및 공격을 더 잘 이해하기 위해 DEFI5(즉, 공격자에게 해킹된 풀)를 사용하여 Indexed Finance의 메커니즘을 설명합니다.

0x2.1 토큰 바인딩

DEFI5는 이더리움 DeFi 프로젝트 상위 5개 토큰의 거래 서비스를 제공하도록 설계되었습니다. 구체적으로, Indexed Finance는 MarketCapSqrtController를 통해 시가총액을 기반으로 토큰 순위를 업데이트합니다. 시간이 지남에 따라 상위 5개 토큰의 순위가 변할 수 있으므로, DEFI5 풀에서 사용하는 토큰 수는 다음 코드에서 볼 수 있듯이 5개보다 많을 수 있습니다:

그림 1
그림 1

그림 1은 새 토큰을 바인딩하기 위해 DEFI5가 reindexTokens 함수에 의해 호출되는 _bind 함수를 트리거해야 하며, 이 함수는 MarketCapSqrtController의 reindexPools 함수에 의해서만 호출될 수 있음을 보여줍니다:

그림 2
그림 2

그림 2는 MarketCapSqrtController가 먼저 시장에서 토큰 정보(총 공급량 및 가격 포함)를 가져온 다음 시가총액을 기반으로 순위를 계산하는 것을 보여줍니다. reindexPool 함수를 호출할 때, 상위 토큰의 주소가 인수로 전달되어 reindexTokens 함수를 호출합니다. 새로 추가된 토큰은 DEFI5의 기존 토큰을 대체하지 않고 DEFI5에 바인딩된다는 점에 유의하십시오.

0x2.2 다음은 무엇인가?

토큰 바인딩 후, DEFI5는 거래를 활성화하기 위해 토큰 상태를 나타내는 ready 변수를 true로 설정해야 합니다:

그림 3
그림 3

코드 로직에 따르면, 컨트랙트 초기화를 제외하고 readygulp 함수에서만 설정될 수 있습니다. 그림 3에서 보듯이, 이는 DEFI5의 토큰 잔액이 _minimumBalances보다 크거나 같을 때 발생합니다. 동시에, 초기 토큰 가중치(즉, denorm)는 다음 공식을 기반으로 계산됩니다:

0x3. 취약점 분석

취약한 코드는 MarketCapSqrtController의 updateMinimumBalance 함수에 속합니다.

그림 4
그림 4

그림 4에서 볼 수 있듯이, updateMinimumBalanceready가 false인 토큰의 minimumBalance를 poolValue의 1/100로 변경할 수 있습니다. poolValue의 계산이 취약점의 핵심입니다.

그림 5
그림 5

그림 5의 계산은 다음 공식을 구현합니다:

그러나 이 공식에는 두 가지 잠재적인 문제가 있습니다:

  • 하나의 토큰 유동성을 사용하여 전체 풀의 가치를 추정함;
  • 풀의 가중치(_totalWeight)와 토큰의 가중치(token.denorm)는 유동성 변화에 영향을 받지 않습니다. 실제로, 이들은 외부 시장의 시가총액에 의해 영향을 받습니다. 또한, 그 변화는 시간 주기에 의해 제한됩니다. 즉, 시간당 1%씩 증가 또는 감소합니다.

요약하면, 공격자는 플래시론을 사용하여 토큰의 유동성에 즉각적으로 큰 변화를 일으켜 poolValue를 조작할 수 있으며, 이때 풀과 토큰의 가중치는 그에 상응하여 변하지 않습니다. 이렇게 함으로써, ready가 false인 토큰의 minimumBalance를 조작하여 가격 조작 공격을 감행할 수 있습니다.

0x4. 공격 분석

공격은 다음 9단계로 구성됩니다:

1단계: SUSHI를 바인딩하기 위해 reindexPool 함수를 호출합니다. 호출 전, DEFI5 풀에는 UNI, AAVE, COMP, SNX, CRV, MKR을 포함한 6개의 토큰이 있었습니다. SUSHI의 시가총액이 상위 5위에 들어감에 따라 SUSHI가 풀에 추가됩니다.

2단계: SushiSwap을 통해 IndexPool이 지원하는 6개 토큰(UNI, AAVE, COMP, SNX, CRV, MKR) 모두를 대출합니다.

3단계: 빌린 토큰으로 swapExactAmountIn 함수를 여러 번 호출하여 UNI를 스왑합니다(COMP를 예로 들면).

참고 1: 여기서 여러 번 호출하는 이유는 MAX_IN_RATIO의 제약으로 인해 한 번에 토큰 잔액의 절반만 스왑할 수 있기 때문입니다.

참고 2: 이 단계에서 풀 내 UNI(firstToken) 잔액이 크게 감소하기 때문에 poolValue가 크게 과소평가됩니다.

4단계: updateMinimumBalance 함수를 호출하여 SUSHI의 minimumBalance를 수정합니다.

3단계에서 계산된 비정상적인 poolValue로 인해 minimumBalance가 정상 값보다 작다는 점에 유의하십시오.

5단계: 유동성을 제공하기 위해 joinswapExternAmountIn 함수를 호출하여 LP 토큰을 준비합니다. 이 LP 토큰들은 더 많은 SUSHI로 스왑하는 데 사용됩니다.

참고: MAX_IN_RATIO의 영향으로 인해 joinswapExternAmountIn 함수를 여러 번 호출해야 합니다.

6단계: 먼저 대량의 SUSHI를 대출하여 풀에 전송하고, 그 다음 gulp 함수를 호출하여 SUSHI의 readytrue로 설정함으로써 DEFI5 풀에서 SUSHI의 가중치를 조작합니다. 이렇게 함으로써 SUSHI의 초기 가중치(denorm)가 높은 값이 됩니다.

7단계: exitPool 함수를 호출하여 LP 토큰을 기초 토큰(UNI, AAVE, COMP, SNX, CRV, MKR, SUSHI)으로 스왑합니다.

exitPool 함수는 각 토큰의 가중치를 고려하지 않으므로, 결과적으로 기초 토큰은 동일한 비율로 반환됩니다.

8단계: SUSHI로 joinswapExternAmountIn 함수를 호출하여 LP 토큰을 스왑함으로써 유동성을 제공합니다. 당시 SUSHI의 비정상적인 가중치로 인해 더 많은 LP 토큰을 획득할 수 있습니다.

joinswapPoolAmountIn 함수는 수신된 기초 토큰(이 경우 SUSHI)의 가중치를 기반으로 LP 토큰을 발행한다는 점에 유의하십시오.

9단계: 8단계에서 획득한 LP 토큰으로 exitPool 함수를 호출하여 풀을 고갈시킵니다.

0x5. 수익 분석

조사 결과, 공격자가 사용한 모든 자금(트랜잭션 수수료 포함)은 Tornado Cash에서 나온 것으로 확인되었습니다.

총 두 건의 공격 트랜잭션이 있었습니다:

  • 첫 번째 트랜잭션에서 공격자는 다음을 획득했습니다: 6,226.8 AAVE, 15 ETH, 192,358.6 UNI, 5,459.5 COMP, 721,611.3 CRV, 16,680.6 SNX, 406.5 MKR.

  • 두 번째 트랜잭션에서 공격자는 다음을 획득했습니다: 109.6 MKR, 17,844 UMA, 1,002.4 COMP, 34,602.5 UNI, 131,645.4 BAT, 28,754.1 SNX, 1,273.6 AAVE, 124,194.2 CRV, 33,215.4 LINK, 5.24 YFI.

또한, 공격자는 여러 차례 실패한 시도도 있었습니다.

이 글을 작성하는 시점을 기준으로, 공격자가 얻은 수익은 1,600만 달러에 달하며, 아직 전송되지 않은 상태입니다.

BlockSec 소개

BlockSec은 2021년 세계적으로 著名한 보안 전문가 그룹이 설립한 선도적인 블록체인 보안 회사입니다. 이 회사는 대중적인 채택을 촉진하기 위해 신흥 Web3 세계의 보안과 사용성을 향상시키는 데 전념하고 있습니다. 이를 위해 BlockSec은 스마트 컨트랙트 및 EVM 체인 보안 감사 서비스, 위협을 사전에 차단하고 보안 개발을 위한 Phalcon 플랫폼, 자금 추적 및 조사를 위한 MetaSleuth 플랫폼, 그리고 Web3 빌더들이 크립토 세계를 효율적으로 탐색할 수 있는 MetaSuites 확장 프로그램을 제공합니다.

현재까지 회사는 MetaMask, Uniswap Foundation, Compound, Forta, PancakeSwap 등 300개 이상의 저명한 고객사를 대상으로 서비스를 제공했으며, Matrix Partners, Vitalbridge Capital, Fenbushi Capital을 포함한 저명한 투자자들로부터 두 차례의 투자 라운드에서 수천만 달러를 유치했습니다.

공식 웹사이트: https://blocksec.com/

공식 트위터 계정: https://twitter.com/BlockSecTeam

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