크로스체인 브리지 경종: 폴리곤이'판도라 상자'의 오픈을 어떻게 예방하는가

Polygon 네트워크 구조, 상호작용성과 크로스체인 메시지 전달 방식을 깊이 있게 분석하고 쌍화구멍 안전 사건을 이야기한다.

1 폴리곤이 누구야?

Polygon은 이더리움의layer2 확장 방안으로 이더리움의 블록체인 인터넷을 구축하는 것이 바람이다.Polygon은 유니버설 프레임워크를 제공하여 개발자가 이더리움의 안전성을 이용하여 맞춤형 프로그램을 만들고 응용 프로그램의 체인에 전념하며 상호작용적인 네트워크를 제공하여 다양한 확장 방안을 결합시켰다. 예를 들어 zk-rollup, PoS 등이다.그 중에서 Polygon PoS는 현재 Polygon에서 가장 성숙하고 널리 알려진 확장 방안이다.이것은 사이드체인을 이용하여 거래 처리를 하고 거래 속도를 향상시키고 가스의 소모를 절약하는 목적을 실현한다. 네트워크 구조는 주로 다음과 같은 3층을 포함한다.

Ethereum 레이어:

이더리움 메인 네트워크의 일련의 계약은 주로 Staking, Checkpoint, Reward 계약을 포함하고 PoS 권익과 관련된 담보 관리 기능을 책임진다. 이는 MATIC 원생 화폐의 담보 기능을 제공하여 이 화폐를 담보하는 모든 사람이 검증자로 시스템에 가입할 수 있도록 한다.Polygon 네트워크의 상태 전환을 검증하여 품질 보증 보상을 획득하기;검증자의 이중 서명, 검증자의 정지 등 비합법적인 행위를 처벌한다.checkpoint를 저장합니다.

Heimdall 레이어:

권익증명 검증 노드층은 PoS Heimdall 노드를 포함하여 Polygon 네트워크의 검사점을 이더리움 메인 네트워크에 제출하고 이더리움에 배치된 품질 보증 계약을 감청한다.주요 절차는 먼저 검증자 탱크의 일부 활발한 검증자를 블록 생산자로 선택하고 이들은 Bor층에서 블록을 만들고 방송하는 것을 책임진다.이어 Bor가 제출한 검사점에 따라 Merkle건 해시를 검증하고 서명을 추가한다.마지막으로 제안자는 지정된 검사점의 모든 검사자의 서명을 수집하고 서명 수량이 2/3 이상이면 이더리움에 이 검사점을 제출한다.

Bor 레이어:

블록 노드 층은 Heimdall 층의 검증자 위원회가 정기적으로 선택한 블록 생산자를 포함한다. 이들은 검증자 서브집합으로 Polygon 사이드체인의 거래를 집합하고 블록을 생성한다.이 레이어는 정기적으로 Heimdall 레이어에 체크포인트(checkpoint)를 발표하는데, 그 중에서 체크포인트는 Bor 체인의 스냅샷을 대표한다. 아래 그림과 같다.

2 Polygon 상호 운용성

2.1 체크포인트(checkpoint)

체크포인트 메커니즘은 Bor층의 데이터를 이더리움에 동기화하는 메커니즘이다. 그 중에서 동기화된 데이터는 체크포인트이다. 즉, 체크포인트 간격의 시간대에 포함된 Bor층 블록 데이터 스냅샷이다. 원본은 다음과 같다.

  • Proposer: 제안자, 그것도 검증자가 선택한 것이다. 블록 생산자와 제안자는 모두 검증자의 서브집합이고 그들의 책임은 전체 연못의 지분 비율에 달려 있다.

  • RootHash: StartBlock에서 EndBlock 사이의 Bor 블록에서 생성된 Merkle Hash입니다.

다음은 번호 1에서 n까지의 Bor 블록이 RootHash 값을 생성하는 위조 코드입니다.

종합적으로 이 값은 Bor 블록 헤드의 블록 번호number, 블록 시간 스탬프time, 거래 나무 뿌리 Hash 값 txhash, 영수증 나무 뿌리 Hash 값 receipthash가 계산한keccak256 해시 값으로 구성된 Merkel tree의 뿌리 해시 값이다.

