Back to Blog

주간 Web3 보안 사고 요약 | 2026년 3월 9일 – 3월 15일

March 18, 2026
19 min read

지난 한 주(2026/03/09 - 2026/03/15) 동안 BlockSec은 총 8건의 공격 사건을 탐지 및 분석했으며, 총 추정 손실은 약 $1.66M입니다. 아래 표는 각 사건을 요약하며, 이후 소절에서 각 사례에 대한 상세 분석을 제공합니다.

날짜 사건 유형 추정 손실
2026/03/09 EtherFreakers 사건 결함 있는 비즈니스 로직 ~$25K
2026/03/10 Alkemi 사건 결함 있는 비즈니스 로직 ~$89K
2026/03/10 MT 사건 결함 있는 비즈니스 로직 ~$242K
2026/03/11 AAVE 청산 사건 잘못된 설정 ~$1.01M
2026/03/11 Planet Finance 사건 결함 있는 비즈니스 로직 ~$10K
2026/03/12 AM 사건 결함 있는 비즈니스 로직 ~$131K
2026/03/12 DBXen 사건 결함 있는 비즈니스 로직 ~$149K
2026/03/15 Goose Finance 사건 결함 있는 비즈니스 로직 ~$8K

EtherFreakers 사건

간략한 요약

2026년 3월 9일, 이더리움의 NFT 게임인 EtherFreakers가 잘못된 이중 계산으로 인해 익스플로잇되어 약 $25K의 손실이 발생했습니다. 게임 내 각 NFT는 인출 가능한 ETH 잔액(이른바 "에너지")을 보유합니다. 게임 메커니즘으로서, 플레이어는 attack()을 사용하여 하나의 NFT가 다른 NFT를 포획하고 대상의 에너지를 획득할 수 있습니다. 그러나 컨트랙트는 회계 처리를 완료하기 전에 대상의 잔액을 지급하고 NFT를 전송합니다. 이때 전송 훅이 오래된 지급 이전 데이터를 읽어 그 일부를 글로벌 배당 풀에 다시 투입하여, 새로운 ETH 뒷받침 없이 풀을 부풀립니다. 공격자는 이 포획 메커니즘을 반복하여 글로벌 인덱스를 펌핑한 뒤, 다수의 NFT에서 부풀려진 잔액을 탈취했습니다.

배경

EtherFreakers는 온체인 NFT 게임으로, 각 NFT("Freaker"라고 불림)는 energy라는 인출 가능한 ETH 잔액을 보유합니다. 이 시스템은 배당 풀 방식으로 작동합니다: 특정 행동이 발생하면 ETH의 일정 비율이 모든 Freaker에게 비례하여 분배됩니다. 각 Freaker의 청구 가능한 ETH는 글로벌 누산기 freakerIndex와 토큰별 지분 가중치 fortune의 조합으로 추적됩니다.

구체적으로, 회계 공식은 다음과 같습니다: energyOf = basic + (freakerIndex - index) * fortune. freakerIndex_dissipateEnergyIntoPool(amount)가 실행될 때 증가하며, amount의 80%를 모든 Freaker에게 분배하고 20%는 창작자에게 분배합니다. charge()를 통한 직접 예치는 freakerIndex에 영향을 주지 않고 basic만 증가시킵니다. 따라서 freakerIndex의 증가는 항상 시스템에 실제로 유입되는 이더에 의해 뒷받침되어야 합니다. freakerIndex가 대응하는 ETH 유입 없이 증가하면, Freaker는 컨트랙트가 실제로 보유한 것보다 더 많은 이더를 상환할 수 있게 됩니다.

취약점 분석

근본 원인은 EtherFreak 컨트랙트(0x3A27...c0f33)의 잘못된 실행 순서입니다. 포획이 성공하면 attack() 함수는 다음 단계를 순서대로 실행합니다:

  1. 237번 줄: 방어자에게 targetCharge(대상 NFT의 전체 에너지)를 직접 ETH 전송으로 지급합니다. 이제 에너지는 소진됩니다.
  2. 240번 줄: _transfer(defender, capturer, targetId)를 호출하여 NFT를 이동시킵니다. 내부적으로 _transfer()는 ERC-721 훅 _beforeTokenTransfer()를 호출하며, 이는 energyOf(targetId)의 0.1%를 인자로 _dissipateEnergyIntoPool()를 호출합니다. 이것이 _dissipateEnergyIntoPool()의 첫 번째 호출이며, 5단계가 아직 실행되지 않았으므로 오래된 값을 읽습니다.
  3. 241번 줄: _dissipateEnergyIntoPool(sourceSpent)를 명시적으로 호출합니다. 이것이 두 번째 호출이며, 일반 게임 로직의 일부입니다.
  4. 244~251번 줄: sourceIdtargetId 모두에 대해 energyBalances를 업데이트합니다.

버그는 2단계에 있습니다: energyBalances[targetId]가 아직 업데이트되지 않았기 때문에, 훅은 여전히 지급 이전 잔액을 보고 이미 소진된 에너지의 일부를 배당 풀에 투입합니다. 1단계의 직접 ETH 지급과 2단계의 풀 투입이 동일한 에너지에서 발생하여, 새로운 ETH 뒷받침 없이 freakerIndex를 부풀립니다.

