Patch Thursday — ibToken의 교환비 조작으로 인한 보안 위험성

ibToken(Interest-bearing token)이란 기초 자산을 예치했을 때 예치한 기초 자산과 미래에 발생하는 이자를 추적하기 위해 발행되는 토큰을 의미합니다. DeFi에서 ibToken의 역할과 보안 취약점, 그리고 안전한 구현을 위한 해결 방안을 살펴보세요.
ChainLight's avatar
Jun 29, 2023
Patch Thursday — ibToken의 교환비 조작으로 인한 보안 위험성

Summary

본 글은 ibToken의 개념과 원리를 소개하고, 다양한 시나리오 및 Hundred Finance 해킹 사례를 통해 ibToken의 교환비 조작의 보안 위험성을 조명합니다.

ibToken(Interest-bearing token)이란?

ibToken(Interest-bearing token)이란 기초 자산을 예치했을 때 예치한 기초 자산과 미래에 발생하는 이자를 추적하기 위해 발행되는 토큰을 의미합니다. 예치한 자산으로 유동성을 제공했을 때 예치한 자산과 앞으로 발생할 이자를 추적하기 위해 발행되는 토큰입니다. 예를 들어, Uniswap V2 USDC/USDT 페어(pair)에 유동성을 공급하면 발행되는 LP(Liquidity Provider) 토큰 또한 ibToken이라고 할 수 있습니다.

ibToken은 DeFi(Decentralized Finance)에서 흔히 볼 수 있는 형태의 토큰이며, 스테이킹 서비스, DEX(Decentralized Exchange) 유동성 풀(Pool) 등 사용자의 자산을 기반으로 이자가 발생하는 서비스에서 사용됩니다.

사용자가 예치한 자산에 더불어 이자가 계속 축적되기 때문에, 예치 초기에는 ibToken과 기초 자산의 교환비는 1:1이지만, ibToken의 가치가 기초 자산보다 점진적으로 상승하게 됩니다.

  • ibToken의 가치가 하락하는 예외적인 상황도 존재합니다. 해킹으로 인해 ibToken 컨트랙트가 가지고 있는 기초 자산이 탈취되거나, 대출 프로토콜에서 ibToken의 기초 자산을 대출 자산으로 운용할 경우 프로토콜이 감당할 수 없을 정도로 악성 부채(Bad Debt)가 발생하게 되면 ibToken의 가치가 하락할 가능성이 있습니다.

ibToken에 대한 더 자세한 정보를 알고 싶으시다면, Alpaca Finance의 문서를 참고해주세요.

교환비란?

교환비의 역할은 사용자가 예치하는 자산의 가치에 해당하는 ibToken을 발행하는 데에 쓰이며, 동시에 기존 예치자들의 ibToken 가치가 훼손되지 않음을 보장하는 역할을 합니다. ibToken의 교환비와 발행될 ibToken 개수는 하기의 수식으로 정해집니다.

  • ibToken 교환비 = 발행된 ibToken / (예치된 기초 자산 + 발생한 이자)

  • 발행될 ibToken 개수 = 예치할 기초 자산 개수 * 교환비

기초 자산에서 ibToken으로 교환하는 데에 관여하는 교환비는, 발행된 ibToken / (예치된 기초 자산 + 발생한 이자) 입니다. 이 교환비에서 분모에 해당하는 예치된 기초 자산 + 발행된 이자의 값은 두 가지 방법으로 적용할 수 있습니다.

  1. 예치된 기초 자산에 대한 입출금이 발생하거나, 이자가 발생할 때마다 컨트랙트에 저장된 상태 변수(스토리지에 저장)에 업데이트하고 이를 통해 기초 자산의 잔액을 추적하여 적용합니다.

  2. 컨트랙트가 보유하고 있는 기초 자산의 잔액을 실시간 조회(token.balanceOf())하여 적용합니다.

매번 상태 변수를 업데이트할 경우 가스 비용의 문제 혹은 구현에 따라 어려움이 있을 수 있어, 컨트랙트가 보유하고 있는 기초 자산의 잔액을 조회하여 사용하는 것이 일반적입니다.

  • 컨트랙트에 저장된 변수를 통해 추적하는 방식은 sync()와 같은 이름의 함수로 컨트랙트가 보유하고 있는 기초 자산을 즉시 변수에 업데이트하는 기능을 지원하는 경우도 있습니다. 기초 자산의 실시간 잔액을 조회하여 사용하거나 기초 자산을 즉시 변수에 업데이트하는 기능을 지원하는 경우, 교환비 공식에 따라 공격자가 토큰을 컨트랙트로 전송하여 기초 자산의 잔액을 순간적으로 크게 증가시켜 ibToken의 가치를 임의로 상승, 교환비 하락을 조장할 수 있습니다.