AccountRootHash: 각 체크포인트를 이더리움에 있는 검증자 관련 계정 정보로 보내야 하는 Merkle Hash, 단일 계정 정보의 해시 값 계산 방식은 다음과 같습니다.

계정 Merkle tree 루트 해시 값으로 계정 루트 해시를 생성하는 방식은 루트 해시 값과 같습니다.

2.2 StateSync

상태 동기화 메커니즘(StateSync)은 이더리움 데이터를 Polygon Matic 체인에 동기화하는 것으로 주로 다음과 같은 몇 가지 단계로 나뉜다.

  • 우선 이더리움의 계약은 StateSender를 촉발합니다.sol의 syncState () 함수 상태 동기화

  • syncState () 함수는 다음과 같은 이벤트 이벤트를 실행합니다.

  • Heimdall층의 모든 검증자는 이 사건을 받을 것입니다. 그 중 한 검증자는 이 거래를 Heimdall 블록에 포장하고 처리할 상태 동기화 목록에 추가합니다.

  • bor층 노드는 API를 통해 상기 동기화 대기 목록을 얻고 bor층의 계약에 넘겨 진일보한 업무 논리 처리를 한다.

2.3 Polygon Bridge

Polygon Bridge는 Polygon과 Ethereum 간의 양방향 체인 통로를 실현하여 사용자가 두 개의 서로 다른 체인 플랫폼 사이에서 더욱 편리하게 코인을 이전할 수 있고 제3자 위협과 시장 유동성 제한이 발생하지 않도록 한다.Polygon Bridge는 PoS와 Plasma 두 가지 유형이 있는데 양자는 Polygon과 Ethereum 간의 자산 이전에서 다음과 같은 점이 있다.

1) 먼저 Ethereum의 토큰을 Polygon에 매핑해야 합니다. 아래 그림과 같습니다.

2) 양방향 앵커 기술(Two-way Peg), 즉

  • a: 이더리움에서 이전된 기호화폐 자산은 먼저 Ethereum에 잠기고 같은 수량의 기호화폐는 Polygon에서 주조된다.

  • b: 기호화폐 자산을 Ethereum에서 추출하기 위해서는 먼저 이 영사 기호화폐를 Polygon에서burn에서 제거한 다음에 Ethereum에 잠긴 자산을 해제해야 한다.

다음 그림은 PoS Bridge와 Plasma Bridge의 비교입니다.

위의 그림에서 알 수 있듯이 안전성에 있어 PoS Bridge는 외부 검증자 집합의 안전성에 의존하고 Plasma는 Ethereum 메인체인의 안전성에 의존한다.또한 사용자가 크로스체인 자산을 이전할 때(예를 들어 토큰을 Polygon에서 Ethereum으로 이전하는 경우) PoS는 검사점의 간격이 약 20분에서 3시간 정도만 필요하다.플라즈마는 7일의 쟁의 도전기가 필요하다.또한 PoS는 더 많은 표준 토큰을 지원하지만 Plasma는 ETH, ERC20, ERC721 등 세 가지 유형만 지원합니다.

3 크로스체인 메시징 - PoS Bridge

PoS Bridge는 주로 두 가지 기능을 포함하는데 그것이 바로 Deposit와 Withdrawals이다. 그 중에서 Deposit는 사용자가 이더리움에 있는 자산을 Polygon으로 옮기는 것을 가리키고, Withdrawals는 자산을 Polygon에서 이더리움으로 추출하는 것을 가리킨다.

Deposit

다음은 사용자 Alice가 PoS Bridge를 사용하여 이더리움 계정에 있는 토큰 자산을 Polygon 계정에 전송하는 것을 예로 들 수 있습니다.

1. 만약에 사용자가 이전하고 싶은 기호화폐 자산이 ERC20, ERC721, ERC1155 유형이라면 먼저 사용자가 이전할 기호화폐를 approve 함수를 통해 권한을 부여해야 한다.아래와 같이 이더리움의 token 계약 중의 approve 방법을 호출하여 대응하는 수량의 token을 ec20Predicate 계약에 권한을 부여합니다.

여기서 approve 함수는 두 개의 매개 변수가 있습니다.

  • spender: 사용자 권한 수여로 토큰을 사용할 수 있는 목표 주소

  • amount: 쓸 수 있는 토큰 수량