freakerIndex_dissipateEnergyIntoPool()가 호출될 때마다 증가합니다:

공격 분석

다음 분석은 트랜잭션 0x89e24d...9abd2942를 기반으로 합니다.

  • 1단계: 1,700 WETH를 대출합니다.

  • 2단계: 공격자가 제어하는 주소 아래에 새로운 Freaker, 토큰 590과 토큰 591 두 개를 발행합니다.

  • 3단계: 게임의 attack(590, 591) 함수를 반복적으로 호출하여 포획 성공 분기에서 실행을 유지합니다.

  • 4단계: 각 성공 후, 같은 쌍을 재사용할 수 있도록 토큰 591을 헬퍼에게 다시 전송합니다.

  • 5단계: 각 성공적인 루프는 시스템이 실제로 보존하는 이더 이상으로 freakerIndex를 부풀립니다.

  • 6단계: 인덱스가 충분히 높아지면, 이전에 제어하던 Freaker 배치를 방전시킵니다. 토큰 ID 496에서 520까지 각각 0.278052246002402082 이더로 방전됩니다.

  • 7단계: 탈취한 이더를 WETH로 변환하고, 1,700 WETH 플래시 론을 상환한 뒤 약 7.498 WETH를 수익으로 보유합니다.

결론

근본 원인은 attack()의 포획 성공 흐름에 있습니다: EtherFreakers는 대상 토큰의 에너지 상태가 확정되기 전에 targetCharge를 지급합니다. 그 후 _transfer()_beforeTokenTransfer()를 트리거하여, 오래된 지급 이전 energyOf(targetId) 값을 읽고 그 일부를 풀에 투입합니다. 이는 새로운 이더 뒷받침 없이 freakerIndex를 증가시키므로, 동일한 대상 에너지가 지급과 풀 투입 모두에 계산됩니다. 이것은 재진입 버그가 아닌 비즈니스 로직 인플레이션 버그입니다.

향후 유사한 위험을 줄이기 위해:

  • 동일한 트랜잭션이 아직 처리 중인 동안 전송 훅 내부에서 가변 상태의 경제적 값을 재계산하는 것을 피하십시오.

  • 전송 훅이 상태 변수를 읽는 경우, 실행 순서가 결과에 영향을 미치지 않도록 하십시오(예: 훅이 실행된 후가 아닌 전에 상태를 확정).


Alkemi 사건

간략한 요약

2026년 3월 10일, 이더리움의 Alkemi 프로토콜이 익스플로잇되어 약 $89K의 손실이 발생했습니다. 근본 원인은 회계 오류와 결함 있는 비즈니스 로직입니다. 결함 있는 청산 로직은 누구든 동일한 트랜잭션 내에서 자신의 포지션을 청산하고 수익을 얻을 수 있게 합니다. 또한, 회계 오류로 인해 청산 시 공격자 자신의 담보 차감이 덮어쓰여져, 공격자가 의도된 비용 없이 청산 보상을 획득할 수 있습니다.

배경

Alkemi는 대출 프로토콜입니다. 차용자의 포지션이 담보 부족 상태가 되면, 누구든 liquidateBorrow()를 호출하여 부채의 일부를 상환하고 할인된 가격으로 담보를 압류할 수 있습니다. 과도한 청산을 방지하기 위해, 프로토콜은 트랜잭션당 상환 가능한 금액을 다음 세 값의 최솟값으로 제한합니다:

  1. 차용자의 현재 대출 잔액 (currentBorrowBalance_TargetUnderwaterAsset).
  2. 청산 할인 적용 후 차용자의 담보가 커버할 수 있는 최대 상환액 (calculateDiscountedBorrowDenominatedCollateral()).
  3. 계정을 청산 경계로 되돌리는 데 필요한 상환액 (calculateDiscountedRepayToEvenAmount()), 시장이 isSupported인 경우에만 확인.

취약점 분석

근본 원인은 Alkemi 프로토콜(0x4822...a888)의 결함 있는 비즈니스 로직과 회계 오류입니다. 차용자에게 미상환 부채가 있는 한 currentBorrowBalance_TargetUnderwaterAsset은 필연적으로 0보다 크고, 차용자에게 담보가 있는 한 calculateDiscountedBorrowDenominatedCollateral()이 반환하는 값도 필연적으로 0보다 크기 때문에, AlkemiEarnPublic 프로토콜은 사실상 calculateDiscountedRepayToEvenAmount()에 의존하여 특정 대출이 청산 가능한지 여부를 결정합니다. 이 함수에서 청산해야 할 부채의 양은 accountShortfall_TargetUser라는 변수를 기반으로 계산되어야 합니다.

그러나 실제 구현에서는 함수가 대신 전역 변수 closeFactorMantissa를 사용하여 상환 허용 부채 금액의 상한선을 계산하고 이 값을 반환합니다. 결과적으로, 공격자는 동일한 트랜잭션 내에서 대출을 받고 즉시 자신의 포지션을 청산할 수 있게 됩니다.

