Back to Blog

#10: ThirdWeb 사고: 신뢰할 수 있는 모듈 간의 비호환성으로 인한 취약점 노출

Code AuditingPhalcon Security
February 22, 2024
6 min read
Key Insights
  • Thirdweb는 사전 구축된 ERC-20/721/1155 컨트랙트의 심각한 취약점을 공개했으며(2023년 12월 5일), 이는 공개 이후 실제로 악용되었습니다.

  • 근본 원인: ERC-2771 메타 트랜잭션 컨텍스트와 OpenZeppelin의 MulticallUpgradeable 간의 비호환성—multic

2023년 12월 5일, 저명한 Web3 개발 플랫폼인 Thirdweb은 사전 구축된 컨트랙트에 영향을 미치는 중대한 스마트 컨트랙트 보안 취약점을 공개했습니다. 이 치명적인 결함은 해당 취약한 컨트랙트를 사용하여 배포된 모든 ERC-20, ERC-721, ERC-1155 토큰에 영향을 미쳤습니다. 공개 이후 며칠 동안, 취약한 컨트랙트로 배포된 토큰들은 일련의 공격을 통해 점진적으로 악용되었으며, 이는 근본적인 비호환성의 심각성을 여실히 보여주었습니다.

ThirdWeb 스마트 컨트랙트 취약점 이해하기

ThirdWeb 사건의 근본 원인은 스마트 컨트랙트 개발의 두 가지 핵심 구성 요소인 ERC-2771과 OpenZeppelin의 Multicall 구현 간의 예기치 못한 상호작용에 있습니다. 취약점을 완전히 이해하려면 각 구성 요소를 개별적으로 파악한 후, 그 상호작용이 어떻게 악용 가능한 경로를 만들어냈는지 이해하는 것이 필수적입니다.

ERC-2771: 메타 트랜잭션과 신뢰할 수 있는 포워더

EIP-2771Recipient 컨트랙트가 신뢰할 수 있는 Forwarder 컨트랙트를 통해 메타 트랜잭션을 수락할 수 있도록 하는 컨트랙트 수준의 프로토콜을 정의합니다. 이 표준은 제3자(포워더)가 사용자를 대신해 가스 수수료를 지불할 수 있게 함으로써 사용자 경험을 개선하고, 사용자가 네이티브 블록체인 토큰을 보유해야 하는 필요성을 추상화하는 데 있어 중요한 역할을 합니다.

실제로 OpenZeppelin의 ERC2771Context는 널리 채택된 구현체입니다. 핵심 기능은 신뢰할 수 있는 포워더로부터 수신된 calldata의 마지막 20바이트를 유효한 _msgSender()로 처리하는 것입니다. 이 라이브러리를 사용하는 개발자들의 일반적인 관행은 메타 트랜잭션과의 호환성을 보장하기 위해 msg.sender를 직접 사용하는 모든 경우를 _msgSender()로 대체하는 것입니다. 마찬가지로, _msgData()는 추가된 발신자 정보를 제외한 원본 트랜잭션 데이터를 검색하는 데 사용됩니다.

function _msgSender() internal view virtual override returns (address) {
    uint256 calldataLength = msg.data.length;
    uint256 contextSuffixLength = _contextSuffixLength();
    if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
        return address(bytes20(msg.data[calldataLength - contextSuffixLength:]));
    } else {
        return super._msgSender();
    }
}

function _msgData() internal view virtual override returns (bytes calldata) {
    uint256 calldataLength = msg.data.length;
    uint256 contextSuffixLength = _contextSuffixLength();
    if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
        return msg.data[:calldataLength - contextSuffixLength];
    } else {
        return super._msgData();
    }
}

Multicall: 효율성을 위한 트랜잭션 일괄 처리

Multicall 기능은 사용자가 여러 함수 호출을 단일 트랜잭션으로 묶을 수 있게 하여 가스 비용을 크게 줄이고 트랜잭션 효율성을 향상시킵니다. OpenZeppelin의 MulticallUpgradeable은 이 목적을 위해 널리 사용되는 구현체입니다. calldata 바이트 배열을 받아 각 항목에 대해 delegatecall을 수행하며, 호출하는 컨트랙트의 컨텍스트 내에서 실행합니다.

function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
    results = new bytes[](data.length);
    for (uint256 i = 0; i < data.length; i++) {
        results[i] = _functionDelegateCall(address(this), data[i]);
    }
    return results;
}

(참고: 여기서 논의된 버그는 이후 OpenZeppelin의 Multicall 최신 버전에서 수정되었습니다.)

비호환성: ERC-2771과 Multicall의 충돌

ThirdWeb 사건의 스마트 컨트랙트 취약점의 핵심은 ERC-2771과 Multicall이 calldata를 처리하는 방식에서 발생하는 치명적인 불일치에서 비롯되었습니다. ERC-2771은 신뢰할 수 있는 포워더가 메시지 데이터와 발신자 정보를 함께 패킹할 것을 기대합니다. 그런 다음 수신자 컨트랙트는 _msgData()_msgSender()를 사용하여 이 정보를 올바르게 언패킹합니다.