2. 상기 권한 수여 거래가 확인되면 사용자는 이어서 Root Chain Manager 계약의 deposit For () 방법을 호출하여 이더리움의 ec20Predicate 계약에 토큰을 잠그게 된다.여기서 이전 자산 유형이 ETH인 경우 depositeEtherFor()를 호출합니다.구체적으로 다음과 같습니다.

여기서 depositFor 함수는 다음과 같은 세 가지 매개변수가 있습니다.

  • user: Polygon의 deposit 토큰을 받는 사용자 주소

  • rootToken: 이더리움 메인체인의 token 주소

  • depositData: ABI 인코딩 후 토큰 수

다음은 RootChainManager 계약의 depositFor 함수에 대한 구체적인 코드입니다.

원본 코드를 분석하면 이 함수는 먼저 token에 대응하는predicate 계약 주소를 얻고 그 다음에 lockTokens () 함수를 호출하여 token을 이 계약에 잠그는 것을 알 수 있다.마지막 _stateSender는 syncState () 를 호출해서 상태 동기화를 합니다. 이 함수는admin이 설정한 상태 발송자 (statesender) 만 호출할 수 있습니다.

3、StateSender.sol의 syncState () 함수는 다음과 같이 이벤트 StateSynced를 제출합니다.

그 중에서 첫 번째 파라미터는 이log의 번호 인덱스이고, 두 번째 파라미터는 호출자가 이미 등록된 합법적인 계약 주소인지, 세 번째는 상태 동기화를 해야 하는 데이터입니다.이 거래는 Heimdall 블록에 추가되고 중단된 상태 동기화 목록에 추가됩니다.

4. 이어서 Polygon Matic 체인의 bor 노드가 API를 통해 상태 동기화 목록에 있는 StateSynced 이벤트를 가져오면 이 체인의 ChildChainManager 계약은 onStateReceive() 함수를 호출합니다. 이 함수는 이더리움에서 업로드된 동기화 데이터를 수신하고 상태 동기화의 업무 논리 유형에 따라 다음 처리를 합니다.

데이터: bytes32 형식의syncType,bytes 형식의syncData를 포함합니다.그 중에서syncType는 업무 유형을 대표하는데 deposit와mapping 토큰맵을 포함한다.syncType이mapping일 때syncData는인코딩된rootToken주소,childToken주소와bytes32유형의tokenType입니다.syncType이 deposit일 때,syncData는 인코딩된 사용자 주소,rootToken 주소,bytes 형식의 depositData입니다.depositData는 REC20에서 수량이고 ERC721에서 tokenId를 가리킨다.

5. 이곳은 Deposit 업무이기 때문에 다음에 호출됩니다_syncDeposit() 함수입니다.이 함수는 우선syncData를 대응하는 형식에 따라 디코딩하여 대응하는 rootToken,user 주소,depositData를 얻습니다.이어서 루트토큰이polygon에 대응하는 맵 토큰childToken이 있는지 확인하고, 있으면childToken의 deposit () 함수를 호출합니다.

6. 여기서 우리는 ERC20의 토큰 계약을 예로 삼아 토큰 계약이 어떻게 deposit되는지 소개한다.이 함수는mint에 대응하는 수량의 기호화폐를 사용자 계정에 연결합니다.

이 함수는 두 개의 매개 변수가 있습니다.

  • user: 예금 중인 사용자 주소

  • depositData: ABI로 인코딩된amount

Withdrawals

다음은 사용자 Alice가 PoS Bridge를 사용하여 Polygon 계정에 보관한 자금을 이더리움 계정으로 인출하는 것을 예로 들 수 있습니다.

1. 사용자 withdraw를 사용할 때 먼저 Polygon 체인에서 토큰 계약을 비추는 withdraw () 함수를 호출하여 대응하는 수량의 비추는 토큰을 버립니다.

withdraw는 하나의 매개 변수만 포함합니다. burn에서 떨어질 token 수량입니다.해당하는 token 계약의 withdraw () 함수는 다음과 같습니다.

2. 상술한 거래는 약 20분에서 3시간에 걸쳐 체크포인트에 포함되고 피검증자는 이더리움에 제출된다.