또한, liquidateBorrow() 함수에서 청산자와 차용자가 동일한 주소일 때, 변수 supplyBalance_TargetCollateralAssetsupplyBalance_LiquidatorCollateralAsset은 동일한 스토리지 슬롯을 가리킵니다. 함수는 동일한 초기 잔액을 기반으로 "감소된 잔액"과 "보상된 잔액"을 각각 계산하고, 이후 동일한 스토리지 슬롯에 순서대로 다시 씁니다. 감소된 잔액이 먼저 쓰여지고 보상된 잔액이 이후에 쓰여지기 때문에, 감소 효과는 덮어쓰여져 사라지고 보상 결과만 남게 됩니다. 이를 통해 공격자는 수익을 더욱 증폭시킬 수 있습니다.

공격 분석

다음 분석은 트랜잭션 0xa170...6d9d를 기반으로 합니다.

  • 1단계: 공격자는 Balancer에서 51e18 WETH 플래시 론을 실행합니다.

  • 2단계: 공격자는 51e18 WETHETH로 언래핑하여 Alkemi 프로토콜에 공급합니다.

  • 3단계: 공격자는 Alkemi에서 39.5e18 ETH를 대출합니다.

  • 4단계: 공격자는 39.5395e18 ETH를 사용하여 자신의 포지션을 청산합니다.

  • 5단계: 공격자는 Alkemi에서 93.5e18 ETH를 인출합니다.

  • 6단계: 공격자는 플래시 론을 상환하고 43.4e18 ETH의 수익을 얻습니다.

결론

근본 원인은 결함 있는 청산 로직이 공격자로 하여금 동일한 트랜잭션 내에서 대출 후 자신의 포지션을 청산하여 수익을 얻을 수 있게 하는 반면, 잘못된 회계 로직은 공격자의 이득을 더욱 증폭시킨다는 것입니다.

향후 유사한 위험을 줄이기 위해:

  • 차용자와 청산자에 대한 잔액 업데이트 시, 프로토콜은 잔액을 별도 계산 및 재기록을 위해 임시 메모리 변수에 복사하는 대신 스토리지 변수에 직접 연산해야 합니다.

MT 사건

간략한 요약

2026년 3월 10일, BNB Chain의 디플레이션 토큰 MT Token이 익스플로잇되어 약 $242K의 손실이 발생했습니다. 근본 원인은 결함 있는 거래 제한 로직과 특수 전송 조건의 일관성 없는 처리입니다. 디플레이션 단계 중 컨트랙트는 풀 준비금이 고정 임계값을 초과할 때 매수 작업을 제한합니다. 그러나 컨트랙트는 정확한 금액(예: 2e17 MT)의 전송을 리퍼럴 바인딩 행동으로 처리하여, 공격자가 매수 제한을 우회하고 초기 토큰을 획득할 수 있게 합니다. 또한, 제한 로직은 불완전한 경로 감지(isBuy)에 의존하여 Pair에서 Router로의 간접 스왑 경로를 커버하지 못하며, 화이트리스트 확인이 중요한 검증을 추가로 단락시킵니다. 공격자는 제한이나 수수료를 트리거하지 않고 MT 토큰을 축적하고, 통제된 유동성 운영과 거래를 통해 pendingBurnAmount를 조작하여, 토큰 가격이 인위적으로 부풀려진 비정상적인 상태로 풀을 몰았습니다.

배경

MT Token은 내장된 거래 제한이 있는 BNB Chain의 디플레이션 토큰입니다. 디플레이션 단계에서 컨트랙트는 풀의 MT 준비금이 21,000e18을 초과할 때 매수 작업을 차단합니다. 준비금이 이 임계값 아래로 떨어지면 디플레이션 단계가 종료되고 매수가 재활성화됩니다. MT Token에는 리퍼럴 메커니즘도 포함되어 있습니다: 정확히 2e17 MT 또는 1e17 MT의 전송은 일반 거래가 아닌 추천인 바인딩 행동으로 처리됩니다.

취약점 분석

근본 원인은 MT 컨트랙트(0x037E...b449)의 결함 있는 매수 제한 설계입니다. 정상적인 상황에서 공격자는 제한 단계에서 시드 자본으로 MT를 획득할 수 없어야 합니다. 그러나 컨트랙트는 정확히 2e17 MT의 전송을 매수가 아닌 리퍼럴 바인딩 행동으로 처리하여, 공격자가 매수 제한을 우회하면서 2e17 MT를 구매할 수 있게 합니다.

또한, 거래 제한은 isBuy 분기에 의존하여 구매를 차단하지만, "Pair에서 Router로" 경로를 커버하지 않습니다. Router와 Pair 모두 화이트리스트 주소이므로, 그러한 전송은 화이트리스트 확인에서 단락되어 매수 제한 로직에 도달하지 않습니다. 이를 통해 공격자는 매수를 Router로 라우팅하고 이후 유동성을 제거하여 토큰을 자신에게 돌려받는 방식으로 MT를 획득할 수 있습니다.

공격 분석

