Back to Blog

~$88M 손실: COLDCARD 및 LULA 익스플로잇 | BlockSec 위클리

Code Auditing
August 5, 2026
8 min read
Key Insights

지난 한 주(2026/07/27 - 2026/08/02) 동안 주목할 만한 보안 사고 2건이 발생했으며, 총 손실액은 약 $88M에 달합니다.

날짜 사고 유형 추정 손실
2026/07/29 LULA 비즈니스 로직 결함 ~$578K
2026/07/30 COLDCARD 결함 있는 엔트로피 생성 ~1,370 BTC (~$88M)*

* COLDCARD의 손실은 확인 방법에 따라 다릅니다: 표시된 ~1,370 BTC (~$88M)는 공개적으로 검증 가능한 온체인 최솟값(coldcardwatch.com)이며, 비공개 채널 대조(Galaxy Research, 73명의 피해자와의 서신)에서는 더 높은 수치인 약 1,596 BTC, 그리고 의심되지만 미확인된 인출을 포함하면 최대 ~2,055 BTC (~$130M)로 집계됩니다.

선정 이유

  • LULA: AMM 페어의 잔액을 이동시키고 강제로 리저브를 재동기화할 수 있는 권한 있는 토큰 함수가 가격 조작을 통해 반복 가능한 유동성 탈취 수단이 됩니다.
  • COLDCARD: 지갑 펌웨어의 빌드 및 통합 오류로 인해 시드 생성이 결정론적 소프트웨어 폴백을 통해 조용히 이루어졌으며, 이는 엔트로피 보장을 훼손하고 시드 복구를 오프라인 탐색으로 전환시켜 대규모 자금 손실로 이어졌습니다.

Web3 최고의 보안 감사 기관

출시 전 설계, 코드, 비즈니스 로직을 검증하세요

주간 하이라이트: COLDCARD

이번 주 하이라이트로 COLDCARD를 선정한 이유는 지갑 엔트로피 버그가 해당 기간 최대 손실을 야기했기 때문입니다. 근본 원인인 설정 매크로의 존재 여부만 확인하고 활성화 여부는 확인하지 않은 빌드 가드는 기능 테스트로는 발견할 수 없는 종류의 조용한 통합 오류이며, 이 교훈은 온체인 보안이 오프체인 무작위성에 의존하는 모든 시스템에 적용됩니다.

비트코인 하드웨어 지갑인 COLDCARD는 2021년에 의도된 하드웨어 난수 생성기(RNG) 대신 결정론적 소프트웨어 소스를 사용하여 지갑 시드를 생성하는 펌웨어를 출시했습니다 [1][2]. 이 결함은 2026년 7월 말까지 대규모로 악용되지 않았으나, 7월 30일부터 시작된 온체인 파동으로 영향받은 지갑들이 일괄 인출되었습니다: 공개적으로 확인된 손실은 최소 1,370 BTC (~$88M, 8월 5일 $64,099 가격 기준) [3]에 달하며, 비공개 확인 보고서에서는 약 1,596 BTC까지 추산됩니다 [4]. 근본 원인은 시드 생성을 의도된 하드웨어 RNG 대신 소프트웨어 폴백으로 라우팅한 빌드 및 설정 오류였습니다. 영향받은 기기에서 이는 시드 복구를 암호학적으로 불가능한 문제에서 오프라인 탐색으로 전환시켰습니다.

배경

COLDCARD는 비트코인 하드웨어 지갑입니다. 지갑의 개인 키와 주소는 모두 단일 비밀 값인 시드에서 파생되므로, 자기 수탁 지갑의 보안은 해당 시드의 두 가지 속성에 달려 있습니다: 시드가 비밀로 유지되는 것과 생성 시 예측 불가능한 것입니다. 하드웨어 지갑은 주로 첫 번째 속성을 보호하기 위해 존재하지만, 이번 사고는 두 번째 속성의 실패입니다. BIP-39 시드 구문은 인간이 읽을 수 있지만, 예측 불가능성 요건 아래의 보안 속성은 여전히 시드 생성에 사용된 무작위 바이트의 엔트로피입니다. 이 바이트들이 재현될 수 있다면 시드도 재현될 수 있습니다. 직관적으로는 주사위를 굴려 조합을 선택하는 금고와 같습니다: 주사위가 편향되어 있다면, 자물쇠가 아무리 강해도 편향을 아는 누구에게나 금고는 열려 있습니다.