ibToken 발행 원리

상기의 교환비를 통해 ibToken 발행량이 계산되고, 발행량 계산식은 사용자가 예치할 기초 자산 개수 * 교환비입니다. 이 식을 통해 기존에 발행된 ibToken의 가치가 훼손되지 않고, 사용자가 예치한 기초 자산의 가치에 해당하는 ibToken을 발행할 수 있습니다.

ibToken 교환비 조작 시나리오

ibToken의 교환비를 임의로 조작하면 다음과 같은 문제가 발생할 수 있습니다.

  • 가치가 낮은 ibToken 발행: ibToken의 교환비가 조작되면 사용자가 예치한 자산보다 낮은 가치의 ibToken이 발행될 수 있습니다. 이에 따라 사용자가 기초 자산을 회수하려고 할 때 손실이 발생할 수 있습니다.

  • 서비스 거부(DoS) 공격: ibToken의 교환비가 조작되면 잠재적으로 ibToken을 발행할 수 없는 서비스 거부 공격이 발생할 수 있습니다. 이는 유저로 하여금 프로토콜과 상호 작용하지 못하게 할 수 있습니다.

  • 온체인 오라클에 부정적인 영향: 조작된 ibToken의 교환비가 오라클에 사용되는 경우, 그 결과는 더욱 심각할 수 있습니다. 조작된 교환비가 오라클을 통해 프로토콜 전체에 부정확한 정보를 전파하면, 정확한 가격 데이터에 의존하는 다양한 DApp(Decentralized Application)과 스마트 컨트랙트에 영향을 미칠 수 있습니다.

ibToken의 교환비 조작 시나리오를 다음 세 가지 예시를 통해 살펴봅니다.

ChainLight는 지난 3월 21일, 교환비 조작으로 인해 거버넌스 토큰 발행에 대한 DoS 공격이 가능할 수 있었던 문제를 제보했습니다. 자세한 내용은 여기에서 확인하실 수 있습니다.


  • 시나리오 1: 발행된 ibToken이 존재하지 않을 때의 교환비 조작 시나리오

  1. 공격자는 기초 자산을 1 wei를 예치하고, ibToken 1 wei를 발행합니다.

  2. 공격자는 기초 자산을 ibToken 발행 컨트랙트에 기초 자산을 100 ETH 전송합니다. 이때, 교환비는 1에서 1 / (1 + 100 ETH)가 됩니다.

  3. 피해자는 ibToken을 발행하기 위해 기초 자산 10 ETH를 예치합니다. 발행 공식에 의해 ibToken 개수는 10 ETH * 1 wei / (1 wei + 100 ETH)로 계산할 수 있습니다. Round-down이 발생하여 기초 자산 10 ETH를 예치했지만, 발행되는 ibToken은 0입니다.

  4. 공격자는 ibToken을 소각하고, 기초 자산을 수령합니다. 수령하는 기초 자산 수량은 110 ETH + 1 wei입니다. 공격자는 피해자의 기초 자산 10 ETH를 탈취했습니다.


  • 시나리오 2: 발행된 ibToken이 존재할 때의 교환비 조작 시나리오

  1. (발생한 이자가 없다고 가정)발행된 ibToken이 10 ETH일 때, 공격자는 보유하고 있는 기초 자산 110 ETH 중 10 ETH 예치하고 ibToken을 10 ETH 발행합니다.

  2. 공격자는 기초 자산 100 ETH를 ibToken 발행 컨트랙트에 전송합니다.
    이때, 교환비는 1에서 20 ETH / (20 ETH + 100 ETH)가 됩니다.

  3. 피해자는 ibToken을 발행하기 위해 10 ETH를 예치합니다. 위 시나리오와 동일하게 Round-down이 발생하여, 기초 자산을 예치했지만 발행되는 ibToken은 0입니다.

  4. 공격자는 ibToken을 소각하고, 기초 자산을 수령합니다. 수령하는 기초 자산은 65 ETH 입니다.

  5. 공격자는 피해자의 기초 자산 5 ETH를 탈취했지만, 공격 비용에 사용한 기초 자산 100 ETH 중 50 ETH를 잃습니다.

