On August 10, 2021, Beijing time, Poly Network, a cross-chain bridge project, was attacked and lost more than 600 million U.S. dollars. Although the attacker will repay the stolen digital currency later, this is still the largest attack in the history of the blockchain. Since the entire attack process involves different blockchain platforms, and there are complex interactions between contracts and Relayers, the existing analysis reports have not been able to sort out the complete process of the attack and the root cause of the vulnerability.
The entire attack is divided into two main stages, including modification of the keeper’s signature and final withdrawal. For the second stage, since the keeper’s signature has been modified, the attacker can directly construct a malicious withdrawal transaction. For details, please refer to our previous report. However, there is no detailed article to clarify how the transaction that modifies the keeper’s signature is finally executed on the target chain. And this step is the core step of the attack.
This report starts with modifying the keeper signature transaction (Ontology chain transaction 0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c), and analyzes the principles behind and the nature of the vulnerability. We found that the following reasons are the reasons why Keeper can be modified:
- The relayer on the source chain (Ontology) does not perform semantic verification on the transaction on the chain, so malicious transactions that include the modification of the keeper can be packaged on the poly chain
- Although the relayer on the target chain (Ethereum) verifies the transaction, the attacker can directly call the EthCrossChainManager contract on Ethereum and finally call the EthCrossChainData contract to complete the signature modification
- The attacker carefully enough the function signature that can cause hash conflicts, and then call to
putCurEpochConPubKeyBytescomplete the modification of the signature
Involving transactions and contracts
The interaction flow in the whole process is as follows:
Ontology交易 -> Ontology Relayer -> Poly Chain -> Ethereum Relayer -> Ethereum
0xb1f70464bd95b774c6ce60fc706eb5f9e35cb5f06e6cfe7c17dcda46ffd59581: modify the keeper’s transaction
0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c: Modify the keeper’s transaction
0x1a72a0cf65e4c08bb8aab2c20da0085d7aee3dc69369651e2e08eb798497cc80: modify the keeper transaction
The entire attack can be roughly divided into three steps. The first step is to generate a malicious transaction on the Ontology chain (0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c), the second step is to modify the keeper signature in the Ethereum EthCrossChainData contract, and the third step is to construct a malicious transaction to initiate a final attack and withdraw.
The attacker first initiated a cross-chain transaction in Ontology (0xf771ba610625d5a37b67d30bf2f8829703540c86ad76542802567caaffff280c), which contained an attack payload:
It can be seen that the transaction contains a well-designed function name (numbers starting with 6631 in the figure, after conversion
f1121318093), the purpose is
哈希冲突to call the
putCurEpochConPubKeyBytesfunction (belonging to the EthCrossChainData contract on Ethereum) by causing (hash collision ). There have been many discussions about the details of hash function conflicts on the Internet, you can refer to .
Subsequently, the transaction was received by the Ontology Relayer. Note that there is no strict verification here. The trade fair was successfully listed on the Poly Chain through Relayer (0x1a72a0cf65e4c08bb8aab2c20da0085d7aee3dc69369651e2e08eb798497cc80). The Ethereum Relayer will perceive the generation of new blocks.
However, this transaction was taken by the Ethereum Relayer
拒绝. The reason is that the Ethereum Relayer verifies the target contract address, and only allows the LockProxy contract as the target address, and the attacker passes in the EthCrossChainData address.
Therefore, the attacker’s path of attack is interrupted here. However, as mentioned earlier, the attack transaction containing the malicious payload has been successfully listed on the Poly Chain and can be further exploited.
The attacker manually initiates a transaction, calls the
verifyHeaderAndExecuteTxfunction in the EthCrossChainManager contract, and takes the attack transaction data saved in the Ploy Chain block in the previous step as input. Since the block is a legal block on the poly chain, it can pass
verifyHeaderAndExecuteTxthe verification of the signature and merkle proof in the middle. Then execute the
putCurEpochConPubKeyBytesfunction in the EthCrossChainData contract to modify the original 4 keeper to the address specified by yourself (0xA87fB85A93Ca072Cd4e5F0D4f178Bc831Df8a00B).
After the keeper is modified, the attacker directly calls the
verifyHeaderAndExecuteTxfunction on the target chain (no need to go through the poly chain – because the keeper has been modified, the attacker can arbitrarily sign the block on the poly chain that seems reasonable to the target chain), Finally, it was called to the
Unlockfunction (belonging to the LockProxy contract), and a large amount of funds was transferred, which caused serious losses to the project party. For specific details of the attack, please refer to our previous report .
Relayer code analysis
In the process of this attack, both the Ontology party and the Ethereum party have a Relayer responsible for putting transactions from Ontology on the poly Chain and putting the transactions on the poly chain on Ethereum. These two Relayers are service processes implemented by the Go language.
However, we found that both Relayers lack effective verification. Which resulted in
- An attacker can construct a malicious cross-chain transaction in Ontology and successfully package it on the poly chain.
- Although Relayer in Ethereum has a verification function, attackers can directly interact with the on-chain contract on Ethereum and directly execute malicious functions.
Ontology Relayer fully trusts cross-chain transactions from Ontology
Poly Network’s ont_relayer (https://github.com/polynetwork/ont-relayer) is responsible for monitoring cross-chain transactions on the Ontology chain and packaging them into the incoming Poly Chain.
- In Ontology Relayer, Side refers to Ontology Chain; Alliance refers to Poly Chain.
- CrossChainContractAddress is a smart contract natively numbered 09 on the Ontology chain.
In the above figure, when the Ontology Relayer starts, three Goroutines are opened, which are responsible for monitoring the cross-chain transactions of the Ontology Chain and the Poly Chain, and checking the status of the cross-chain transactions on the Poly Chain. In this report, we only focus on the 69 lines of code logic for monitoring Side.
In the above figure, the Ontology Relayer calls the RPC interface provided by the Ontology Chain (line 215, calls the SDK function GetSmartContractEventByBlock) to obtain the smart contract events triggered in the block; then lines 228 and 232 indicate that the Ontology Relayer only listens to the Ontology Chain. The makeFromOntProof event triggered by CrossChainContractAddress;
In the above figure, when processing cross-chain transactions on the Ontology Chain, the Ontology Relayer performs a total of five verifications, which are two RPC request verifications sent to the Ontology Chain (check 1 and check 4), and whether the three parameters are Empty check (check2, check3, and check5). These five verifications are all regular verifications, and the cross-chain transactions from the Ontology Chain are not semantically verified; lines 167 and 171 take out the transaction parameter information required for execution on the target chain (proof, auditPath); line 183 sends a transaction to Poly Chain;
After constructing the transaction on the Poly Chain, the Ontology Relayer initiates an RPC request to the Poly Chain to send the transaction (line 164, function call SendTransaction);
This Goroutine named ProcessToAliiance Check AndRetry only did the job of retransmitting failed transactions, and still did not do any semantic verification on cross-chain transactions from the Ontology Chain.
At this point, we can see that ont-relayer listens to all makeFromOntProof events triggered by CrossChainContractAddress from the Ontology Chain, and without any semantic verification, forwards the transaction to the Poly Chain. Any cross-chain transaction sent by anyone to Ontology will trigger the makeFromOntProof event of CrossChainContractAddress, so Ontology Relayer will forward all cross-chain transactions from Ontology to the Poly chain.
Invalid verification in Ethereum Relayer
The Ethereum Relayer is responsible for monitoring the Poly Chain and forwarding cross-chain transactions whose target chain is Ethereum to Ethereum.
The Ethereum Relayer starts a Goroutine to monitor the Poly Chain;
The Ethereum Relayer listens to all cross-chain transactions on the Poly Chain whose target chain is Ethereum (lines 275 to 278); Ethereum Relayer will verify whether the target contract of the cross-chain transaction is one of the contracts specified in config.TargetContracts, if not, it will not This cross-chain transaction will be sent to Ethereum (line 315).
Although the Ethereum Relayer does partial verification of cross-chain transactions on the Poly Chain, such as restricting the target contract, unlike the Poly Chain, anyone can send transactions to the EthCrossChainManager contract on Ethereum. In other words, the verification performed by the Ethereum Relayer here has no practical significance. As long as the cross-chain transaction containing the malicious payload is successfully packaged into the Poly Chain (although it is not forwarded to the Ethereum chain by the relay), then anyone can Directly use the packaged block data to send the payload to the Ethereum EthCrossChainManager contract and execute it (in this process, it can be verified by the merkle proof, because it is the poly chain block data that has been normally uploaded).
The attacker took advantage of the above two flaws to complete step one and step two in the attack process.
Write at the end
Through a complete combing and detailed analysis of the entire attack process, we believe that the incomplete verification of Relayer is the root cause of the attack. Other aspects (such as the use of hash conflicts, etc.) are more brilliant attack techniques. All in all, cross-chain verification and authentication is the key to cross-chain system security, and it deserves more efforts from the community.
Posted by:CoinYuppie，Reprinted with attribution to:https://coinyuppie.com/in-depth-analysis-of-key-steps-in-poly-network-attacks/
Coinyuppie is an open information publishing platform, all information provided is not related to the views and positions of coinyuppie, and does not constitute any investment and financial advice. Users are expected to carefully screen and prevent risks.