2023년 4월 16일, Compound V2의 포크인 Hundred Finance가 공격을 받아 약 740만 달러의 손실이 발생했습니다. 이 공격에는 두 가지 주요 문제가 포함되어 있었습니다:
- 정밀도 손실 문제 (잘못된 반올림 문제);
- 빈 마켓(empty markets), 이를 통해 해커가 exchangeRate를 조작할 수 있었습니다.
DeFiLlama에 따르면 가장 많이 포크된 대출 프로토콜인 Compound V2는 100개 이상의 포크를 보유하고 있습니다. OpenZeppelin의 감사를 받고 실전에서 검증된 이 컨트랙트는 안전하다고 여겨졌습니다. 그러나 Hundred Finance 공격은 특히 낮은 유동성 환경에서 정밀도 손실이 DeFi 프로토콜 보안에 치명적인 영향을 미칠 수 있음을 보여주었으며, Midas와 Radiant 같은 유명 포크들에서도 유사한 취약점 악용 사례가 연이어 발생하는 계기가 되었습니다.
더 깊이 이해하고자 하신다면 전체 분석 자료를 참고하시기 바랍니다. 아래에서는 2023년 10대 보안 사고 중 하나로서 이 사건에 대한 간략한 소개를 제공합니다.
배경
Hundred Finance 개요
Hundred Finance는 Chainlink 오라클을 활용하여 여러 메인넷에서 운영되는 Compound v2의 포크입니다. 전통적인 금융 대출 방식과 달리, Compound와 Aave 같은 DeFi 대출 프로토콜은 초과 담보 대출을 허용하지 않습니다. 간단히 말해, $100 상당의 토큰 A를 예치하면 $100 미만의 자산만 빌릴 수 있습니다. 대부분의 프로토콜의 위험 통제 계수에 따르면, 이 비율은 일반적으로 50%에서 80% 사이입니다.
대출 프로토콜에서 흔한 공격 방법으로는 가격 조작과 재진입(reentrancy)이 있습니다. 흥미롭게도, Hundred Finance는 이전에 2022년 3월 재진입 공격을 경험한 바 있지만, 이번 사건은 새로운 공격 벡터를 만들어냈습니다.
hToken
Compound와 Aave를 포크한 대출 프로토콜은 각 기초 토큰(담보)에 대응하는 회계 토큰을 생성합니다. Hundred Finance의 경우:
- USDC는 hUSDC에 대응
- WBTC는 hWBTC에 대응
기초 토큰과 hToken 사이의 교환 비율을 exchangeRate라고 합니다.
- 자산을 예치할 때, 사용자는 hToken의
mint()를 호출해야 합니다. - 자산을 인출할 때, 사용자는 hToken의
redeem()을 호출해야 합니다.
exchangeRate
다음은 exchangeRate 계산 공식입니다:

여기서:
getCash(): 이 hToken 컨트랙트가 소유한 기초 토큰 잔액의 양. 이것은 조작될 수 있는 핵심 파라미터입니다. 기억해 두시기 바랍니다.totalBorrows(): 마켓에서 현재 대출된 기초 토큰의 양으로, 마켓 공급자에게 이자가 누적되는 기준 금액입니다.totalReserves(): 준비금은 각 hToken 컨트랙트의 회계 항목으로, 프로토콜의 거버넌스를 통해 출금하거나 이전할 수 있는 현금으로 따로 적립된 과거 이자의 일부를 나타냅니다.totalSupply(): 현재 이 hToken 마켓에서 유통 중인 토큰의 수량.
참고: hToken과 기초 자산 간의 exchangeRate(예: dai 대 hDai 또는 eth 대 hEth)는 0.020에서 시작하여 복리 시장 이자율과 동일한 속도로 증가합니다.
청산(Liquidation)
부실 채권을 방지하기 위해 대출 프로토콜은 모든 사용자가 다른 사용자의 채무를 청산할 수 있도록 허용합니다. 다음 예시를 통해 설명하겠습니다:
- 앨리스는 $100 상당의 BTC를 예치하고 $70 상당의 ETH를 빌립니다.
- ETH 가격이 상승하거나 BTC 가격이 하락하면, 앨리스의 자산이 청산 임계값에 도달할 수 있습니다.
- 밥은 일정량의 ETH를 사용하여 앨리스의 BTC를 청산함으로써, 앨리스의 부채를 건전한 수준으로 되돌려 프로토콜 자금의 안전을 보장할 수 있습니다(프로토콜은 청산을 시작한 사용자에게 보상을 제공합니다).
청산은 이번 공격의 핵심이 아니지만, 공격에 관여되었습니다. 여기서 우리는 단지 모든 사용자가 한 종류의 토큰으로 다른 사용자의 채무를 청산할 수 있으며, 이로 인해 해당 hToken이 감소한다는 점만 알면 됩니다.
취약점
정밀도 손실 문제
해커는 redeem()을 통해 담보를 인출할 때, 차감해야 할 hToken 계산 결과가 1.99999992(2에 매우 가깝지만 2 미만)가 되도록 만듭니다. truncate()에서 정수로 변환할 때 내림(rounding down) 처리로 인해 최종 결과가 1이 됩니다.

