Patch Thursday — MEV-Boost Equivocation 공격과 PBS 보상 구조 취약점 연구
Summary
본 글은, 2023년 4월 2일경 발생한 MEV-Boost 취약점 공격(Unbundling Attack)에서 영감을 받아 진행한 MEV-Boost 및 PBS 보상 구조의 후속 리서치와 그 과정에서 발견한 취약점을 소개합니다.
ChainLight 팀이 취약점 보고서를 송부했을 시점, 언급한 취약점 중 일부는 이미 패치가 배포되었고 포럼에서 논의가 진행 중인 내용이 있었습니다.
Unbundling 공격(low-carb crusader)이 발생한 직후인 2023년 4월 4일경, ChainLight 팀은 공격 분석 연구 과정에서 Equivocation 확인 절차, MEV-Boost-Relay의 네트워크 Race condition, PBS(Proposer-Builder Separation) 구조상에서 발생할 수 있는 잠재적인 취약점들과 개선 사항을 발견할 수 있었습니다. 취약점 검증 및 실험을 위해 2달간의 PoC(Proof Of Concept) 환경 제작과 설정 과정을 거쳐 Flashbots와 Ethereum Foundation측에 보고서를 전달했습니다.
리서치 과정과 발견한, 또는 이미 패치된 취약점을 통해 더욱더 안전한 Web3 생태계를 만들어 가기 위해 연구 및 취약점 리포트를 공개합니다. WAGMI!
Vulnerabilities Description
Ethereum Beacon 체인의 합의 과정과 MEV-Boost의 동작 방식에 대해 더 알고 싶으시다면 Paradigm의 ‘Time, slots, and the ordering of events in Ethereum Proof-of-Stake — Paradigm’를 읽어보시는 것을 추천해 드립니다.
본 보고서는 MEV-Boost-Relay가 사용하는 Prysm 노드로 인해 발생한 문제 두 가지와 PBS 보상 구조의 문제를 다룹니다. 세 가지 문제 모두 잠재적인 자금 손실을 초래할 수 있습니다. Prysm과 MEV-Boost-Relay는 이 두 가지 문제를 빠르게 패치할 수 있지만, Builder는 PBS의 보상 구조 문제를 해결하기 위해서 새로운 컨트랙트를 배포해야 합니다.
Prysm이란? Ethereum 네트워크에 접근하기 위한 클라이언트이며, Validator(검증자) 노드를 운영하는 데에 사용됩니다.
취약점 (1) Prysm publishBlock API는, 공격자가 서명한 블록을 MEV-Boost-Relay에 보내기 전에, 동일한 슬롯에 공격자가 이미 블록을 게시한 경우에도 유효한 응답인 200 status code를 반환합니다. (Equivocation 검사하지 않음)
취약점 (2) MEV-Boost-Relay는 Prysm을 통해 연결된 모든 Beacon 노드의 응답을 확인하지 않고, 한 노드만 응답에 성공해도 Block propose API가 성공을 반환합니다. 이러한 문제로 인해 네트워크의 대다수가 MEV-Boost-Relay의 서명된 블록을 드롭(Drop)하고 Reorg 합니다.
취약점 (3) PBS 보상 구조의 마지막 버그로 인해, 블록 Builder가 최종 보상을 Proposer의 EOA(External Owned Account) 주소로 전송하며 블록이 Reorg 되었을 때, 기존 체인에 해당 보상 트랜잭션이 포함되지 않은 경우 공격자가 다음 블록에서 해당 트랜잭션을 사용할 수 있습니다.
취약점 (1), (2)를 악용하면, 공격자는 블록 N의 Gas를 Gas target보다 낮게 설정할 수 있습니다. 따라서 블록 N+1의 Base fee는 감소하고 공격자는 다음 블록에 Builder의 reward 트랜잭션을 추가할 수 있습니다.
Self Equivocation Attack과 공격 시나리오
저희는 (1), (2), (3) 취약점을 악용한 공격을 통칭하여 ‘Self Equivocation Attack’이라고 명명했습니다. Self Equivocation Attack은 하기 시퀀스 다이어그램으로 간단히 설명할 수 있습니다.
공격자는 자신의 슬롯(Slot) 차례에 블록 ‘B’를 제안하고 전파합니다.
공격자는 블록 ‘A’의 해시를 MEV-Boost-Relay에 요청한 다음, 해시를 서명해 MEV-Boost-Relay에 반환합니다.
MEV-Boost-Relay는 블록을 자신의 Prysm 노드에 블록 게시를 시도하고, Relay의 Prysm 노드가 성공적으로 블록을 전파하면 공격자에게 블록을 공개합니다.
그러나 Prsym 노드는 API를 통해 블록 전파를 요청했을 경우 Equivocation 여부를 확인하지 않습니다. (Prysm은 블록이 P2P 네트워크에서 온 경우 Equivocation 여부를 확인하고 블록 Proposer를 슬래싱합니다.)
공격자의 블록 ‘B’가 MEV-Boost-Relay의 블록 ‘A’보다 먼저 전파되기 때문에 네트워크의 Validator 대다수는 공격자의 블록 ‘B’를 선택하고 블록 ‘A’를 제외한 후 공격자를 슬래싱해야 합니다.
공격자는 ‘B’ 블록으로 Rebuild 하고 Flashbots(또는 다른 PBS 솔루션)를 통해 ‘A’ 블록에 포함된 트랜잭션을 활용한 트랜잭션을 생성하여 이익을 얻습니다.
슬래싱(Slashing)이란, 블록체인 네트워크상의 규칙을 지키지 않은 Validator에 페널티를 부과하여 보상을 삭감하는 것을 뜻합니다.
MEV-Boost-Relay는 동일한 슬롯에 Equivocation 블록이 들어오거나 블록이 Reorg 될 수 있는 다른 상황이 발생하면 Beacon 체인 API(Prysm)가 200이 아닌 status code를 반환할 것이라고 가정하지만, 그렇지 않았습니다.
다음 코드는 Prysm의 ‘P2P broadcasted block handling function’에서 가져왔습니다. 같은 Proposer가 같은 슬롯에 다른 블록을 제안하면 Prysm은 해당 블록을 무시합니다. 반면, Prysm의 API 구현(POST /eth/v1/beacon/blocks)은 이를 확인하지 않고* MEV-Boost-Relay에 200 status code를 반환합니다.
// Verify the block is the first block received for the proposer for the slot.
if s.hasSeenBlockIndexSlot(blk.Block().Slot(), blk.Block().ProposerIndex()) {
return pubsub.ValidationIgnore, nil
}
위의 문제 뿐만 아니라, 사건 발생 후 완료된 ‘check for any non-200 code’ 패치만으로는 공격자의 Timing Attack과 Race condition 악용을 방지하기에 충분치 않습니다.
아래의 코드는 MEV-Boost-Relay에서 Beacon 노드의 응답을 확인하는 코드입니다. 만일, 한 개 이상의 Beacon 노드가 오류 없이 200 code로 응답하면, 다른 모든 Beacon 노드의 응답을 무시하는 함수가 포함되어 있습니다. 공격자는 피해자의 MEV-Boost-Relay와 연결된 Beacon 노드 중 하나만 200 status code로 응답하도록 하면 됩니다.
var lastErrPublishResp publishResp
for i := 0; i < len(clients); i++ {
res := <-resChans
log = log.WithField("beacon", clients[res.index].GetURI())
if res.err != nil {
log.WithField("statusCode", res.code).WithError(res.err).Warn("failed to publish block")
lastErrPublishResp = res
continue
} else if res.code == 202 {
// Should the block fail full validation, a separate success response code (202) is used to indicate that the block was successfully broadcast but failed integration.
// https://ethereum.github.io/beacon-APIs/?urls.primaryName=dev#/Beacon/publishBlock
log.WithField("statusCode", res.code).WithError(res.err).Error("block failed validation but was still broadcast")
lastErrPublishResp = res
continue
}
c.bestBeaconIndex.Store(int64(res.index))
log.WithField("statusCode", res.code).Info("published block")
return res.code, nil
}
log.Error("failed to publish block on any CL node")
return lastErrPublishResp.code, fmt.Errorf("last error: %w", lastErrPublishResp.err)
}
Exploit Scenarios
앞서 언급한 바와 같이, 확실하게 블록을 Reorg 할 수 있는 취약점을 가진 공격은 두 유형의 피해자를 양산할 수 있습니다. 첫 번째는 MEV 봇이고 또 다른 하나는 블록 Builder입니다.
#1 MEV-bots
MEV 봇을 악용하는 방법은, 이전에 발생했던 공격 사례(salmonella, low-carb-crusader의 공격)* 에서 사용한 방법과 동일합니다. 이 공격은 서명된 블록에서 Sandwich 트랜잭션을 Rebuild 하는 것과 다음 블록에서 Rebuild 하는 것에 따라 다른 유형을 띱니다.
일부 MEV 봇은 이미 이러한 유형의 공격을 방지하기 위해(또는 공격의 목적이 아닌 Reorg를 방지하기 위해) MEV 트랜잭션이 대상 블록에 포함되어야 하는 블록 번호를 확인하여 사전 공격 방지 조처를 취하고 있습니다. 그러나 Eigenphi에 기재되어 있는 일부 상위 MEV 봇은 여전히 해당 기능을 사용하지 않으며, 심지어 블록 번호나 deadline을 확인하지 않는 것으로 나타났습니다.
*https://github.com/Defi-Cartel/salmonella, https://etherscan.io/txs?block=16964664, https://collective.flashbots.net/t/post-mortem-april-3rd-2023-mev-boost-relay-incident-and-related-timing-issue/1540
#2 Builder
PBS의 사양에 따르면, Builder가 블록의 마지막 위치에 있는 Validator에 수수료(보상)를 보내는 트랜잭션을 생성하기 때문에 MEV-Boost-Relay는 블록의 마지막 트랜잭션만을 확인해도 Proposer에게 가장 이익이 되는 블록을 선택할 수 있습니다. 그러나 Builder의 보상 트랜잭션이 포함된 블록이 공격 시나리오나 Ethereum에서 발생하는 블록의 자연스러운 Reorg 등 어떤 방식으로든 블록이 Reorg 되는 경우, 해당 트랜잭션은 다른 블록에서 사용될 수 있습니다. 저희는 이를 ‘Grab-from-forked-block Attack’이라고 부릅니다. 해당 취약점 공격에 선제적으로 대응하기 위해서는 PBS 보상 사양을 수정해야 합니다.
위의 공격 시나리오와 함께 MEV 블록을 제거할 수 있는 취약점을 악용하면 Builder가 보유하고 있는 Ethereum 전체를 탈취할 수 있습니다. Builder들은 이익의 극대화를 위해 해당 취약점을 악용하기 위한 방법으로 의도적으로 많은 Bribe를 지불하는 트랜잭션을 생성하지만, 동일한 nonce를 사용하여 Proposer에게 다수의 Bribe가 지불되는 것을 방지합니다.
Bribe란? Builder가 Proposer에 지불하는 금액을 PBS에서는 일반적으로 Bribe라는 표현을 사용합니다.
더 문제가 되는 경우는, 공격 목적이 아닌 시나리오에서도 발생할 수 있다는 것입니다. 아래 PoC는 fork 된 블록(17217053*)에서, Validator에 보내는 rsync-builder의 트랜잭션을 사용합니다.
~/workspaces/forked-block-research$ cast publish - rpc-url=http://127.0.0.1:13378 0x02f872018301315b808524f02ac969825208947e2a2fa2a064f693f0a55c5639476d913ff12d0588066fe49529ad331f80c080a07f21607377ac8f0d95590491b00e31e0e210f64ac2d74c304c74831b3f1c2d88a062f1a7eb6c6dea090524799448734b203cee29623abda2e0a46192a43b9b9e3b
{"transactionHash":"0xc9ef0bab624a6140678e08c0e8d941f37247909ada1877bf847a5324c4f78b46","transactionIndex":"0x0","blockHash":"0xad4f1ca23cc67a9349f43c8decaa8b3be4f8fe99eac322da80bbbd398bb8b378","blockNumber":"0x106b61f","from":"0x1f9090aae28b8a3dceadf281b0f12828e676c326","to":"0x7e2a2fa2a064f693f0a55c5639476d913ff12d05","cumulativeGasUsed":"0x5208","gasUsed":"0x5208","contractAddress":null,"logs":[],"status":"0x1","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","type":"0x2","effectiveGasPrice":"0x238478411c"}
Proof of Concept of grab-from-forked-block attack
Patch Recommendations
(MEV)-Prysm
블록이 이미 동일한 슬롯에 들어왔을 때(+ 동일한 Proposer와 함께) Prysm이 200 이외의 상태 코드를 반환하도록 설정합니다. 패치가 적용된 후 시퀀스 다이어그램은 아래와 같습니다:
MEV-Boost-Relay
MEV-Boos-Relay는 한 개 노드의 응답 성공 여부만을 확인하는 것이 아니라, 연결된 모든 Beacon 노드의 전체 응답을 확인해야 합니다.
MEV-bots
MEV 봇은 트랜잭션 입력 데이터에 목표 블록 번호 또는 deadline을 추가해야 하며, Strategy Contract는 이를 검증해야 합니다.
PBS Reward Architecture
Builder는 nonce 재사용 공격을 완화하기 위해, 블록 번호를 확인하는 스마트 컨트랙트를 사용하여 보상 전송 방법을 변경해야 합니다. 컨트랙트 예시는 아래와 같습니다:
-- disclaimer: we did not test it
-- calldata: (address << 32) | blocknumber
calldataload
dup1 ; address + block number
push4 0xffffffff
and
number
eq
push2 XX
jumpi
stop
XX:returndatacopy
returndatacopy
returndatacopy
returndatacopycallvalue
dup N
push1 0x20
shr
gas
call
Conclusions
PBS, MEV-Boost와 같이 기존의 MEV가 가지고 있던 부정적인 영향들을 완화하기 위한 솔루션이 개발 및 연구됨과 동시에 발생할 수 있는 취약점들의 개선 또한 병행되어야 합니다. 현재 Flashbots, Ethereum Foundation의 커뮤니티에서 PBS에 관한 다수 연구와 논의가 진행되고 있습니다.
Flashbots forum: https://collective.flashbots.net/
Ethereum community: https://notes.ethereum.org/@domothy/pbs_links
PBS와 MEV-Boost에 기여하고 싶으신 분들은 위의 링크를 통해 의견을 교류하실 수 있습니다. 앞으로도 ChainLight 팀은 Web3 사용자들의 안전을 위해 Ethereum 생태계 기여에 앞장서도록 하겠습니다.
References
https://www.paradigm.xyz/2023/04/mev-boost-ethereum-consensus
https://ethresear.ch/t/equivocation-attacks-in-mev-boost-and-epbs/15338
https://twitter.com/VitalikButerin/status/1588669782471368704?s=20
https://notes.ethereum.org/@vbuterin/pbs_censorship_resistance
✨ We are ChainLight!
ChainLight 팀은 풍부한 실전 경험과 깊은 기술 이해를 바탕으로 새롭고 효과적인 블록체인 보안 기술을 연구합니다. 연구 결과를 바탕으로 Web3 생태계의 각종 보안 위험 요소와 취약점을 사전 파악하여 제거하는 혁신적인 보안 감사 서비스를 제공합니다. 보안 감사 이후에도 온체인 데이터 모니터링 및 취약점 탐지 자동화 서비스를 이용한 지속적인 디지털 자산 위험 관리 솔루션을 제공합니다.
ChainLight 팀은 사용자들이 탈중앙화 서비스를 안전하게 활용할 수 있도록 Web3 생태계 위협으로부터의 보호에 힘쓰고 있습니다.
ChainLight의 더 다양한 정보를 보고 싶으시다면? 👉 Twitter 계정도 방문해 주세요.
🌐 Website: chainlight.io | 📩 TG: @chainlight | 📧 chainlight@theori.io
Originally published at https://blog.theori.io on August 18, 2023.