3. 거래가 검사점에 추가되어 이더리움에 제출되면 이더리움에 있는 RootChainManager 계약의 exit() 함수를 호출합니다. 이 함수는 제출된 검사점 내용을 검증하여 Polygon에서 withdraw 거래의 유효성을 확인하고 해당하는Predicate 계약의 사용자 deposit 잠금 해제를 촉발합니다.

여기서 이 함수를 전송하는 Proof 증명 inputData에는 다음 데이터가 포함됩니다.

  • header Number:withdraw 거래를 포함하는 검사점 블록 header

  • blockProof: 서브체인의 블록 헤더가 제출된merkle root의 잎 노드임을 증명합니다

  • blockNumber: 서브체인에 withdraw 거래가 포함된 블록 번호

  • blockTime:withdraw 거래의 블록 타임 스탬프

  • txRoot: 블록 트리의 root 값

  • receiptRoot: 블록 영수증 트리의 root 값

  • receipt:withdraw 거래 영수증

  • receiptProof:withdraw 거래 영수증의 메르크 증명

  • branchMask: 영수증 트리 중 32위가 표시하는 영수증 경로

  • receiptLogIndex: 영수증 트리에서 읽은 로그 인덱스

다음은 이 함수의 핵심 논리로 주로 세 부분을 포함한다. 첫 번째 부분은withdraw 거래 영수증의 유효성을 검증하는 것이고, 두 번째 부분은 검사 지점에 거래 블록이 포함되었는지, 세 번째 부분은predicate 계약 중의 exitTokens () 함수를 호출하여 잠긴 지폐를 사용자에게 보내는 것이다.

4. ERC20Predicate 계약을 예로 들면 로그에서 수신자, 발송자, 발송 지폐의 수량을 디코딩한 후 주어진 수량의 지폐를 사용자에게 발송한다.

PoS Bridge 크로스체인 메시지 전달 과정 원본 분석을 통해 알 수 있듯이 전체 과정의 함수 호출은 검증자가 지정한 역할만 호출할 수 있기 때문에 크로스체인의 안전성은 PoS가 보증한다(공증인).

4 크로스체인 메시징 - Plasma Bridge

Plasma Bridge 역시 다음 그림과 같이 Deposit 및 Withdrawals 두 가지 기능을 제공합니다.

Polygon Plasma는 우리 크로스 체인 브리지 시리즈의 첫 번째 글에서 소개한 비트코인 Plasma MVP와 약간의 차이가 있는데 주로 계좌 모델을 바탕으로 하는 Plasma MoreVP를 사용한다.이 알고리즘은Plasma에 비해 주로withdraw부분에서 부분적으로 개선되었다.

ERC20, ERC721의 토큰 전송은 비트코인 UTXO와 유사한 이벤트 로그를 통해 이루어지기 때문에 이 사건을 먼저 소개합니다.

  • input1: 이체 전 발송자의 계좌 잔액

  • input2: 이체 전 수신자의 계좌 잔액

  • output1: 이체 후 발송자의 계좌 잔액

  • output2: 이체 후 수신자의 계좌 잔액

그 다음으로 원래의 Plasma MVP는 블록이 단일(Operator) 또는 소수의 블록 생산자에 의해 생성되기 때문에 Polygon에 다음과 같은 두 가지 공격 장면이 존재한다.

Operator 악용:

이전 글(<체인 브리지 안전 회고: Nomad 탈중심화 강도 사건은 우리에게 어떤 계발을 가져다 줍니까?) 사용자의 거래가 Operator에 의해 Plasma 블록으로 묶인 후에 체인 데이터의 가용성 문제가 존재한다고 언급했다.따라서 사용자가 exit 거래를 할 때 비교적 오래된 거래부터 탈퇴하면 Operator가 최근의 거래로 도전할 수 있고 도전에 성공할 수 있다.또한 Plasma에서 PoS의 검사점 메커니즘을 사용하기 때문에 Operator가 검사자와 결탁하여 악행을 저지르면 일부 상태 전환을 위조하여 이더리움에 제출할 수 있다.

사용자가 악행을 저지르다:

사용자는 exit 거래를 시작한 후에 계속해서 Polygon에 토큰을 소비하는데 체인을 뛰어넘는 쌍화와 유사하다.