다음 분석은 트랜잭션 0xfb57...fca6를 기반으로 합니다.

  • 1단계: 공격자는 ~358,681e18 WBNB를 플래시 론합니다.

  • 2단계: 공격자는 2e17 MT를 구매하여 매수 제한을 우회합니다.

  • 3단계: 공격자는 유동성 추가를 위해 Pair에 4e12 WBNB2e17 MT를 공급합니다. 이 전송은 위와 같은 이유로 수수료 부과 로직을 우회했습니다.

  • 4단계: 공격자는 Pair에서 Router로 ~10,000,000e18 MT 토큰을 매수하여, 매수 제한과 수수료 부과 로직 모두를 우회합니다.

  • 5단계: 공격자는 유동성 포지션의 절반을 제거하여 Router가 보유한 모든 MT 토큰을 추출한 뒤, 회수한 MTWBNB로 매도합니다. 이 단계에서 pendingBurnAmount가 약 9,000,000e18로 조작됩니다.

  • 6단계: 공격자는 ~10,000,000e18 MT 토큰을 다시 매수하여, 풀의 MT 준비금을 ~6,756,516e18으로 낮추었으며, 이는 pendingBurnAmount보다 낮은 수준입니다.

  • 7단계: 공격자는 남은 유동성 포지션 절반을 제거하고, 구매한 MT 토큰을 인출한 후, distributeDailyRewards()를 호출하여 풀에서 MT를 소각합니다. 결과적으로 MT 준비금이 21,000e18으로 감소합니다.

  • 8단계: 공격자는 모든 MT~1,198e18 WBNB로 스왑하고, 플래시 론을 상환한 뒤 수익을 확정합니다.

결론

이 익스플로잇은 잘못된 거래 제한으로 인해 발생했으며, 공격자가 정확히 BINDING_AMOUNTMT 토큰을 구매하여 매수 금지를 우회할 수 있었습니다. MT 토큰을 획득한 후, 공격자는 유동성 추가, Router로 MT 매수, 유동성 제거를 통한 토큰 회수를 통해 수수료 부과 로직과 매수 제한을 모두 우회할 수 있었습니다. 공격자는 이후 매도 작업을 통해 pendingBurnAmount를 축적하고 소각을 실행하여 풀 준비금을 비정상적인 상태로 몰아, 인위적으로 부풀려진 가격에 MT를 매도하고 수익을 얻었습니다.

향후 유사한 위험을 줄이기 위해:

  • 전송 의미론과 거래 로직 사이에 엄격한 분리를 적용하십시오.

AAVE 청산 사건

간략한 요약

2026년 3월 11일, AAVE는 이더리움에서 $21M에 달하는 잘못된 청산을 겪어 약 $1.01M의 손실이 발생했습니다. 근본 원인은 wstETH에 대한 잘못된 오라클 가격으로, 원래 건전했던 포지션이 담보 부족 상태가 되었습니다. 결과적으로 사용자의 포지션이 청산되어 재정적 손실이 발생했습니다.

배경

AAVE는 오라클 어댑터를 사용하여 wstETH와 같은 래핑된 자산의 가격을 책정합니다. 어댑터 CAPO(Capped Price Oracle)는 기본 ETH/USD 가격에 전환 비율(getRatio(), 즉 wstETH 하나가 얼마만큼의 ETH에 해당하는지)을 곱하여 wstETH 가격을 도출합니다. 비율 조작을 방지하기 위해, CAPO는 스냅샷 기반 성장 상한을 적용합니다:

maxRatio = snapshotRatio + maxGrowthPerSecond x (currentTime - snapshotTimestamp)

그리고 가격 책정 시 getRatio() 출력을 고정합니다(currentRatio > maxRatio이면 maxRatio를 사용). 이 메커니즘은 비율과 결과 가격의 최대 상향 드리프트를 효과적으로 제한합니다.

취약점 분석

근본 원인은 CAPO 오라클 앵커 설정(0xe1D9...61Ef)의 시간-비율 불일치였습니다: 스냅샷 타임스탬프와 스냅샷 비율이 설정되었지만, 스냅샷 비율이 실제 wstETH/ETH 비율보다 낮게 구성되었습니다. 결과적으로 어댑터가 계산한 maxRatio가 실시간 비율보다 낮아져 getRatio()를 하향 고정하여, 체계적으로 wstETH/USD 오라클 가격을 과소평가했습니다. 이로 인해 담보 가치가 낮아져 wstETH를 담보로 사용하는 포지션의 건전성 지수가 감소하였고, 건전한 계정이 잘못된 방식으로 비건전 상태로 분류되어 청산되었습니다.

공격 분석

다음 분석은 트랜잭션 0x9064...8a9c를 기반으로 합니다.

  • 1단계: 청산자는 ~6304e18 WETH를 플래시 론하여 차용자를 청산합니다.

  • 2단계: 청산자는 플래시 론을 상환하며 청산을 완료합니다.

결론

이 청산은 잘못된 오라클 가격 설정으로 인해 발생했으며, 건전 상태를 유지해야 할 차용자를 잘못된 방식으로 비건전 상태로 몰아 포지션 청산을 트리거했습니다.

향후 유사한 위험을 줄이기 위해:

  • 각 업데이트 전에 중요한 파라미터의 정확성을 검증하십시오.

  • 잘못된 파라미터를 거부하고 잘못된 설정이 성공적으로 적용되는 것을 방지하기 위해 구현에 검증 확인을 추가하십시오.


Planet Finance 사건

간략한 요약

2026년 3월 11일, Planet Finance가 BNB Chain에서 익스플로잇되어 약 $10K의 손실이 발생했습니다. 근본 원인은 프로토콜이 차용자의 저장된 대출 잔액 증가를 발생된 이자로 잘못 처리하여, 공격자가 반복적으로 대출을 받고 할인 정산을 트리거하여 기록된 부채를 과소계상할 수 있었다는 것입니다.