그러나 취약한 구현에서 Multicall 함수는 ERC-2771이 메타 트랜잭션을 위해 데이터를 패킹하는 방식과 호환되도록 설계되지 않았습니다. 구체적으로, Multicall이 일괄 호출을 처리할 때, 초기 메타 트랜잭션에서 _msgSender()를 올바르게 추출한 다음 각 개별 호출의 calldata에 이 발신자 정보를 추가한 후 실행해야 했습니다. 이 중요한 단계가 누락되었습니다.

Multicall이 처리하는 각 서브 호출 내의 calldata에 발신자 정보가 올바르게 추가되지 않으면, 대상 컨트랙트 내의 ERC-2771 컨텍스트는 서브 호출의 _msgData()마지막 20바이트에서 발신자 정보를 언패킹하려 시도합니다. 결정적으로, 공격자는 이 마지막 20바이트를 제어할 수 있었습니다. 이를 통해 악의적인 행위자는 Multicall에 의해 처리된 후 ERC-2771 지원 컨트랙트에 의해 해석될 때, 조작된 _msgSender() 값(예: 공격자가 제어하는 주소나 프로토콜 자체의 풀 주소)으로 임의의 로직을 실행하는 특정 calldata를 조작할 수 있었습니다. 이는 의도된 보안 검사를 효과적으로 우회하고 두 사양이 설정한 기대치를 위반하여 무단 행위를 초래했습니다.

ThirdWeb 사건: 공격 분석 및 악용

BlockSec의 Phalcon 플랫폼이 분석한 공격 트랜잭션을 사용하여 ThirdWeb 사건의 스마트 컨트랙트 취약점 악용에 대한 실제 사례를 살펴보겠습니다.

공격자의 전략은 _msgSender()를 조작하여 Uniswap 풀을 사칭함으로써 토큰 잔액을 탈취하는 것이었습니다.

  • 1단계: 초기 토큰 획득. 공격자는 탈중앙화 거래소에서 5 WETH를 3,455,399,346 TIME 토큰으로 스왑하는 것으로 시작했습니다. 이는 이후 조작에 필요한 토큰을 확보한 것입니다.

  • 2단계: 악성 Multicall 실행. 이것이 익스플로잇의 핵심입니다. 공격자는 ERC-2771/Multicall 비호환성을 악용하도록 세심하게 조작된 calldata를 가진 신뢰할 수 있는 포워더를 호출했습니다. 이 calldata가 Multicall 함수에 의해 파싱될 때, TIME 토큰 컨트랙트의 burn 함수가 호출되는 결과를 낳았습니다. 결정적으로, 취약점으로 인해 _msgSender()가 Uniswap 풀 주소로 잘못 해석되었습니다. 이를 통해 공격자는 실제 승인 없이 Uniswap 풀이 보유한 TIME 토큰의 상당 부분을 효과적으로 소각할 수 있었습니다. BlockSec Phalcon 플랫폼은 이 흐름을 시각화하기 위한 상세한 트랜잭션 추적을 제공합니다.

    악성 multicall을 보여주는 트랜잭션 추적
    악성 multicall을 보여주는 트랜잭션 추적

    위 이미지는 공격자의 Forwarder.execute 호출이 어떻게 처리되는지를 보여줍니다. multicall 함수는 바이트 배열을 수신하고, 이는 조작된 _msgSender()burn 함수가 호출되는 결과를 낳습니다.

    multicall 파싱 및 burn 함수 호출의 상세 뷰
    multicall 파싱 및 burn 함수 호출의 상세 뷰

    Phalcon의 이 상세 뷰는 길이 1의 bytes[]가 컨트랙트를 호출하는 데이터로 사용되어 거짓 _msgSender() 하에서 burn 함수가 실행되는 것을 보여줍니다.

  • 3단계: 가격 조작. Uniswap 풀에서 대량의 TIME 토큰을 소각함으로써, 공격자는 TIME에 대한 풀의 유동성을 급격히 감소시켰습니다. 이 인위적인 희소성으로 인해 풀 내에서 WETH 대비 TIME의 가격이 치솟았습니다.

  • 4단계: 수익성 있는 차익 거래. TIME 가격이 인위적으로 부풀려진 상태에서, 공격자는 남은 3,455,399,346 TIME 토큰을 다시 94 WETH로 스왑하여 조작된 가격으로 상당한 수익을 실현했습니다.

이 일련의 사건들은 모듈 비호환성에서 비롯된 미묘한 스마트 컨트랙트 취약점을 활용한 정교한 공격을 보여줍니다.

BlockSec으로 스마트 컨트랙트를 보호하세요

숨겨진 비호환성이 프로젝트를 위험에 노출시키지 않도록 하세요. 저희 전문 감사팀은 취약점이 악용되기 전에 식별하고 완화하기 위한 포괄적인 스마트 컨트랙트 감사를 수행합니다.

Web3 최고의 보안 감사 기관

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

