The Analysis and Q&A Of Poly Network Being Hacked

On August 10, 2021, according to the news from the SlowMist Zone, the cross-chain interoperability protocol Poly Network was attacked by hackers. The SlowMist security team immediately cut into the analysis and shared the analysis results as follows.

The Object of Attack

The following are the specific addresses involved in this attack:

The Root Cause of the Attack

2. The target chain did not check the parsed target call contract and call parameters.

3. The owner of the `EthCrossChainData` contract is `EthCrossChainManager`.

4. `bytes4(keccak256(abi.encodePacked(_method,“(bytes,bytes,uint64)”)))` can be collided by hash.

The Details of the Attack

In this attack, the attacker takes two steps to complete the attack.

First, the attacker initiated a cross-chain transaction by calling the `crossChain` function on other chains to construct data.

EthCrossChainManager.crossChain

It is clear from the figure above that this function is only used to help users construct `makeTxParam` and store the constructed hash for subsequent verification. It does not impose any restrictions on the cross-chain operation parameters passed in by the user, so the attacker can completely synchronize the data to the Poly Chain by the Relayer by constructing any data it wants to construct, and synchronize it to the Ethereum Relayer through the Poly Chain.

Then the Relayer on Ethereum verifies the authenticity of the cross-chain information by calling the `verifyHeaderAndExecuteTx` function in the `EthCrossChainManager` contract to submit the block header information.

EthCrossChainManager.verifyHeaderAndExecuteTx

From the above code, we can see that it first deserializes the block header to resolve the specific information that needs to be verified. The `getCurEpochConPubKeyBytes` function is then called to get the Keeper public key from the `EthCrossChainData` contract, and the Keeper address is obtained through the `deserializeKeepers` function.

Next, the `ECCUtils.verifySig` will be used to verify whether the signature is Keeper or not. From the following code, we can find that the `verifySig` function will cut out the signer’s `v r s`. And get the signer address through the `ecrecover` interface, then call the `containMAddresses` function to compare whether the signer is a Keeper’s or not. The check can be passed as long as the number of Keeper signatures meets the requirement, which is `n-(n-1) / 3)` passed in by the ‘EthCrossChainManager’ contract.

The signature is then verified by the Eccutils. merkleProve, which can be passed by normal cross-chain operations. The transaction is then checked for duplication and the validated data is stored. Just make sure not to submit repeatedly.

Last but not least, it executes the constructed data through an internal call to the _executeCrossChainTx function.

We can see that the _executeCrossChainTx function does not check the _toContract, _method and other parameters, and directly executes the transaction in the way of _toContract.call.

From the data on the chain, the owner of the `EthCrossChainData` contract is the `EthCrossChainManager` contract, and previously we knew that the public key of the relay chain validator (i.e. Keeper) exists in the `EthCrossChainData` contract, and this contract exists in `putCurEpochConPubKeyBytes ` function which can directly modify the Keeper public key.

After the above analysis, the result is very clear. The attacker only needs to initiate a cross-chain operation transaction normally through `crossChain` on other chains. The purpose of this transaction is to call the `putCurEpochConPubKeyBytes` function of the `EthCrossChainData` contract to modify the Keeper role. Then, through the normal cross-chain process, Keeper parses the target contract and call parameters of the user request and constructs a new transaction to submit to Ethereum. This is essentially just a normal cross-chain operation, so it can directly pass the Keeper check and Merkel root check. Finally, the operation of modifying the Keeper was successfully executed.

But notice that the `putCurEpochConPubKeyBytes` function is defined as

function putCurEpochConPubKeyBytes(bytes calldata curEpochPkBytes) external returns (bool);

And the execution of the `_executeCrossChainTx` function is defined as

