2023년 12월 5일, 저명한 Web3 개발 플랫폼인 Thirdweb은 사전 구축된 컨트랙트에 영향을 미치는 중대한 스마트 컨트랙트 보안 취약점을 공개했습니다. 이 치명적인 결함은 해당 취약한 컨트랙트를 사용하여 배포된 모든 ERC-20, ERC-721, ERC-1155 토큰에 영향을 미쳤습니다. 공개 이후 며칠 동안, 취약한 컨트랙트로 배포된 토큰들은 일련의 공격을 통해 점진적으로 악용되었으며, 이는 근본적인 비호환성의 심각성을 여실히 보여주었습니다.
ThirdWeb 스마트 컨트랙트 취약점 이해하기
ThirdWeb 사건의 근본 원인은 스마트 컨트랙트 개발의 두 가지 핵심 구성 요소인 ERC-2771과 OpenZeppelin의 Multicall 구현 간의 예기치 못한 상호작용에 있습니다. 취약점을 완전히 이해하려면 각 구성 요소를 개별적으로 파악한 후, 그 상호작용이 어떻게 악용 가능한 경로를 만들어냈는지 이해하는 것이 필수적입니다.
ERC-2771: 메타 트랜잭션과 신뢰할 수 있는 포워더
EIP-2771은 Recipient 컨트랙트가 신뢰할 수 있는 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을 보여주는 트랜잭션 추적 위 이미지는 공격자의
Forwarder.execute호출이 어떻게 처리되는지를 보여줍니다.multicall함수는 바이트 배열을 수신하고, 이는 조작된_msgSender()로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의
ERC2771Context와MulticallUpgradeable처럼 널리 사용되고 견고해 보이는 구성 요소들도 통합이 꼼꼼하게 처리되지 않으면 치명적인 보안 허점을 만들 수 있다는 것을 명확히 보여줍니다. - 심층 기술 감사의 필수성: 이 유형의 스마트 컨트랙트 취약점은 피상적인 검사로는 쉽게 발견되지 않습니다. 서로 다른 모듈이 데이터, 특히 calldata를 처리하고 해석하는 방법을 분석하고 잠재적인 불일치를 식별하기 위해서는 깊은 기술적 전문성이 필요합니다. 교차 모듈 상호작용과 엣지 케이스에 집중하는 철저한 스마트 컨트랙트 감사가 무엇보다 중요합니다.
- 지속적인 모니터링과 사고 대응: 강력한 감사에도 불구하고 새로운 공격 벡터가 등장할 수 있습니다. BlockSec의 Phalcon이 제공하는 것과 같은 지속적인 블록체인 보안 모니터링은 실시간으로 의심스러운 활동을 감지하고 피해를 최소화하기 위한 신속한 사고 대응을 가능하게 하는 데 매우 중요합니다.
- 개별 모듈 보안을 넘어서: 개발자들은 개별 구성 요소의 보안을 넘어 전체 스마트 컨트랙트 시스템의 총체적인 보안 상태를 고려해야 합니다. 데이터가 서로 다른 모듈 간에 어떻게 흐르는지, 컨텍스트가 어떻게 보존되거나 변경되는지, 외부 호출이 어떻게 처리되는지가 모두 중요한 고려 사항입니다.
ThirdWeb 사건은 블록체인 보안에 대한 사전적이고 포괄적인 접근 방식의 중요성을 강조합니다. 개별 라이브러리의 명성에만 의존하는 것은 불충분하며, 라이브러리 간의 상호작용을 엄격하게 면밀히 검토해야 합니다.
Phalcon으로 온체인 사건을 조사하세요
BlockSec의 Phalcon은 실시간 모니터링, 사고 대응 및 심층 트랜잭션 분석을 위한 선도적인 Web3 보안 플랫폼입니다. ThirdWeb 사건과 같은 복잡한 익스플로잇을 탁월한 명확성으로 이해하세요.
이 시리즈의 다른 글 읽기:
- 도입: 2023년 주목할 만한 보안 사건 TOP 10
- #1: Flashbots Relay 취약점을 악용한 MEV 봇 수확
- #2: Euler Finance 사건: 2023년 최대 규모의 해킹
- #3: KyberSwap 사건: 극도로 미묘한 계산으로 반올림 오류를 교묘하게 악용
- #4: Curve 사건: 컴파일러 오류가 무해한 소스 코드에서 결함 있는 바이트코드 생성
- #5: Platypus Finance: 운 좋게 세 번의 공격을 생존하다
- #6: Hundred Finance 사건: 취약한 포크 프로토콜에서 정밀도 관련 익스플로잇의 물결을 촉발
- #7: ParaSpace 사건: 업계 최악의 공격을 저지하기 위한 시간과의 싸움
- #8: SushiSwap 사건: 어설픈 구조 시도가 일련의 모방 공격으로 이어지다
- #9: MEV 봇 0xd61492: 독창적인 익스플로잇에서 포식자에서 먹잇감으로