배경

Planet Finance는 차용자가 이자 할인으로 상환할 수 있는 대출 프로토콜입니다. 할인은 등급제로 적용되며, 사용자의 스테이킹된 GAMMA와 다른 자산의 스테이킹된 가치 비율에 따라 결정됩니다: 이 비율이 높을수록 상환 할인이 높아집니다. 할인 일정은 세 등급으로 구성되며, 최소 0%에서 최대 50%까지 범위입니다.

취약점 분석

근본 원인은 changeUserBorrowDiscount()에서 차용자의 할인을 정산할 때, 프로토콜(0x4c9E...F467)이 차용자의 저장된 대출 잔액 증가를 새롭게 발생된 이자로 잘못 처리했다는 것입니다. 결과적으로 발생 이자에만 적용되어야 할 할인이 새로 빌린 원금에 잘못 적용되어, 차용자의 기록된 부채가 부적절하게 감소했습니다. 공격자는 borrowchangeUserBorrowDiscount 루프를 반복적으로 수행하여 과도한 할인을 축적하고, 온체인 기록 부채를 실제 대출 금액보다 지속적으로 낮게 만들어 궁극적으로 그 차이에서 수익을 얻을 수 있었습니다.

공격 분석

다음 분석은 트랜잭션 0x5f45...5ec9를 기반으로 합니다.

  • 1단계: 공격자는 200,000e18 USDT를 플래시 론합니다.

  • 2단계: 공격자는 5,000e18 USDT를 사용하여 WBNB를 구매한 뒤, 획득한 WBNB~8,726,524e18 GAMMA를 구매합니다.

  • 3단계: 공격자는 먼저 획득한 모든 GAMMA를 gGAMMA 마켓에 스테이킹한 후, 나머지 USDT를 담보로 공급하여 상환 할인을 5%로 높이고 이후 대출을 가능하게 합니다.

  • 4단계: 공격자는 borrowupdateUserDiscount를 반복적으로 호출하여 기록된 부채를 지속적으로 감소시킵니다.

  • 5단계: 공격자는 최종적으로 부채를 상환하고 담보를 환매하여 수익을 실현합니다.

결론

이 사건은 Planet Finance의 changeUserBorrowDiscount()의 결함 있는 할인 정산 로직으로 인해 발생했으며, 차용자의 저장된 대출 잔액 증가를 새롭게 발생된 이자로 잘못 처리하고 이자 할인을 그 증분에 적용합니다. 공격자는 borrowupdateUserDiscount를 반복적으로 호출하여 기록된 부채를 과소계상하고 궁극적으로 실제 부채보다 적게 상환하여 수익을 추출할 수 있습니다.

향후 유사한 위험을 줄이기 위해:

  • 대출 프로토콜에서 이자와 신규 대출을 구별하십시오.

AM 사건

간략한 요약

2026년 3월 12일, BNB Chain의 디플레이션 토큰 AM Token이 익스플로잇되어 약 $131K의 손실이 발생했습니다. AM Token은 각 매도 시 유동성 풀에서 추가 소각을 트리거하여 총 공급량을 줄이는 디플레이션 메커니즘을 구현합니다. 그러나 소각은 즉시 실행되지 않습니다 - 대신, 전체 매도 금액이 toBurnAmount로 기록되고 실제 소각은 다음 매도 시로 연기됩니다. 이 지연은 기록과 실행 사이에 창구를 만들며, 그 동안 공격자는 AM을 다시 매수하여 풀의 AM 준비금을 toBurnAmount까지 줄일 수 있습니다. 다음 매도가 지연된 소각을 트리거하면, 전체 AM 준비금이 소멸되어 가격이 극단적으로 상승하고, 공격자는 AM을 매도하여 수익을 얻을 수 있습니다.

배경

AM Token은 BNB Chain의 디플레이션 토큰입니다. 각 매도 시 컨트랙트는 스왑에 관련된 AM 금액을 toBurnAmount로 기록하고, 다음 매도 시 해당 기록된 금액을 유동성 풀에서 소각합니다. 사실상, 매도는 풀의 AM 준비금을 줄이는 지연된 소각을 트리거합니다. 또한, 소각을 실행하기 전에 프로토콜은 누적된 totalTokenFeeUSDT로 스왑하여 수수료 할당 로직에 따라 분배합니다.

취약점 분석

근본 원인은 토큰(0x27f9...213f)의 매도 로직이 전체 스왑된 AM 금액을 toBurnAmount로 누적하고 다음 매도 시 AM/USDT 페어에서 토큰을 제거하고 pair.sync()를 호출하여 준비금을 업데이트하는 방식으로 소각을 실행한다는 것입니다. 이 설계는 공격자가 풀의 AM 준비금을 조작하고, 온체인 가격을 왜곡하여 차익 거래로 수익을 얻을 수 있게 합니다.

공격 분석

