작성자: Kong@ 슬로우미스트 보안팀
배경
6월 9일, Optimism과 Wintermute는 모두 2천만 개의 OP 토큰이 손실된 사건을 커뮤니티에 공개하는 발표를 했습니다. Optimism은 Wintermute에게 2차 시장에서 OP에 대한 유동성 서비스를 제공하도록 의뢰했으며 Wintermute에 2천만 개의 OP 토큰을 제공할 것입니다. 이 토큰을 받기 위해 Wintermute는 Optimism에 다중 서명 주소를 제공했습니다. Optimism이 테스트에서 두 개의 트랜잭션을 전송하고 Wintermute가 이들이 정확함을 확인한 후 Optimism은 2천만 OP를 이 주소로 전송했습니다. Optimism이 토큰을 전송한 후 Wintermute는 그들이 제공한 다중 서명 주소가 당분간 이더리움 메인넷에만 배포되었고 아직 Optimism 네트워크에 배포되지 않았기 때문에 이러한 토큰을 제어할 방법이 없다는 것을 발견했습니다. Wintermute는 즉시 수정 작업을 시작했지만 공격자는 이 취약점을 발견하고 Wintermute 이전에 Optimism 네트워크 주소에 다중 서명을 배포하여 2천만 개의 토큰을 성공적으로 제어했습니다. 그래서 질문은 왜 그런 허점이 있습니까?
사전 지식
먼저 트랜잭션 서명이 [EIP155] 표준에 부합하는지 확인해야 하는데 [EIP155] 표준에 부합하는 서명은 9개의 RLP 인코딩 요소(nonce, gasprice, gas, to, value, data, chainid)를 해시하게 됩니다. , 0, 0), 여기서 The chainid가 포함되므로 [EIP155] 호환 서명의 v-값은 {0,1} + chainid * 2 + 35입니다. [EIP155] 규격에 맞지 않는 서명의 경우 6개의 요소(nonce, gasprice, gas, to, value, data)만 해시하므로 서명 후 v의 값은 {0,1} + 27이 됩니다. 서로 다른 체인은 서로 다른 chainid를 정의하고 서로 다른 chainid는 서로 다른 v 값을 얻습니다. ECDSA에 따르면 v의 값이 다르면 r과 s의 값이 같더라도 서명에 의해 복원된 공개키도 다르다는 것을 우리는 알고 있다. 따라서 [EIP155] 표준을 충족하는 트랜잭션은 다른 체인에서 성공적으로 재생할 수 없습니다.
[EIP2718]이 새로운 트랜잭션 형식 0x02 || RLP([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, amount, data, access_list, signature_y_parity, signature_r, signature_s])를 도입했다는 점을 언급할 가치가 있습니다. chainid는 별도로 인코딩됩니다. 서명 v 값에는 포함되지 않으며 서명 v 값은 단순 패리티 비트로만 사용되므로 현재 트랜잭션 서명에서 얻은 v 값은 0 또는 1이 됩니다.
트랜잭션 재생
위의 트랜잭션 서명 구조를 이해한 후 서명 v 값 27 또는 28이 다른 체인에서 재생될 수 있음을 명확하게 알 수 있습니다. 그렇다면 다른 체인에서 재생하는 방법은 무엇입니까? 이것은 거래를 보내는 것과 다르지 않으며, 우리는 다른 체인에 원래의 거래 내용만 보내면 됩니다.
예를 들어 Wintermute에서 2,000만 개의 OP 토큰을 훔쳤습니다. 여기서 공격자는 Gnosis Safe가 Factory 계약을 배포한 트랜잭션을 재생했습니다. 여기에서 nonce가 3인 Gnosis Safe Deployer 3 트랜잭션을 재생하려고 합니다.
더 간단한 방법은 먼저 Etherscan을 통해 원래 트랜잭션을 얻는 것입니다.

그런 다음 Optimistic의 eth_sendRawTransaction[RPC]을 통해 직접
(https://eth.wiki/json-rpc/API) 인터페이스를 보낼 수 있습니다.
원본 트랜잭션 내용을 직접 얻을 수 없는 경우 먼저 eth_getTransactionByHash를 전달할 수 있습니다.
트랜잭션 콘텐츠를 얻기 위한 [RPC](https://eth.wiki/json-rpc/API) 인터페이스.

그런 다음 RLP는 트랜잭션 내용을 인코딩하여 원본 트랜잭션 내용을 가져옵니다.

그런 다음 Optimistic의 eth_sendRawTransaction [RPC]를 전달합니다.
(https://eth.wiki/json-rpc/API) 인터페이스를 보낼 수 있습니다.


참조 :
https://eips.ethereum.org/EIPS/eip-155
https://eips.ethereum.org/EIPS/eip-2718
https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm
https://github.com/ethereum/go-ethereum/blob/master/core/types/transaction_signing.go