ThirdWeb 사건의 주요 교훈

ThirdWeb 사건은 특히 서드파티 라이브러리의 상호작용과 관련하여 Web3 보안에 내재된 복잡성을 상기시켜 주는 중요한 사례입니다.

  • 상호운용성 위험: 빠르게 진화하는 DeFi 공간에서 프로젝트들은 서드파티 라이브러리와 모듈의 스택에 크게 의존합니다. 이러한 구성 요소들이 개발을 가속화하는 반면, 그 상호작용은 예기치 못하고 은밀한 취약점을 도입할 수 있습니다. ThirdWeb 사건은 OpenZeppelin의 ERC2771ContextMulticallUpgradeable처럼 널리 사용되고 견고해 보이는 구성 요소들도 통합이 꼼꼼하게 처리되지 않으면 치명적인 보안 허점을 만들 수 있다는 것을 명확히 보여줍니다.
  • 심층 기술 감사의 필수성: 이 유형의 스마트 컨트랙트 취약점은 피상적인 검사로는 쉽게 발견되지 않습니다. 서로 다른 모듈이 데이터, 특히 calldata를 처리하고 해석하는 방법을 분석하고 잠재적인 불일치를 식별하기 위해서는 깊은 기술적 전문성이 필요합니다. 교차 모듈 상호작용과 엣지 케이스에 집중하는 철저한 스마트 컨트랙트 감사가 무엇보다 중요합니다.
  • 지속적인 모니터링과 사고 대응: 강력한 감사에도 불구하고 새로운 공격 벡터가 등장할 수 있습니다. BlockSec의 Phalcon이 제공하는 것과 같은 지속적인 블록체인 보안 모니터링은 실시간으로 의심스러운 활동을 감지하고 피해를 최소화하기 위한 신속한 사고 대응을 가능하게 하는 데 매우 중요합니다.
  • 개별 모듈 보안을 넘어서: 개발자들은 개별 구성 요소의 보안을 넘어 전체 스마트 컨트랙트 시스템의 총체적인 보안 상태를 고려해야 합니다. 데이터가 서로 다른 모듈 간에 어떻게 흐르는지, 컨텍스트가 어떻게 보존되거나 변경되는지, 외부 호출이 어떻게 처리되는지가 모두 중요한 고려 사항입니다.

ThirdWeb 사건은 블록체인 보안에 대한 사전적이고 포괄적인 접근 방식의 중요성을 강조합니다. 개별 라이브러리의 명성에만 의존하는 것은 불충분하며, 라이브러리 간의 상호작용을 엄격하게 면밀히 검토해야 합니다.

Sign up for the latest updates
~$160만 손실: Moke 토큰, LpdFi 익스플로잇 | BlockSec 위클리
Security Insights

~$160만 손실: Moke 토큰, LpdFi 익스플로잇 | BlockSec 위클리

2026년 8월 3~9일, BNB 체인에서 2건의 보안 사고가 발생해 총 약 160만 달러의 손실이 발생했으며, 모두 가격 조작이 원인이었습니다. LpdFi(약 69.7만 달러)는 PancakeSwap 유동성 풀을 주문 평가와 이자 정산에 동시 사용해 공격자가 원금을 부풀리고 과도한 이자를 탈취했습니다. Moke Token(약 90.6만 달러)은 조작 가능한 현물 가격과 중복 LP 배당 회계를 결합해 MOKE를 부풀려 BNB 배당을 반복 수령했습니다.

COLDCARD 사건: 지갑의 "무작위" 시드가 무작위가 아니었을 때
Security Insights

COLDCARD 사건: 지갑의 "무작위" 시드가 무작위가 아니었을 때

COLDCARD 펌웨어의 빌드 통합 버그로 비트코인 시드 생성이 취약한 소프트웨어 RNG로 라우팅되어 지갑 시드가 오프라인 복구 가능해졌습니다. 시드 자체의 취약점이므로 펌웨어 업데이트로 해결 불가하며, 2026년 8월 7일 기준 확인된 피해는 1,405 BTC(~9,100만 달러), 비공개 추정치는 최대 2,055 BTC입니다.

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

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

2026년 7월 27일~8월 2일, 비트코인과 BNB 체인에서 약 8,800만 달러 손실을 유발한 두 건의 보안 사고가 발생했습니다. COLDCARD 사고는 하드웨어 지갑 펌웨어의 엔트로피 오류로, RNG 매크로 활성화 여부 미확인으로 결정론적 폴백이 실행되어 약 1,370 BTC(~8,800만 달러)가 탈취됐습니다. BNB 체인의 LULA 토큰은 비즈니스 로직 취약점으로 `recycle()` 함수가 악용되어 PancakeSwap V2 유동성에서 약 57만 8천 달러가 유출됐습니다.

Best Security Auditor for Web3

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

BlockSec Audit

Get Real-Time Protection with Phalcon Security

Audits alone are not enough. Phalcon Security detects attacks in real time and blocks threats mid-flight.

phalcon security