다음 분석은 트랜잭션 0xd0d1...f859를 기반으로 합니다.

  • 1단계: 공격자는 ~27,265,119e18 USDC~361,710e18 WBNB를 플래시 론한 후, 이를 ~100,423,811e18 USDT로 스왑합니다.

  • 2단계: 공격자는 ~5,062e18 AM 토큰을 USDT로 스왑하여, 컨트랙트의 기록된 toBurnAmount~4,303e18으로 조작합니다.

  • 3단계: 공격자는 USDT를 AM Token으로 스왑하여, 풀의 AM 준비금을 ~4,303e18으로 낮춥니다.

  • 4단계: 공격자는 6 wei AM을 풀에 전송하여 매도 경로 소각 로직을 트리거합니다. 결과적으로 컨트랙트는 풀에서 전체 AM 잔액을 소각하여 AM 준비금을 0으로 낮춥니다. 참고: 프로토콜은 소각 전에 먼저 누적된 수수료를 USDT로 스왑하려 시도합니다. 이 수수료 전환 경로도 매도 분기 소각 로직을 트리거합니다. 소각이 실행되고 AM 준비금이 0에 도달하면, 수수료 스왑이 실패합니다. try/catch로 감싸져 있기 때문에, 실패는 트랜잭션을 되돌리지 않습니다. 대신 실행이 계속되고 수수료 누산기가 0으로 재설정됩니다.

  • 5단계: 공격자는 pool.sync()를 호출하고 남은 USDT1 wei AM을 풀에 전송합니다. 두 토큰이 동시에 전송되었기 때문에, 컨트랙트는 이를 addLiquidity로 처리하여 toBurnAmount가 누적되지 않았습니다. AM 준비금은 7로 업데이트되었습니다.

  • 6단계: 공격자는 남은 AM 토큰을 USDT로 스왑합니다. 이 스왑 중 AM을 Pair에 전송하면 매도 경로 소각 로직이 트리거되어 AM 준비금이 1로 감소합니다. 또한, 4단계에서 totalFeeAmount가 0으로 재설정되었기 때문에, 수수료를 USDT로 전환하는 작업이 더 이상 실행되지 않아, 공격자가 인위적으로 부풀려진 가격에 AM을 매도할 수 있었습니다.

  • 7단계: 공격자는 플래시 론을 상환하고 남은 수익을 실현합니다.

결론

이 사건은 AM Token의 결함 있는 소각 메커니즘으로 인해 발생했으며, 각 매도의 스왑 관련 AMtoBurnAmount로 누적하고 다음 매도 시 AM/USDT Pair에서 해당 금액을 소각하면서 pool.sync()를 호출합니다. 이를 통해 공격자는 Pair의 AM 준비금을 극단적인 수준으로 조작하고 인위적으로 부풀려진 가격에 AM을 매도하여 USDT를 탈취할 수 있습니다.

향후 유사한 위험을 줄이기 위해:

  • 트랜잭션당 최대 소각 금액을 제한하고 소각 트리거 빈도를 제한하여, 공격자가 단기간에 풀의 토큰 준비금을 대량으로 소비하는 것을 방지하십시오.

DBXen 사건

간략한 요약

2026년 3월 12일, 이더리움과 BNB Chain의 번-투-언(burn-to-earn) 프로토콜 DBXen이 익스플로잇되어 총 약 $149K의 손실이 발생했습니다. 근본 원인은 _msgSender()msg.sender 사이의 불일치입니다. burnBatch()forwarder를 통해 호출될 때, 소각된 XEN 금액은 _msgSender()(공격자 제어)에 기록되지만, 사이클 기록은 msg.sender(forwarder)에 업데이트됩니다. 이 분리를 통해 공격자는 오래된 사이클 기록에 대한 보상과 수수료를 청구하여 비정상적으로 큰 지급을 받을 수 있습니다.

배경

DBXen은 번-투-언 프로토콜입니다: 사용자는 XEN 토큰을 소각하여 DXN 보상과 누적된 프로토콜 수수료의 일부를 받습니다. 핵심 메커니즘은 사이클 단위로 작동합니다. 사용자가 burnBatch()를 호출하면 두 가지가 발생합니다: (1) 소각된 XEN 금액이 호출자 주소(_msgSender()로 식별)에 기록되고, (2) XEN 컨트랙트가 onTokenBurned()를 통해 DBXen으로 콜백하여 호출자의 사이클 기록(소각 사이클과 lastFeeUpdateCycle)을 현재 사이클로 업데이트합니다.

보상과 수수료는 updateStats()를 통해 정산됩니다. 보상은 소각 사이클에서 사용자의 총 소각된 XEN 비율에 비례합니다. 수수료는 사용자의 마지막 기록된 사이클 이후 발생한 누적 프로토콜 수수료를 기반으로 합니다. 두 계산 모두 사용자의 사이클 기록이 최신 상태인지에 따라 달라집니다.

취약점 분석

근본 원인은 DBXen 프로토콜(0xf5c8...2abd)의 결함 있는 비즈니스 로직입니다. _msgSender() 함수는 msg.senderforwarder인지 확인합니다. 그렇다면 calldata의 마지막 20바이트를 반환하며, 이 반환값은 forwarder 컨텍스트에서 임의로 제어될 수 있습니다. 그러나 burnBatch()msg.sender가 보유한 XEN을 직접 소각합니다. 결과적으로, 공격자는 forwarder를 통해 burnBatch()를 호출하여 프로토콜이 forwarder가 보유한 XEN을 소각하고 forwarder의 소각 사이클 기록과 수수료 업데이트 사이클 기록을 현재 사이클로 업데이트하게 만들 수 있습니다. 그러나 동시에, 프로토콜은 소각된 XEN 금액을 _msgSender()에 해당하는 주소에 기록합니다.