종합적으로 Polygon의 Plasma More Vp 알고리즘은 또 다른 퇴출 우선순위를 계산하는 알고리즘을 사용했다. 즉, 최근의 거래부터 퇴출하는 것이다.이 방식은 UTXO와 유사한 LogTransfer 이벤트를 사용했기 때문에 사용자의 합법적인 거래가 정확한 input1, input2를 사용하기만 하면 Operator의 일부 악성 거래가 사용자 거래 전에 포장되더라도 사용자 거래는 유효한 input에서만 이루어지기 때문에 정확하게 처리될 수 있다.관련 위조 코드는 다음과 같습니다.

Deposit

다음은 사용자 Alice가 Plasma Bridge를 사용하여 이더리움 계정에 있는 토큰 자산을 Polygon 계정에 전송하는 것을 예로 들 수 있습니다.

1. 우선 사용자 역시 이전이 필요한 기호화폐 자산을 approve 함수를 통해 메인체인(Ethereum)의 Polygon 계약 deposit Manager에 권한을 부여해야 한다.

2. 권한 수여 거래가 확인되면 사용자는erc20token을 호출합니다.deposit () 함수, depositManager 계약을 촉발하는 depositerC20ForUser () 함수, 사용자의 ERC20 코인 자산에 저장합니다.

3. 이더리움 메인 네트워크가 이 deposit 거래를 확인하면 다음에 이 거래만 포함하는 블록을 만들고 이를 상태 동기화 메커니즘으로 Polygon 네트워크의childChain 계약에 보내고mint와 같은 수량의 맵코인을 사용자가 Polygon에 있는 계정에 저장한다.

주:childChain 계약 원본 분석을 통해 알 수 있듯이 Plasma는 ETH, ERC20, ERC721 등 세 가지 유형만 지원합니다.

Withdraw

Plasma bridge를 사용하여 Polygon에서 이더리움으로 자산을 추출하려면 다음과 같은 몇 가지 절차를 거치게 됩니다.

1. 사용자는 Polygon에서 화폐를 상영하는 withdraw() 함수를 호출하여 Polygon 체인에 있는 맵 코인 자산을 버립니다.

Polygon의 Plasma Client의 withdrawStart () 인터페이스를 호출해서 실행할 수도 있습니다.

2. 사용자는 ERC20Predicate 계약에서 startExitWithBurntTokens() 함수를 호출할 수 있습니다. 이 함수는 우선 WithdrawManager를 호출합니다.verifyInclusion () 체크 포인트에 withdraw 거래와 대응하는 영수증이 포함되어 있는지 검사합니다. 코드는 다음과 같습니다.

검증이 통과되면 Withdraw Manager가 호출됩니다.addExitToQueue()는 우선 순위에 따라 메시지 대기열에 삽입합니다.

마지막으로, addExitToQueue() 호출_addExitToQueue()는 환불 증명서로 NFT를 주조합니다.

3. 사용자는 7일간의 도전기를 기다린다

4. 도전 기간이 완료되면 Withdraw Manager를 호출할 수 있습니다.processExits() 함수는 사용자에게 토큰을 보냅니다.

이 함수는 주로 두 단계로 나뉜다. 우선 메시지 대기열에 있는 withdraw 거래가 7일의 도전기를 넘겼는지 확인하고, 도전기를 넘으면 이 거래를 대기열에서 제거한다.

이어 환불 증명서 NFT가 도전 기간 내에 삭제되었는지 판단하고 삭제되지 않으면 해당 NFT를 폐기하고 해당 자산을 사용자에게 반환합니다.

5 Polygon Plasma Bridge 쌍화구멍

2021년 10월 5일, 흰 모자 Gerhard Wagner는 Polygon의 빈틈을 제출했다. 이 빈틈은 쌍화 공격을 초래할 수 있다. 관련된 금액은 8.5억 달러이며, 흰 모자는 이로 인해 Polygon 정부의 2만 달러의 빈틈 상금을 받았다.