abi.encodePacked(bytes4(keccak256(abi.encodePacked(_method, “(bytes,bytes,uint64)”)))

Under normal circumstances, we can know that the `_method` passed in the function signature of these two functions is `putCurEpochConPubKeyBytes`, which must be completely different, so the `_toContract.call` cannot theoretically call the `putCurEpochConPubKeyBytes` function.

But `_method` is controllable by the attacker, it is completely possible to enumerate various character combinations to obtain the same function signature as calling the `putCurEpochConPubKeyBytes` function, which requires only the first 4 bytes to be enumerated. The SlowMist security team also tried hash collision, as shown below:

It can be seen that the first four bytes are consistent with the `putCurEpochConPubKeyBytes` function

So far we have recovered the attacker’s attack details. By analyzing the data on the chain, we can find that the attacker replaced Keeper with 0xA87fB85A93Ca072Cd4e5F0D4f178Bc831Df8a00B

Finally, the attacker only needs to sign with the replaced Keeper address to transfer the assets under management by calling the `LockProxy` contract through all checks and executions.

The Process of the Attack

2. Submit data in the target chain normally using the official Relayer and replace Keeper.

3. The attacker uses the replaced Keeper address to sign the operation and submits it to ‘EthCrossChainManager’ for verification.

4. Verify that the Keeper is the address that has been replaced by the attacker. If yes, transfer the asset to the address specified by the attacker.

5. Profit and leave.

The Analysis Process of MistTrack

The Analysis of Capital Flow:

Event sorting: (As of 05:00 UTC August 11)

On BSC: Hacker address 1, the hacker added nearly 120 million U.S. dollars (including about 32.1 million BUSD and about 87.6 million USDC) of liquidity to the Curve fork project Ellipsis Finance. Currently, the market is still making no more transactions.

On Polygon: Hacker address 2, there is no more transactions in funds.

On Ethereum:

1) Hacker address 3, there was only one transaction that transferred out 13.37 ETH to address 0xf8b5c45c6388c9ee12546061786026aaeaa4b682

2) After the hacker added more than 97.06 million U.S. dollars (including 670,000 DAI and 96.38 million USDC) liquidity to Curve , the liquidity was canceled and 96.38 million USDC and 670,000 DAI were exchanged for 96.94 million DAI. The funds remained at address 3. Currently, 33.43 million USDT has been frozen by Tether.

Q&A:

A: The `eccd` contract is authenticated, and only the owner is allowed to call `putCurEpochConPubKeyBytes` to change the keeper. Because the owner of the `eccd` contract is `eccm`, the value of the keeper can be changed through `eccm`.

Q: Why is it possible to replace a Keeper’s transaction with a signature transaction?

A: Verified based on toContract, the original keeper may have signed it as a normal cross-chain transaction, but it is a transaction to replace the keeper.

Q: Why can the attacker bypass the limitation of the code bytes4(keccak256(abi.encodePacked(_method, “(bytes,bytes,uint64)”))) and then execute the putCurEpochConPubKeyBytes(bytes) function?

A: The function signature uses keccak-256 for hash, and then takes the previous 4bytes. In this case, it is easier to be collided by hash.

Q: How is the hacker’s keeper replacement transaction signed by the old keepers?

A: Keepers is a chain Replayer that will sign all cross-chain requests of normal users. When a user initiates a cross-chain transaction on BSC, keepers will parse the target contract and call parameters requested by the user, construct a new transaction and submit it to Ethereum, and use the eccm contract to call the target contained in the user transaction on Ethereum contract. The hacker’s replacement of the keeper’s transaction is essentially a normal cross-chain transaction, except that the target contract called is the eccd contract, and the calling parameter is to replace the keeper, so it can be signed normally.

Summary

SlowMist AML’s MistTrack anti-money laundering tracking system will continue to monitor the transfer of stolen funds, block all wallet addresses controlled by attackers, and remind exchanges and wallets to strengthen address monitoring to prevent related malicious funds from flowing into the platform. In addition, special thanks to the teams such as Hoo, Poly Network, Huobi ZLabs, ChainNews, WePiggy, TokenPocket, Bibox, OkLink and many individual partners for synchronizing relevant attacker information with the SlowMist security team on time under the premise of compliance, and buying valuable time for tracking attacker.

At present, with the efforts of many parties, hackers have begun to return funds one after another.

Focuses on Blockchain Ecosystem Security, has served Huobi/OKEx/Binance/imToken, nearly a thousand commercial customers in total.