이후 공격자는 claimFees()를 호출하며, 이는 updateStats()를 실행합니다. _msgSender() 주소의 사이클 기록이 한 번도 업데이트되지 않았기 때문에(소각 사이클과 lastFeeUpdateCycle 모두 0으로 유지됨), updateStats()는 현재 사이클의 보상을 계산하고 사이클 0부터 누적된 수수료를 계산합니다 - 프로토콜의 전체 수수료 이력에 걸쳐. 공격자는 claimFees()claimRewards()를 호출하여 수익을 얻습니다.

공격 분석

다음 분석은 트랜잭션 0x914a5a...b808bc37를 기반으로 합니다.

  • 1단계: 공격자는 먼저 Forwarder 컨트랙트의 registerDomainSeparator() 함수를 호출하여 이후 Forwarder.execute() 호출을 가능하게 합니다.

  • 2단계: 공격자는 Uniswap V2 풀에서 0.14e18 ETH13,900,000,000e18 XEN으로 스왑합니다.

  • 3단계: 공격자는 13,900,000,000e18 XENForwarder 컨트랙트에 전송합니다.

  • 4단계: 공격자는 Forwarder.execute()를 사용하여 DBXen이 Forwarder가 보유한 13,900,000,000e18 XEN을 사용하도록 승인합니다.

  • 5단계: 공격자는 Forwarder.execute()를 사용하여 DBXen.burnBatch()를 호출하고 13,900,000,000e18 XEN을 소각합니다. 소각 금액은 주소 0x425D3eC2DCeBE2c04bA1687504D43AFC6be7328d에 기록되고, 소각 실행 중 XENonTokenBurned()를 통해 DBXen으로 콜백하여 Forwarder의 관련 사이클 기록을 업데이트합니다.

  • 6단계: 공격자는 Forwarder.execute()를 사용하여 DBXen.claimFees()를 호출하고 65.36e18 ETH를 획득합니다.

  • 7단계: 공격자는 Forwarder.execute()를 사용하여 DBXen.claimRewards()를 호출하고 2,305.4e18 DXN을 발행합니다.

결론

이 사건의 근본 원인은 DBXen 프로토콜이 _msgSender()msg.sender를 일관성 없이 사용했다는 것입니다. 이 두 값이 다를 수 있기 때문에, 프로토콜의 내부 회계가 일관성을 잃어 공격자가 그 불일치를 악용하여 수익을 얻을 수 있었습니다.

향후 유사한 위험을 줄이기 위해:

  • 모든 로직 경로에서 _msgSender()를 일관되게 사용하거나, msg.sender 의존 작업과 _msgSender() 의존 회계가 항상 동일한 주소를 참조하도록 보장하십시오.

Goose Finance 사건

간략한 요약

2026년 3월 15일, BNB Chain의 이자 농사 프로토콜 Goose Finance가 약 $8K의 익스플로잇을 당했습니다. 근본 원인은 StrategyGooseEgg의 지분 가격 책정 순서 결함입니다: deposit()가 수확된 보상을 회계에 정산하기 전에 지분을 발행하여, 지분 가격 책정에 사용되는 총 자산 분모가 이러한 보상을 제외하여 실제 가치보다 낮아집니다. 이는 예치자가 받아야 할 것보다 더 많은 지분을 받는다는 것을 의미합니다. withdraw()가 호출되면 총 자산을 증가시키는 보상 수확을 트리거하여 각 지분의 가치가 더 높아집니다. 단일 트랜잭션 내에서 예치와 인출을 반복함으로써, 공격자는 반복적으로 과다 평가된 지분을 발행하고 수정된(더 높은) 가치로 상환하여 그 차액을 수익으로 추출했습니다.

배경

Goose Finance는 BNB Chain 이자 농사 프로토콜로, 사용자 자금이 금고에서 전략으로 흘러 들어가 MasterChef에 자산을 스테이킹하여 EGG 보상을 획득합니다.

이 사건과 관련된 구성 요소는 다음과 같습니다:

  • VaultChef (0x3f64...): 사용자 포지션을 추적하고 StrategyGooseEgg에 자본을 전달합니다.

  • StrategyGooseEgg (0x0980...): sharesTotalwantLockedTotal로 전략 수준 회계를 유지합니다.

  • MasterChef (0xe70e...): 스테이킹된 자산을 받고 EGG 보상을 지급합니다.

  • WrappedEgg (0xb815...): EGG를 1:1로 WEGG로 래핑하여 스테이킹합니다.

운영적으로, 예치는 VaultChef에서 StrategyGooseEgg로 라우팅된 후 MasterChef에 스테이킹됩니다. 인출은 VaultChef에서 시작되어 전략에 의해 실행됩니다.

핵심 회계 기대치는 지분 가격이 가격 책정 시점의 총 전략 자산(스테이킹된 원금 및 전략이 이미 보유한 유휴 보상 포함)을 반영해야 한다는 것입니다. 그러나 StrategyGooseEgg에서, deposit()_farm()이 유휴 자산을 wantLockedTotal에 정산하기 전에 지분을 발행하는 반면, withdraw()MasterChef에서 보상 수확을 트리거할 수 있습니다. 이 순서가 아래에서 분석하는 취약점의 기반입니다.