지갑에서 "편향된 주사위"는 약한 난수 생성기를 의미합니다. 하드웨어 지갑은 보안 마이크로컨트롤러의 하드웨어 진정난수생성기(TRNG)에서 시드 엔트로피를 끌어오도록 기대되는데, 소프트웨어 의사난수생성기(PRNG)는 결정론적이기 때문입니다: 내부 상태와 호출 이력이 주어지면 출력을 정확히 재현할 수 있습니다. 생성기의 출력이 예측 가능하다면, 후보 범위를 열거하여 주소, xpub, 공개 키와 같은 공개 지갑 데이터와 대조할 수 있으며, 이는 시드 복구를 암호학적으로 불가능한 문제에서 오프라인 탐색으로 전환시킵니다.

COLDCARD의 펌웨어는 두 개의 별개 RNG 인터페이스를 노출했습니다. MicroPython은 지갑의 암호화 라이브러리가 기대하는 전역 rng_get() 심볼을 노출하는 STM32 플랫폼 레이어를 탑재했으며, COLDCARD는 자체 보드 로컬 하드웨어 RNG 래퍼도 유지했습니다. 두 인터페이스 모두 하드웨어 엔트로피를 공급하도록 의도되었으며, 지갑의 암호화 라이브러리는 펌웨어 빌드 시 해석되는 단일 전역 RNG 심볼을 통해 둘 중 하나에 접근합니다.

취약점 분석

근본 원인은 MICROPY_HW_ENABLE_RNG 설정 매크로와 관련된 빌드 및 통합 오류였습니다. COLDCARD의 프로덕션 보드 설정은 이 매크로를 0으로 설정했는데, 펌웨어가 MicroPython의 하드웨어 RNG 구현 대신 자체 보드 로컬 하드웨어 RNG 래퍼를 사용하려 했기 때문입니다. 그러나 지갑 생성 경로는 ngu.random.bytes(32)로 마이그레이션되었고, 암호화 라이브러리의 STM32 경로는 궁극적으로 MicroPython이 해석하는 전역 rng_get() 심볼에 의존했습니다.

문제 체인은 다음과 같았습니다:

generate_seed()
  -> ngu.random.bytes(32)
  -> libngu CHIP_TRNG_32()
  -> rng_get()
  -> MicroPython STM32 RNG 모듈
  -> MICROPY_HW_ENABLE_RNG == 0이므로 Yasmarang 소프트웨어 폴백

보드 설정은 MicroPython의 하드웨어 RNG 분기를 비활성화했습니다:

// 이 코드의 자체 버전이 있습니다.
#define MICROPY_HW_ENABLE_RNG (0)

암호화 라이브러리는 여전히 매크로를 하드웨어 RNG의 충분한 증거로 취급했는데 [5], rng_get()을 호출하기 전에 매크로의 존재 여부만 확인했기 때문입니다:

extern uint32_t rng_get(void);
#define CHIP_TRNG_32() rng_get()

#ifndef MICROPY_HW_ENABLE_RNG
#error "get a HW TRNG plz"
#endif

이 가드는 위험한 경우를 놓칩니다: 0으로 정의된 매크로는 여전히 정의된 것이므로 #ifndef 검사를 통과하고 빌드가 성공합니다. MicroPython은 매크로의 존재 여부가 아닌 값에 따라 RNG 구현을 선택하므로, MICROPY_HW_ENABLE_RNG == 0은 COLDCARD의 보드 로컬 래퍼 대신 소프트웨어 폴백 분기로 rng_get()을 라우팅했습니다 [6]:

#if MICROPY_HW_ENABLE_RNG
    // STM32 하드웨어 RNG
#else
    // Yasmarang 소프트웨어 폴백
#endif

결과는 기기 세대에 따라 다릅니다. Mk2/Mk3 펌웨어 v4.0.0-v4.1.9의 경우, Block의 분석 [7]에 따르면 ngu.random에 암호화 엔트로피가 추가되지 않아, 폴백 상태와 호출 이력이 알려지면 지갑 생성이 결정론적이 될 수 있습니다(Coinkite의 권고 [2]는 Mk2/Mk3 범위를 v4.0.1-v4.1.9로 약간 더 좁게 한정합니다). Mk4/Q/Mk5의 경우, 보안 요소 자료가 해싱되었지만 ngu.random.reseed()에는 4바이트만 전달되어, 보안 리시드를 단일 32비트 상태 워드로 제한하여 사용자가 기대하는 지갑 엔트로피보다 훨씬 적은 탐색 공간을 갖습니다. 최종 32개의 무작위 바이트를 해싱해도 결과의 엔트로피를 높일 수 없으며, 이미 제한된 후보 집합을 변환할 뿐입니다.