공격자가 ibToken에 지분을 100%가 아닌 50% 가지고 있는 상황에서, 기초 자산을 ibToken 발행 컨트랙트로 전송했기 때문에 공격자는 공격 비용 100 ETH의 50%를 잃게 됩니다.

발행되는 ibToken의 수량이 0일 경우, revert를 하도록 구현한 컨트랙트도 존재합니다. 유동성이 비어있을 때 위 공격을 통해 공격자가 피해자의 자금을 온전히 탈취할 수 없지만, ibToken을 발행하지 못하는 DoS가 발생할 수 있고, MEV(Maximal Extractable Value)를 통해 피해자의 자금 일부를 탈취할 수 있습니다.

  • 시나리오 3: 발행될 ibToken이 0일 때 revert를 발생시킬 경우, MEV를 통해 피해자의 자금을 탈취하는 시나리오

  1. 피해자는 발행된 ibToken이 없을 때 기초 자산 10 ETH를 예치하는 트랜잭션을 전송합니다.

  2. 공격자는 피해자의 트랜잭션을 확인하고 피해자의 트랜잭션 보다 먼저 기초 자산 1 wei를 예치(ibToken 1 wei 발행)합니다. 그리고 기초 자산을 5 ETH를 전송하는 트랜잭션을 실행합니다. 이때, 교환비는 1 wei / (5 ETH + 1 wei)입니다.

  3. 이후, 피해자 트랜잭션이 실행되면 발행되는 ibToken 개수는 10 ETH * 1 wei / (5 ETH + 1 wei)로 산정되는데, Round-down이 발생하여 1 wei가 발행됩니다.

  4. 공격자는 ibToken 발행량의 50%를 가지고 있기 때문에 수령하는 기초 자산은 (15 ETH + 1 wei) / 2입니다.

  5. 공격자는 피해자가 예치한 기초 자산의 25%를 탈취합니다.

이 시나리오는 발행되는 ibToken이 0일 때 revert를 발생시킨다고 해도 교환비 조작 공격으로 인한 사용자 자금의 탈취를 막을 수 없다는 것을 보여줍니다.

교환비 조작으로 인한 해킹 사례

2023년 4월 25일에 발생한 Hundred Finance 해킹 사건은, 공격자가 교환비 조작으로 ibToken의 가치가 부풀려져 담보의 가치를 높게 평가받아, 실제 가치보다 더 높은 가치의 자산을 탈취한 사건입니다. 이 해킹으로 총 $7M의 자산이 공격자에 의해 탈취되었습니다.

Hundred Finance는 Compound V2를 fork 하여 Optimism에 배포한 대출 프로토콜입니다. 사용자는 wBTC를 예치하면 hwBTC라는 ibToken을 발행할 수 있습니다. Hundred Finance는 hwBTC를 담보로 사용하여 다른 자산을 빌릴수 있습니다.

해킹 원인과 분석

공격자는 hwBTC 풀에 유동성이 비어있어 교환비를 마음대로 조작할 수 있었고, ibToken을 기초 자산으로 교환할 때 Round-down이 발생하는 것을 악용해 공격 자금을 모두 탈취할 수 있었습니다.

  1. 공격자는 발행된 hwBTC가 없을 때 2 wei에 해당하는 hwBTC를 발행합니다.

  2. 공격자는 hwBTC pool에 플래시론(Flash loan)으로 빌린 wBTC를 전송, 교환비를 조작하여 ibToken의 가치를 크게 상승시킵니다.

  3. 가치가 부풀려진 ibToken 1 wei를 담보로 다른 기초 자산을 빌립니다.

  4. 공격자는 redeemUnderlying 함수를 호출할 때, hwBTC pool에 존재하는 기초 자산 — 1 값을 넣어 돌려받을 기초 자산을 호출합니다. Round-down이 발생하여, 1.9xxx… wei가 소각되지 않고 hwBTC(hwBTC pool에 존재하는 기초 자산 — 1 * 교환비)는 1 wei만 소각됩니다. 이를 악용하여 교환비 조작에 사용된 wBTC를 돌려받습니다.

  • Compound Finance의 cToken은 유동성을 제거할 때, 제거할 ibToken에 개수를 입력하는 redeem 함수와 돌려받을 유동성에 개수를 입력하는 redeemUnderlying 함수가 존재합니다.

5. 이때 hwBTC와 wBTC의 교환비는 다시 1:1이 됩니다.

6. 이후 공격자가 빌린 금액에 비해 담보의 가치가 급격히 떨어지게 되고, 악성 부채(Bad Debt)가 생기게 됩니다. 공격자는 이 포지션을 청산하고 계속 공격을 반복하여 $7M를 탈취합니다.