취약점 분석

근본 원인은 보상 수확과 지분 가격 책정 사이의 StrategyGooseEgg(0x0980...b26b)의 회계 비동기화입니다.

StrategyGooseEgg에서 지분 가격 책정은 wantLockedTotal을 분모로 사용합니다: shares = deposit * sharesTotal / wantLockedTotal. 이것이 공정하려면, wantLockedTotal은 전략이 실제로 보유한 모든 자산(컨트랙트에 있는 유휴 EGG 보상 포함)을 반영해야 합니다. 그러나 deposit()_farm()이 유휴 보상을 wantLockedTotal에 정산하기 전에 지분을 발행합니다. 이는 분모가 미계상 보상을 제외하여 실제 총 자산보다 낮아짐을 의미하며, 예치자가 받아야 할 것보다 더 많은 지분을 받게 됩니다.

또한, withdraw()MasterChef.withdraw()를 호출하여 스테이킹된 원금과 미지급 EGG 보상을 전략에 반환합니다. 전략의 회계는 요청된 _wantAmtwantLockedTotal에서 차감하므로, 수확된 보상은 wantLockedTotal에 반영되지 않고 전략의 잔액에 남아 있습니다. 이는 실제 보유 자산과 기록된 wantLockedTotal 사이의 격차를 넓혀, 이후 deposit() 지분 가격 책정을 더욱 부정확하게 만듭니다.

공격 분석

다음 분석은 트랜잭션 0x86efdf...ce316223를 기반으로 합니다.

  • 1단계: 공격자는 두 Pancake 페어에서 EGG를 플래시 차입합니다.

  • 2단계: VaultChef/StrategyGooseEgg에 첫 번째 예치 (10,170,000e18 EGG).

  • 3단계: 첫 번째 인출 (12,593,884e18 EGG)이 MasterChef에서 보상을 수확합니다; 359,561e18 EGGStrategyGooseEgg에 전송되어 유휴/미계상 가치로 남습니다 (R > 0).

  • 4단계: 두 번째 예치는 인출된 자본을 재사용합니다 (12,593,884e18 EGG). 유휴 가치가 정산되기 전에 지분이 가격 책정되므로, 이것이 과다 발행 단계입니다.

  • 5단계: 두 번째 인출 (12,826,027e18 EGG)은 과다 발행된 지분에서 수익을 실현합니다 (즉, 4단계 예치 입력보다 232,143 EGG 초과).

  • 6단계: 공격자는 플래시 스왑을 상환하고 순 스프레드를 보유합니다.

결론

이 익스플로잇은 StrategyGooseEgg의 지분 가격 책정 순서 결함에서 비롯됩니다: deposit()_farm()wantLockedTotal을 업데이트하기 전에 지분을 발행하는 반면, withdraw()MasterChef에서 보상을 수확하여 일시적으로 유휴 및 미계상 상태로 남을 수 있습니다. 이를 통해 예치는 오래된 분모로 발행되고 나중에 업데이트된 자산으로 인출됩니다.

향후 유사한 위험을 줄이기 위해:

  • 지분 발행 및 지분 소각 계산 모두 이전에 보상을 정산하고 회계를 업데이트하십시오.

  • 정확한 계산 시점에 단일 totalAssets(staked + idle)를 기준으로 지분을 가격 책정하십시오.

  • 비零 유휴 보상 조건 하에서 shares_minted <= D * S / (A + R) 에 대한 불변 테스트를 추가하십시오.


BlockSec 소개

BlockSec은 풀스택 블록체인 보안 및 암호화폐 컴플라이언스 제공업체입니다. 저희는 고객이 코드 감사(스마트 컨트랙트, 블록체인 및 지갑 포함), 실시간 공격 차단, 사건 분석, 불법 자금 추적, AML/CFT 의무 이행을 수행할 수 있도록 돕는 제품과 서비스를 구축하며, 프로토콜과 플랫폼의 전체 생명주기에 걸쳐 지원합니다.

BlockSec은 권위 있는 컨퍼런스에서 다수의 블록체인 보안 논문을 발표했으며, DeFi 애플리케이션의 여러 제로데이 공격을 보고하고, 다수의 해킹을 차단하여 2천만 달러 이상을 구출하고, 수십억 달러의 암호화폐를 보호했습니다.

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 회로의 제약 누락으로 공격자가 가짜 머클 트리로 온체인 검증을 통과했습니다.

~$598만 달러 손실: Aztec, Raydium 등 | BlockSec 위클리
Security Insights

~$598만 달러 손실: Aztec, Raydium 등 | BlockSec 위클리

이 주간 블록체인 보안 리포트는 2026년 6월 8일~14일을 다루며, 이더리움과 솔라나에서 발생한 4건의 주요 사고를 분석하고 총 손실액은 약 598만 달러입니다. Aztec Connect의 입력 검증 누락으로 롤업 증명 경로와 L1 정산 불일치가 발생했고, Raydium의 레거시 AMM v3 검증 누락으로 LP 토큰 상환 계산이 조작되어 4개 풀이 탈취됐습니다. 두 취약점 모두 수년간 노출된 상태였습니다. 입력 검증 부재, 정수 오버플로우, 거버넌스 탈취 등의 공격 유형을 다룹니다.