공격 분석

스마트 컨트랙트 익스플로잇과 달리, 이번 사고에는 추적할 단일 온체인 공격 트랜잭션이 없습니다. 이는 온체인 일괄 인출이 뒤따른 오프라인 시드 복구 문제였습니다. 전제 조건은 영향받은 사용자들이 취약한 ngu.random.bytes(32) 경로를 통해 지갑 시드를 생성하여, 시드 자료가 완전한 하드웨어 엔트로피가 아닌 재현 가능한 소프트웨어 폴백 상태에 의존했다는 것입니다. 두 번째 추론된 전제 조건은 영향받은 지갑이 시드만으로 파생 가능했다는 점입니다: 강력하고 고유한 BIP-39 패스프레이즈는 RNG 결함이 건드리지 않은 독립적인 사용자 제공 엔트로피를 PBKDF2를 통해 혼합하여 순수 시드 열거 범위 밖에 놓이며, 일괄 인출의 규모로 볼 때 대부분의 영향받은 사용자들은 패스프레이즈를 설정하지 않은 것으로 보입니다. 이후 복구는 세 단계로 진행된 것으로 추정됩니다:

  1. 공격자는 기기 메타데이터, 부팅 타이밍, RTC/SysTick 가정, 가능성 있는 RNG 호출 이력을 사용하여 후보 RNG 상태를 제한하거나 열거했습니다.
  2. 각 후보 상태에 대해 공격자는 후보 지갑 시드를 파생하고 주소, xpub, 생성된 공개 키와 같은 공개 지갑 데이터와 오프라인으로 대조했습니다.
  3. 후보가 실제 지갑과 일치하면 공격자는 시드를 복구하고, 개인 키를 재구성하여 관련 BTC를 인출했습니다.

온체인에서 도난은 7월 30일부터 시작된 주소 일괄 인출 폭발로 나타났습니다. 독립적인 온체인 휴리스틱 추적 [3]은 4,580개의 검증된 주소에서 인출된 총 최소 1,370 BTC (약 $88M, 8월 5일 BTC 가격 $64,099 기준)를 합산한 여러 인출 파동을 식별하며, 이는 합계가 아닌 검증된 최솟값입니다. 한편 73명의 피해자와의 서신을 통해 확인된 비공개 채널 [4]에서는 약 1,596 BTC, 의심되지만 미확인된 인출을 더하면 2,055 BTC (~$130M)에 달하는 것으로 추산합니다.

결론

COLDCARD 사고는 엔트로피 생성 실패였습니다: 보안에 중요한 시드 생성 API가 빌드 가드가 설정 매크로의 존재 여부만 확인하고 활성화 여부는 확인하지 않아, 의도된 하드웨어 RNG 대신 결정론적 소프트웨어 PRNG 폴백으로 조용히 해석되었습니다. 영향받은 기기에서 이는 시드 복구를 암호학적으로 불가능한 문제에서 오프라인 탐색으로 전환시켰으며, 결과적으로 1,370 BTC 이상이 [3] 여러 파동에 걸쳐 인출되었습니다(비공개 채널 집계에서는 약 1,596~2,055 BTC로 추산 [4]).

핵심 엔지니어링 실패는 출시된 펌웨어가 보안에 가장 중요한 API가 실제로 의도된 하드웨어 RNG에 도달하는지 결코 증명하지 않았다는 것입니다. 세 가지 방법으로 이를 발견할 수 있었습니다: 암호화 엔트로피를 위한 빌드 가드는 매크로 존재 여부와 매크로 값 모두를 확인해야 하며; 엔트로피 폴백은 소프트웨어 PRNG를 조용히 대체하는 대신 안전하게 실패해야 하고; 최종 펌웨어 이미지의 검증은 코드 컴파일 여부뿐 아니라 심볼 출처와 엔드투엔드 엔트로피 흐름을 포함해야 합니다. 영향받은 시드는 그 자리에서 수정할 수 없으므로, 해당 자금을 수정된 펌웨어에서 생성된 지갑으로 이동해야 하며, 강력하고 고유한 패스프레이즈는 시드를 수리하지 않고도 즉각적인 노출을 줄입니다 [2].