이 사례는 교환비 조작의 위험성과 이미 상용화된 프로토콜을 포크할 때 모든 코드를 이해하고 사용해야 한다는 것을 보여주는 사례입니다.

해결 방안

교환비 조작 문제를 해결할 수 있는 세 가지의 실제 해결 방안 예시입니다.

  1. Compound V2 — Compound V2는 코드상에 유동성이 비어있을 때 공격 가능성이 존재하지만, 현재까지 교환비 조작 문제가 발생하지 않았습니다. 처음 배포할 때 소량의 유동성을 공급하여 이 문제를 사전에 방지한 것으로 보입니다. Compound V2를 fork 한 프로젝트들은 이런 위험 가능성을 인지하고 배포할 때 소량의 유동성을 공급하거나 교환비가 조작되지 않도록 코드를 수정하여 이를 방지해야 합니다.

  2. UniswapV2 — 처음 유동성을 공급할 때, 데드 어드레스(Dead address)로 최소 유동성을 공급하여 최소한의 유동성과 ibToken(LP token) 발행량을 유지합니다. 이는 공격자의 공격 비용을 늘려 이익 실현 가능성을 크게 낮춰, 결론적으로 공격자의 공격 동기를 낮출 수 있습니다.

  3. OpenZeppelin ERC-4626 — ibToken 교환비 조작으로 인한 문제의 위험성과 해결 방안이 OpenZeppelin의 공식 문서에 명시되어 있습니다. OpenZeppelin은 YieldBox의 해결 방안*을 채택했고, ‘OpenZeppelin Contracts v4.9’에서 ERC-4626에 해결 방안이 구현되었습니다. (구현되기 이전에도 해당 해결 방안이 권고 사항으로 공식 문서에 명시되어 있었습니다.)

*Virtual Offset이라는 개념을 정의하여, ibToken Decimal(소수점 설정)에 Virtual Offset을 더해 교환비를 계산하는 방식입니다. 유동성이 존재하지 않더라도, 유동성이 존재하는 효과를 발휘해 공격자가 공격을 시도하면 손실이 발생합니다. 이를 통해 공격자의 공격 비용이 늘어나고 이익 실현 가능성을 크게 낮춰 공격자의 공격 동기가 사라지도록 조치했습니다.

결론

ibToken의 교환비 조작에 관한 보안 위험성을 통해 알 수 있는 것은, 단순히 취약점을 인지하는 것을 넘어서 특정 상황에서 발생할 수 있는 악영향이 있는지 면밀히 살펴보아야 한다는 것입니다. 또한, 프로토콜을 fork 하거나 라이브러리(Library)를 사용할 때 모든 코드를 이해하고 적용하는 것이 중요함을 시사합니다. Fork 할 대상 프로토콜이 과거 해킹 사고가 전무하고, 높은 TVL을 유지하는 것은 똑같은 코드를 그대로 사용했을 때 보안 문제가 발생하지 않는다는 것을 보장하지 않기 때문입니다. Fork 한 프로젝트에서 발견되지 않은 취약점이 존재할 수 있고, 본 글에서 기술한 것처럼 유동성이 비어있을 때와 같은 특정한 상황에서 트리거 되는 취약점이 존재할 수 있기 때문입니다.


참고 자료


✨ We are ChainLight!

ChainLight 팀은 풍부한 실전 경험과 깊은 기술 이해를 바탕으로 새롭고 효과적인 블록체인 보안 기술을 연구합니다. 연구 결과를 바탕으로 Web3 생태계의 각종 보안 위험 요소와 취약점을 사전 파악하여 제거하는 혁신적인 보안 감사 서비스를 제공합니다. 보안 감사 이후에도 온체인 데이터 모니터링 및 취약점 탐지 자동화 서비스를 이용한 지속적인 디지털 자산 위험 관리 솔루션을 제공합니다.

ChainLight 팀은 사용자들이 탈중앙화 서비스를 안전하게 활용할 수 있도록 Web3 생태계 위협으로부터의 보호에 힘쓰고 있습니다.

  • ChainLight의 더 다양한 정보를 보고 싶으시다면? 👉 Twitter 계정도 방문해 주세요.


🌐 Website: chainlight.io | 📩 TG: @chainlight | 📧 chainlight@theori.io


Originally published at https://blog.theori.io on June 30, 2023.

Share article

Theori © 2025 All rights reserved.