앞에서 설명한 Plasma Bridge의 전체 Withdraw 거래 과정은 다음과 같습니다.

  1. 사용자가 Polygon에서 Withdraw 거래를 시작하면 이 거래는 사용자가 Polygon에 있는 토큰을 버립니다.

  2. 검사점 간격(약 30분)을 거쳐 이withdraw 거래가 검사점에 포함되기를 기다립니다.

  3. 3분의 2가 넘는 검증자가 서명한 후에 이더리움에 제출합니다. 이때 사용자는 ERC20 PredicateBurn Only 계약의 startExit WithBurnt Tokens () 를 호출하여 checkpoint가 burn 거래를 포함하는지 검사합니다.

  4. 검증이 통과되면 NFT 환불 증명서를 주조하여 사용자에게 보냅니다.

  5. 사용자 대기 7일 도전 기간

  6. WithdrawManager를 호출합니다.processExits() NFT 제거 및 환불

주의: Polygon은 거래 재개(쌍화 공격)를 방지하기 위해 NFT를 환불 증명서로 사용하여 유일하게 Withdraw 거래를 표시합니다.그러나 NFT의 ID 생성 결함으로 인해 공격자는 파라미터를 구성하여 같은 유효한 Withdraw 거래를 이용하여 여러 개의 서로 다른 ID의 NFT를 생성하고 이런 NFT를 이용하여 환불 거래를 하여'쌍화공격'을 실현할 수 있다.

NFT 생성 방법에 대한 자세한 내용은 다음과 같습니다.

1. 위의 원본 코드에서 알 수 있듯이 addExitToQueue () 는 _addExitToQueue()는 NFT를 주조합니다.

전참 분석을 통해 알 수 있듯이 exitid=priority의 경우 NFT의 ID는 Plasma Bridge의age 우선순위 왼쪽으로 한 자리 이동하여 생성됩니다.

2. 위의 원본 해석을 통해 알 수 있듯이 age는 Withdraw Manager이다.verify Inclusion () 함수의 반환값입니다. 이 함수는 withdraw 거래의 유효성을 먼저 검사하고 검사를 통과하면 대응하는age를 생성합니다.그 중에서 검증된 논리에는 제어 가능한 매개 변수 데이터 디코딩 값인 branchMaskBytes가 사용됩니다.

age를 생성할 때도 이 값이 사용됩니다.

3. 추적 거래 검증 논리에서 호출된 Merkle Patricia Proof.verify () 함수, 이 함수 호출 발견_getNibbleArray()는 branchMaskBytes에 대한 디코딩 작업을 수행했습니다.

4. 이 디코딩 함수를 계속 추적합니다. 이 함수는 BranchMaskBytes를 디코딩할 때 일부 값을 버리는 경우가 있습니다. 이런 수치를 잃어버리는 방식은 서로 다른 값을 디코딩한 후에 같은 디코딩 값을 얻을 수 있습니다.구체적으로: 만약 전송된 hp 인코딩 후의 값 b의 첫 번째 16진 비트(반 바이트)가 1이나 3이라면 두 번째 16진 비트를 해석한다.그렇지 않으면 첫 번째 바이트를 무시합니다.

그러면 공격자가 브랜치 MaskBytes 파라미터를 구성하여 첫 번째 16진수 비트가 1과 3과 같지 않게 하면 모두 14*16=224가지 방식으로 같은 디코딩 후의 값을 얻을 수 있다.

구체적인 공격 절차는 다음과 같다.

  • Polygon Plasma를 통해 Polygon에 대량의 ETH/토큰 저장

  • Polygon에서 Withdraw 거래를 시작하여 7일간의 도전기를 기다립니다

  • withdraw 거래에서 branchMaskBytes 파라미터의 첫 번째 바이트(동일한 유효 거래는 최대 23회 다시 제출할 수 있음)를 수정하고 Withdraw 거래를 반복 시작합니다

결론적으로 이 빈틈은 재방출을 방지하는 환불 증명서 NFT를 생성하는 ID 알고리즘 디자인에 문제가 존재하기 때문에 같은 환불 거래가 서로 다른 NFT를 생성하여 쌍화 공격을 초래할 수 있다.인코딩 지점 마스크의 첫 번째 바이트는 항상 0x00이어야 한다는 사실이 증명되었다. 복구 방법은 인코딩된 지점 마스크의 첫 번째 바이트가 0x00인지 확인하고 부정확한 마스크로 간주하지 않는 것이다.

제목: <크로스 체인 브리지 안전 연구(3)| 다각형 전사 폴리곤의 안전 투석, 어떻게 판도라 상자의 오픈을 예방합니까?>

작문: 청두 체인안

출처: ForesightNews