이 실패 모드는 강조할 가치가 있습니다: 이런 종류의 무작위성 버그는 생성된 모든 시드가 개별적으로 유효하기 때문에 기능 테스트에서는 보이지 않습니다. 결함은 단일 출력에 있는 것이 아니라 그것을 생성한 소스에 있습니다: 해당 소스가 예측 가능하고 재현 가능하기 때문에, 시드들은 집합적으로 작고 열거 가능한 범위에 속합니다. 오프체인 키 생성 컴포넌트는 최우선적인 보안 검토를 받아야 합니다.

참고 자료

Phalcon Explorer 시작하기

트랜잭션을 심층 분석하여 현명하게 행동하세요

지금 무료로 사용해보기

이번 주 추가 사고

LULA

BNB Chain의 BEP-20 토큰인 LULA는 2026년 7월 29일 토큰 컨트랙트의 비즈니스 로직 결함으로 약 $578K의 손실을 입었습니다. 공격자가 접근 가능한 경로가 권한 있는 recycle() 함수를 트리거할 수 있어, Rental 컨트랙트가 PancakeSwap V2 페어에서 직접 LULA를 전송한 후 sync()를 호출하여 조작된 잔액으로 페어의 리저브를 업데이트할 수 있었습니다. 공격자는 반복적으로 recycle()을 트리거하여 페어의 LULA 리저브를 거의 0에 가깝게 축소시킨 후, 소량의 LULA를 거의 모든 USDT와 교환했습니다 [1].

배경

LULA는 렌탈 기반 팀 보상 메커니즘을 가진 BNB Chain의 BEP-20 토큰입니다. 자격 있는 주소는 Rental 컨트랙트에서 대기 중인 팀 보상을 누적하고 claimTeamReward()를 통해 청구합니다. 청구 흐름 중, Rental 컨트랙트는 보상 분배를 위해 LULA를 얻기 위해 토큰의 recycle() 함수를 호출합니다. recycle()은 임의의 사용자가 호출할 수 없으며, Rental 컨트랙트만 실행 권한이 있습니다.

claimTeamReward() 진입점에는 "EOA 전용" 검사가 포함되어 있습니다. 이는 msg.sender == tx.origin인 외부 소유 계정의 직접 호출을 지원하며, 위임된 코드 접두사를 검사하여 EIP-7702 위임 호출도 지원합니다.

자동화 시장 메이커(AMM)에서 페어는 저장된 리저브로부터 스왑 가격을 산정하며, 해당 리저브는 페어의 현재 토큰 잔액으로 설정하는 sync() 함수를 통해 업데이트됩니다. 리저브는 스왑 및 유동성 이벤트와 함께 움직이기 때문에 일반적으로 실제 거래를 추적하지만, 페어의 토큰 잔액은 직접 전송으로도 변경될 수 있으며, sync()는 조작되었든 아니든 현재 존재하는 잔액을 저장된 리저브로 복사합니다.

취약점 분석

근본 원인은 LULA.recycle()이 Rental 컨트랙트가 PancakeSwap V2 페어에서 직접 LULA를 전송한 후 sync()를 호출하여 조작된 잔액으로 페어의 리저브를 업데이트할 수 있도록 허용한다는 점입니다 [1].

sync()가 페어에 남아 있는 LULA 잔액으로 리저브를 설정하기 때문에, 이 권한 있는 경로는 USDT 측을 그대로 두면서 페어의 LULA 리저브를 임의로 낮출 수 있습니다. LULA 리저브가 0에 가까워지면, 페어는 소량의 LULA를 거의 모든 USDT의 가치로 산정합니다.

공격 분석