exchangeRate
앞서 소개한 바와 같이, exchangeRate 계산에는 hToken 컨트랙트가 소유한 기초 잔액의 양을 나타내는 getCash()가 포함됩니다. 기초 토큰을 컨트랙트에 직접 전송함으로써(mint 없이 단순 전송), 해커는 exchangeRate를 조작할 수 있습니다.
그러나 이 exchangeRate 문제만으로는 프로토콜의 보안을 위협하지 않는다는 점을 주목해야 합니다. 해커는 이것만으로는 이익을 얻을 수 없습니다. 이번 공격의 맥락에서, 이는 주로 해커의 이익을 증폭시켜 풀을 빠르게 고갈시키는 데 활용되었습니다. 그렇지 않았다면, 공격은 단 한 번의 결정적인 타격에서 여러 차례의 소규모 공격으로 바뀌어 상당한 영향을 미치기 위해 수많은 반복이 필요했을 것입니다.
간단히 말하면, 정밀도 손실이 이번 공격의 핵심 문제입니다.
공격 과정
다음은 공격 트랜잭션이며, Phalcon Explorer를 사용하여 이 복잡한 트랜잭션을 분석하겠습니다.
트랜잭션: 0x6e9ebcdebbabda04fa9f2e3bc21ea8b2e4fb4bf4f4670cb8483e2f0b2604f451
-
플래시론을 통해 Aave V3에서 500 WBTC를 빌립니다.
-
이전에 획득한 모든 hWBTC를
Redeem하여, hWBTC의totalSupply를 0으로 초기화합니다.
이전 단계의 목적은 플래시론을 이용해 준비 자금을 마련하고 hWBTC를 새로운 마켓으로 초기화하는 것입니다.
-
두 번째 공격 컨트랙트(공격 컨트랙트 2라고 함)를
Create하고 모든 WBTC(500.30063816 WBTC)를 공격 컨트랙트 2로 전송합니다.
-
4 WBTC를 사용하여
Mint()hWBTC를 200 hWBTC 생성합니다. -
199.99999998 hWBTC를
Redeem()하여, hWBTC 총량을 0.00000002(2 wei hWBTC)로 남겨둡니다. -
모든 WBTC(500.30063816 WBTC)를 hWBTC로 전송합니다. 직접 전송은 hWBTC를 증가시키지 않으며, WBTC를 풀에 기부하는 것으로 볼 수 있습니다. 이 단계의 주요 목적은 앞서 언급한
exchangeRate를 조작하는 것입니다. 이 시점에서 hWBTC의totalSupply는 여전히 2 wei hWBTC이지만, 이제 500.30064194 WBTC가 있어exchangeRate가 원래의 수백 배가 됩니다.

-
hETH 마켓에서 1021 Ether를 빌립니다.
-
50030063815 WBTC를
Redeem()합니다. 계산상 1.9999992 hBTC가 차감되어야 하지만, 정밀도 손실로 인해 1 hBTC만 차감되어 상당한 정밀도 손실(약 50%)이 발생합니다.
이 시점에서 해커는 500 WBTC + 1021 Ether를 보유하여 1021 Ether의 수익을 성공적으로 얻었습니다. -
공격자는 남은 hWBTC를
liquidate()하여, 다른 마켓에 대한 공격을 계속하기 위한 준비로totalSupply를 0으로 초기화합니다. hWBTC 내의 거의 모든 WBTC가 인출되었기 때문에, 해커는 단 0.000002 Ether만으로 이를 처리합니다.
-
다른 마켓에 대한 공격을 계속하여 전체 프로토콜을 고갈시킵니다.
-
Aave에 플래시론을 상환합니다.
보안 권고사항
대출 프로토콜을 위한 완화 방안
이 문제는 특히 Compound와 Aave의 포크에서 광범위하게 나타납니다. 선제적인 접근 방법으로는, 새로운 마켓을 출시할 때 일부 회계 토큰을 발행하여 totalSupply가 절대 0이 되지 않도록 보장하는 것이 있습니다.
정밀도 손실 문제를 위한 완화 방안
정밀도 손실로 인한 일련의 문제를 더 잘 방지하기 위해, 최솟값을 설정하는 것이 실무에서 효과적인 방법입니다. 이 전략은 매우 작은 값을 처리할 때 정밀도 손실로 인한 심각한 영향을 피하는 데 도움이 됩니다.
이 시리즈의 다른 글 읽기:
- 도입: 2023년 10대 "주목할 만한" 보안 사고
- #1: Flashbots Relay의 취약점을 악용한 MEV 봇 수확
- #2: Euler Finance 사고: 2023년 최대 규모의 해킹
- #3: KyberSwap 사고: 극도로 정교한 계산으로 반올림 오류를 교묘하게 악용
- #4: Curve 사고: 컴파일러 오류로 인해 무해한 소스 코드에서 잘못된 바이트코드 생성
- #5: Platypus Finance: 행운으로 세 번의 공격에서 살아남다
- #7: ParaSpace 사고: 업계에서 가장 치명적인 공격을 막기 위한 시간과의 싸움
- #8: SushiSwap 사고: 서툰 구조 시도가 일련의 모방 공격으로 이어지다
- #9: MEV 봇 0xd61492: 독창적인 익스플로잇으로 포식자에서 먹이로
- #10: ThirdWeb 사고: 신뢰할 수 있는 모듈 간의 비호환성이 취약점을 노출



