2025년 7월 9일, 탈중앙화 영구 포지션 플랫폼 GMX가 Arbitrum 네트워크의 V1 컨트랙트를 대상으로 한 익스플로잇 [1, 2]을 겪었으며, 약 4,200만 달러의 손실이 발생했습니다. 공격자는 크로스 컨트랙트 재진입 취약점을 악용하여 GLP 가격을 조작한 뒤, 왜곡된 가격을 이용해 GMX V1의 유동성 풀에서 기초 자산을 탈취했습니다.
배경
GMX V1 [3]은 Arbitrum에 배포된 탈중앙화 영구 포지션 거래 플랫폼입니다. 사용자는 허가 없이 비수탁 방식으로 다양한 암호화폐 자산에 대해 레버리지를 사용한 영구 계약을 거래할 수 있습니다. GMX V1은 단일 다중 자산 풀 설계를 따르며, 지원되는 모든 자산의 유동성이 통합된 Vault 시스템에 집계됩니다.
GMX의 포지션 관리
GMX의 포지션 관리는 두 단계로 이루어집니다. 구체적으로, 사용자는 OrderBook 또는 PositionRouter 컨트랙트와 상호작용하여 증가/감소 주문을 생성합니다. 그런 다음 권한이 부여된 키퍼(keeper) 계정이 사용자의 주문을 실행하며, 이 과정에서 ShortTracker 컨트랙트의 글로벌 숏 데이터와 Vault 컨트랙트의 해당 상태가 업데이트됩니다. 아래 두 그림은 GMX에서 포지션을 관리하기 위한 두 가지 실행 경로(orderbook-execution 경로와 router-execution 경로)를 보여줍니다. 이번 사건에서 공격자는 두 경로를 모두 사용하여 글로벌 숏 데이터를 조작하고 수익을 실현했습니다.
Orderbook-execution 경로
Router-execution 경로
GMX Vault
GMX의 Vault 컨트랙트는 사용자의 포지션 및 자산 관리(예: 손익 확정)를 담당합니다. 악의적인 상호작용을 방지하기 위해, Vault 컨트랙트는 "레버리지 창"이 열려 있을 때(즉, Vault 컨트랙트의 변수 isLeverageEnabled가 Timelock.enableLeverage() 함수를 통해 true로 설정된 경우)에만 접근할 수 있습니다. 이 유효성 검사는 주문 실행이 고정된 경로(orderbook-execution 및 router-execution)를 따르도록 강제합니다.
GMX Short Tracker
ShortTracker 컨트랙트는 주문 실행 중 글로벌 숏 데이터(예: 변수 globalShortAveragePrice)를 추적하고 업데이트하는 역할을 합니다. orderbook-execution 및 router-execution 경로에 따라, ShortTracker 컨트랙트의 updateGlobalShortData() 함수는 최신 글로벌 숏 데이터를 동기화하기 위해 사용자 주문 실행 전에 호출됩니다. 이 단계는 사용자 포지션에 대한 올바른 손익 실현을 보장합니다.
WETH 포지션 감소
다른 주문과 달리, orderbook-execution 경로를 통해 WETH 포지션을 감소시키면 OrderBook 컨트랙트의 _transferOutETH() 함수가 호출되어 WETH 토큰을 인출하고 네이티브 ETH 토큰을 사용자에게 전송합니다. 수신자 _receiver가 컨트랙트인 경우, sendValue()가 컨트랙트의 fallback() 함수를 트리거하여 잠재적인 재진입 취약점을 유발할 수 있습니다. 이번 사건에서 공격자는 이 재진입 취약점을 반복적으로 악용하여 상당한 수익을 탈취했습니다.
GLP 토큰
GLP(GMX Liquidity Provider) 토큰은 Vault 컨트랙트 내 다양한 자산에 대한 통합 지분을 나타냅니다. 사용자는 GLP를 민팅하고 소각함으로써 자산을 제공하고 환매할 수 있습니다.
GLP 가격은 다음 방정식으로 계산할 수 있습니다:
여기서:
GLPTotalSupply는 GLP 토큰의 총 공급량을 나타냅니다.AUM은 다음 두 가지 구성 요소로 이루어집니다.- 는 모든 숏 포지션의 미실현 손익(uPnL)을 나타냅니다.
- 는 LP가 제공한 유동성과 모든 롱 포지션의 미실현 uPnL을 나타냅니다. 이 항목은 수익 실현 이전 사건 전반에 걸쳐 거의 변하지 않았습니다.
AssetMarketPrice는 기초 자산의 시장 가격(USD 기준)입니다.globalShortSize는 모든 숏 포지션의 합계(USD 기준)입니다.globalShortAveragePrice는 집계된 글로벌 숏 포지션의 평균 진입 가격입니다.
이번 사건에서 공격자는 globalShortAveragePrice를 왜곡하여 GLP 가격을 조작하고 수익을 탈취했습니다.
취약점 분석
근본 원인은 OrderBook 컨트랙트의 크로스 컨트랙트 재진입 취약점입니다. 배경에서 설명한 것처럼, orderbook-execution 경로를 통해 WETH 포지션을 감소시키면 _transferOutETH()를 통해 수신자에게 저수준 폴백 호출이 트리거됩니다. 이 함수에는 nonReentrant 수정자가 적용되어 있지만, 이 가드는 OrderBook 컨트랙트 내의 재진입만 방지할 뿐 Vault에 대한 크로스 컨트랙트 호출은 방지하지 못합니다.
정상적인 운영 하에서, Vault의 increasePosition()은 PositionRouter와 PositionManager를 통해서만 호출될 수 있으며, 이들은 각 포지션 변경 전에 ShortTracker를 호출하여 globalShortAveragePrice를 업데이트합니다. 공격자는 악의적인 컨트랙트를 수신자로 지정한 주문을 생성했고, 폴백 호출 중에 PositionRouter/PositionManager 및 관련 ShortTracker 업데이트를 우회하여 Vault의 increasePosition()을 직접 호출했습니다. 공격자는 globalShortAveragePrice를 업데이트하지 않은 채 숏 포지션을 반복적으로 열고 닫음으로써 해당 변수를 점진적으로 왜곡했습니다. 왜곡된 값은 GLP 가격을 부풀렸고, 공격자는 GLP를 민팅하고 환매하여 수익을 탈취할 수 있었습니다.
공격 분석
공격자는 글로벌 숏 데이터를 조작하고 수익을 실현하는 일련의 트랜잭션을 실행했습니다. 구체적으로, 이번 사건은 세 단계로 나눌 수 있습니다: 준비, 가격 조작, 수익 실현. 관련된 모든 트랜잭션은 아래 표에 나열되어 있습니다.
| Tx 번호 | 단계 | 설명 | 트랜잭션 | 시간 (UTC) |
|---|---|---|---|---|
| 1 | 준비 | 공격 컨트랙트 배포 | 0xa4ece5...8cd4c93f | Jul-09-2025 12:16:32 PM |
| 2 | WETH 롱 증가 주문 생성 | 0x0b8cd6...e90a4712 | Jul-09-2025 12:22:28 PM | |
| 3 | WETH 롱 증가 주문 실행 | 0x28a000...7bf0beef | Jul-09-2025 12:23:23 PM | |
| 4 | WETH 롱 감소 주문 생성 | 0x20abfe...decc49af | Jul-09-2025 12:24:56 PM | |
| 5 | 가격 조작 1 | WETH 롱 감소 주문 실행 | 0x1f00da...6a4a7353 | Jul-09-2025 12:25:37 PM |
| 6 | WBTC 숏 감소 주문 실행 | 0x222cda…c994464e | Jul-09-2025 12:25:43 PM | |
| 7 | 가격 조작 2 | Tx 5와 동일 | 0xc9a469...221293c2 | Jul-09-2025 12:26:25 PM |
| 8 | Tx 6과 동일 | 0x1cbf25...d853943a | Jul-09-2025 12:26:30 PM | |
| 9 | 가격 조작 3 | Tx 5와 동일 | 0xb58415...3b4cfb0b | Jul-09-2025 12:27:22 PM |
| 10 | Tx 6과 동일 | 0x5a37ff...cb59c3b7 | Jul-09-2025 12:27:28 PM | |
| 11 | 가격 조작 4 | Tx 5와 동일 | 0xff6fe6...377bf108 | Jul-09-2025 12:28:13 PM |
| 12 | Tx 6과 동일 | 0xbd65d6...e0187be6 | Jul-09-2025 12:28:18 PM | |
| 13 | 가격 조작 5 | Tx 5와 동일 | 0x105273...19fcdec6 | Jul-09-2025 12:29:12 PM |
| 14 | Tx 6과 동일 | 0x0cdbac...84339fcc | Jul-09-2025 12:29:17 PM | |
| 15 | 수익 실현 | 수익 실현 | 0x03182d....a32626ef | Jul-09-2025 12:30:11 PM |
| 16 | 환불 | 공격자에게 메시지 전송 | 0x92a39e...89547380 | Jul-09-2025 02:04:19 PM |
| 17 | GMX 프로토콜에 응답 | 0x1d806c...919feac0 | Jul-11-2025 06:29:00 AM | |
| 18 | 공격자에게 응답 | 0x9c4ca9...39fa27fc | Jul-11-2025 07:42:17 AM | |
| 19 | 환불 | 0x62b845...99211841 | Jul-11-2025 08:04:34 AM | |
| 20 | 환불 | 0x255d0a...9321b3 | Jul-11-2025 08:08:27 AM | |
| 21 | 환불 | 0xceafc3...a6313b22 | Jul-11-2025 10:17:23 AM |
준비 단계
-
(Tx 1) 공격자는 주문 실행 중 자산 수신자로 사용될 공격 컨트랙트를 배포했습니다. 공격 컨트랙트에는 악의적인
fallback()함수가 포함되어 있었습니다. -
(Tx 2) 공격자는
OrderBook컨트랙트에서 공격 컨트랙트를 위한 WETH 롱 증가 주문을 생성했습니다.
-
(Tx 3) 키퍼가 공격자의 증가 주문(2단계에서 생성)을 실행하여 공격 컨트랙트를 위한 WETH 롱 포지션을 개설했습니다. (Tx 3).
-
(Tx 4) 공격자는
OrderBook컨트랙트에서 공격 컨트랙트를 위한 WETH 롱 감소 주문을 생성했습니다.
조작 단계
-
(Tx 5) 키퍼가 orderbook-execution 경로를 통해 공격 컨트랙트의 WETH 롱 감소 주문(4단계에서 생성)을 실행했습니다. 실행 경로는
_transferOutETH()를 호출하여 공격 컨트랙트의 악의적인fallback()함수를 트리거했습니다.fallback()이 "레버리지 창"이 열린 동안 호출되었기 때문에, 공격 컨트랙트는globalShortAveragePrice를 업데이트하지 않고Vault컨트랙트와 직접 상호작용하여 WBTC 숏 포지션을 개설했으며(increasePosition()호출), 이후 WBTC 숏 감소/종료 주문을 생성했습니다.
-
(Tx 6) 키퍼가 router-execution 경로를 통해 WBTC 숏 감소 주문(5단계에서 생성)을 실행했습니다. 이 실행은 또한
PositionRouter컨트랙트의 폴백 메커니즘을 통해 WETH 롱 감소 주문을 생성했습니다.WBTC 숏 포지션이
globalShortAveragePrice를 업데이트하지 않고 개설되었기 때문에, 해당 변수를 업데이트하면서 포지션을 종료하면globalShortAveragePrice가 예기치 않게 하락했습니다.
-
(Tx 7-14) 공격자는 5-6단계를 4회 반복했습니다. 그 결과,
globalShortAveragePrice는 1.08e35에서 1.9e33으로 왜곡되었습니다.
수익 실현 단계
-
(Tx 15) 키퍼가 orderbook-execution 경로를 통해 WETH 롱 감소 주문(Tx 14에서 생성)을 실행했습니다. 이 실행은
OrderBook컨트랙트의 재진입 취약점으로 인해 공격 컨트랙트의 수익 실현 로직을 트리거했습니다.
-
폴백 호출에서 공격 컨트랙트는 먼저 7,538,567e18 USDC의 플래시 론을 빌렸습니다.
-
공격 컨트랙트는
mintAndStakeGlp()를 호출하여 6,000,000e18 USDC를 사용해 4,129,578e18 GLP를 민팅했습니다. -
공격 컨트랙트는
Vault.increasePosition()을 호출하여 나머지 1,538,567e18 USDC로 WBTC 숏 포지션을 개설했습니다. WBTC의 글로벌 숏 데이터가 극도로 왜곡되어 있었기 때문에, 주문 실행 시 AUM이 크게 증폭되어 GLP 가격이 급격히 상승했습니다. -
공격 컨트랙트는
unstakeAndRedeemGlp()를 호출하여 증폭된 가격으로 GLP를 환매하여Vault컨트랙트의 여러 자산을 획득했습니다. -
공격 컨트랙트는
Vault.decreasePosition()을 호출하여 WBTC 숏 포지션을 종료했습니다. -
공격 컨트랙트는 8.b-8.e 단계를 4회 반복하여
Vault컨트랙트의 모든 자산을 고갈시켰습니다. -
공격 컨트랙트는 약 4,200만 달러의 수익을 남기고 플래시 론을 상환했습니다.
-
환불
공격자와의 협상(Tx 16-18)을 통해, 공격자는 최종적으로 10% 바운티를 수락하고 나머지 탈취한 자산을 반환했습니다(Tx 19-21).
요약
이번 사건은 Arbitrum의 GMX V1을 대상으로 한 다단계 익스플로잇으로, 약 4,200만 달러의 손실이 발생한 것으로 추정됩니다. 공격자는 OrderBook 컨트랙트의 재진입 취약점을 악용하여 globalShortAveragePrice 변수를 왜곡하고 GLP 가격을 부풀렸습니다. 조작된 가격을 활용하여 공격자는 상당한 양의 자산을 탈취했습니다.
주요 교훈:
- 크로스 컨트랙트 재진입: 단일 컨트랙트의
nonReentrant수정자는 동일 시스템 내 다른 컨트랙트로의 재진입을 방지하지 못합니다. 임시 플래그(예: "레버리지 창")에 의존하는 접근 제어 메커니즘은 플래그가 재설정되기 전에 외부 호출이 발생할 경우 우회될 수 있습니다. - 운영 보안: 이번 공격자는 총 15개의 트랜잭션을 실행하여 세 가지 뚜렷한 단계로 프로토콜을 익스플로잇했습니다. 이번 사건은 실시간 모니터링, 신속한 경보 및 효과적인 완화 플레이북의 중요성을 강조합니다.
참고 자료
- https://x.com/GMX_IO/status/1942955807756165574
- https://x.com/GMX_IO/status/1943336664102756471
- GMX V1
BlockSec 소개
BlockSec은 풀스택 블록체인 보안 및 암호화폐 컴플라이언스 제공업체입니다. 저희는 고객이 코드 감사(스마트 컨트랙트, 블록체인 및 지갑 포함), 실시간 공격 차단, 사건 분석, 불법 자금 추적, AML/CFT 의무 이행을 프로토콜 및 플랫폼의 전체 생애주기에 걸쳐 수행할 수 있도록 지원하는 제품과 서비스를 구축합니다.
BlockSec은 권위 있는 학술 컨퍼런스에 다수의 블록체인 보안 논문을 발표했으며, DeFi 애플리케이션의 여러 제로데이 공격을 보고했고, 2,000만 달러 이상을 구제하는 복수의 해킹을 차단했으며, 수십억 달러 규모의 암호화폐를 보호했습니다.
-
공식 웹사이트: https://blocksec.com/
-
공식 트위터 계정: https://twitter.com/BlockSecTeam
-
🔗 BlockSec 감사 서비스 : 요청 제출