다음 분석은 트랜잭션 0xa219ab9...411d7c를 기반으로 합니다.

  • 1단계: 공격자는 Moolah/Lista, Aave V3, Venus, PancakeSwap V3, PancakeSwap Vault, Uniswap V4 PoolManager, Uniswap V3 등 여러 플래시론 및 차입 소스에서 약 $197.05M USDT를 축적하여 조작을 위한 자금을 마련했습니다.
  • 2단계: 공격자는 ~197.05M USDT를 사용하여 PancakeSwap V2 라우터를 통해 USDT -> LULA 대규모 스왑을 수행했습니다. 이로 인해 페어의 LULA 리저브가 약 800만 LULA에서 24,022 LULA로 급격히 감소하고, USDT 측은 약 $197.64M USDT로 증가했습니다.
  • 3단계: 공격자는 여러 EIP-7702 지갑을 통해 보상 경로를 호출했습니다. 각 지갑은 Rental 컨트랙트에서 claimTeamReward()를 호출했으며, 이는 LULA.recycle()을 트리거하여 페어의 LULA 리저브를 24,022 LULA에서 0.004 LULA로 축소시키면서 페어는 여전히 매우 큰 USDT 측을 보유했습니다.
  • 4단계: 공격자는 라우터를 통해 최종 PancakeSwap V2 스왑을 실행하여 페어에 ~4,749 LULA만 보내고 ~197.64M USDT를 받았습니다.
  • 5단계: 공격자는 모든 플래시론을 상환하고 약 $578K의 수익을 얻었습니다.

결론

BNB Chain의 LULA 토큰은 토큰 컨트랙트의 비즈니스 로직 결함으로 약 $578K를 손실했습니다: 공격자가 접근 가능한 경로가 권한 있는 recycle() 함수를 트리거할 수 있어, Rental 컨트랙트가 PancakeSwap V2 페어에서 직접 LULA를 전송한 후 sync()를 호출하여 페어의 리저브를 조작된 잔액으로 재동기화할 수 있었습니다. 공격자는 이를 반복적으로 트리거하여 페어의 가격을 왜곡하고 소량의 LULA를 거의 모든 USDT와 교환했습니다.

토큰 컨트랙트는 AMM 페어의 잔액을 이동시키고 강제로 리저브를 재동기화할 수 있는 권한 있는 경로를 노출해서는 안 됩니다. 그 경로에 접근할 수 있는 누구에게나 가격 통제권을 넘겨주기 때문입니다. AMM 페어와 통합되는 토큰은 페어의 리저브를 실제 시장 주도의 잔액 변화에 한정해야 하며, 가격 산정을 위해 풀 리저브를 읽는 모든 로직은 리저브를 권위 있는 것이 아닌 조작 가능한 것으로 취급해야 합니다.

참고 자료

Sign up for the latest updates
뉴스레터 - 2026년 7월
Security Insights

뉴스레터 - 2026년 7월

2026년 7월 DeFi 3대 사고로 Arbitrum·Solana에서 약 6,790만 달러 손실 발생. AFX Trade는 공급망 공격으로 검증자 서명 권한이 탈취되어 약 2,415만 달러 손실. Ostium OLP 볼트는 오라클 인프라 침해로 약 2,375만 달러 유출. BonkDAO는 공격자가 440만 달러로 의결권 확보 후 악의적 자금 이전을 통과시켜 약 2,000만 달러 손실. 세 사고 모두 프로토콜 보안 범위가 스마트 컨트랙트 코드를 훨씬 초월함을 보여준다.

~$3950만 달러 손실: Allbridge, Wanchain 외 다수 | BlockSec 위클리
Security Audits

~$3950만 달러 손실: Allbridge, Wanchain 외 다수 | BlockSec 위클리

2026년 7월 20~26일 한 주간, 솔라나·이더리움·BNB체인·아비트럼·질리카·카르다노에서 8건의 주요 보안 사고로 약 3,950만 달러의 피해가 발생했다. 주요 사례인 Allbridge Core(~165만 달러)는 동일한 Pool 계정이 두 스왑 역할 모두에 허용된 솔라나 입력 검증 취약점이며, 배포된 바이너리만으로 분석됐다. 기타 사례로는 Wanchain(~50만 달러), Zilliqa(~40만 달러), Lien Finance(~54만 달러)가 있다.

~$135만 달러 손실: BarnBridge, DeFiTuna | BlockSec 주간 보고
Security Insights

~$135만 달러 손실: BarnBridge, DeFiTuna | BlockSec 주간 보고

이 주간 보고서는 2026년 7월 13일부터 19일까지 발생한 2건의 보안 사고를 다루며, 이더리움과 솔라나에서 총 약 135만 달러의 손실이 발생했습니다. 솔라나 대출 프로토콜 DeFiTuna은 포지션 가치가 0일 때 부채와 무관하게 건전한 것으로 처리되는 결함으로 약 57만 달러를 잃었습니다. BarnBridge는 더 이상 사용되지 않지만 활성 상태인 이더리움 거버넌스 시스템을 악용한 공격자가 악의적인 제안을 통과시켜 약 77만 6천 달러의 USDC를 탈취당했습니다.

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit