On July 2nd, 2023, Poly Network suffered a hack of what was initially reported to be 34 billion dollars. The main accuse of this is a compromise of private keys or a multi-signature service attack. The hacker exploited forged proofs to initiate withdrawal operations on the cross-chain bridge contracts across multiple chains.
Poly cross-chain ecosystem provides a platform for various chains to interact and transfer data along with carrying out cross-chain transactions.
To learn more about the Project, check out the official documentation.
Attacker Address: List of issued Poly Network Hackers
Attack Transactions: List of attack transactions
The root cause of the hack was not a logical bug but most likely a case of stolen/misused private keys.
To understand this, let’s first get the hang of Poly Network’s cross-chain interaction
Below is a poly’s sample cross-chain interaction between chains .
Notice that the DApp contract invoked by the users invokes the Cross-Chain Manager Contract
This contract allows tokens to be transferred from the source chain to the destination chain.
A Merkle Proof is required for the transaction’s legitimacy and to ensure that a transaction has been created and occurred on the relay chain.
This gets encoded with other arguments that together withdraw these tokens in the destination chain,
You can read more about the process from the official documentation.
The function verifyHeaderAndExecuteTx is responsible for the verification of the header and then the execution of the transaction.
This is the central access point, though, where users can “unlock” tokens on the destination chain that was “locked” in the source chain.
It takes 3 parameters
The transfer of the token from the original chain is what Poly called as “lock”, and the retrieval of the token is termed as “unlock”.
Poly has a set of Externally Owned Accounts. These EOAs need to sign the “unlock” event at the destination chain also includes other relevant data of the source chain, for the transaction to happen.
At this point, either
To verify the signature, this function is used
For the transaction to happen, the signature needs to be verified.
Upon investigation, it has been clear that the attacker correctly invoked this function.
It is worth noting that the list of keepers has remained constant for a long time and has not been modified.
The hypothesis of key compromise was further solidified when further inspection was done on the Merkle Prover function in hopes of finding a logical bug in the implementation of smart contract.
The above function takes 2 inputs
_auditPath – This will contain a leaf node followed by a path through the Merkle tree that acts as a proof of it’s existence
_root – This will take the state root of the Merkle tree
According to this implementation –
The hash of the leaf node needing to correspond to the state root hash for the proof to succeed implies that the integrity of the data stored within the leaf node is crucial for the verification process. If this requirement was not in place, the attacker could have potentially manipulated the implementation by exploiting the flexibility allowed by the verifier.
Without the condition that the hash of the leaf node must match the state root hash, the attacker could have provided a zero-length witness and an empty path as proof. In this scenario, the attacker could have crafted an artificial state root containing an unlock command to send tokens to themselves. By bypassing the need for a valid leaf node hash, the attacker would have been able to create fraudulent proof that falsely claimed ownership or authorisation for certain actions.
However, because the hash of the leaf node must correspond to the state root hash for the proof to succeed, it ensures the integrity and authenticity of the data stored within the leaf node. This requirement prevents attackers from manipulating the implementation by constructing artificial state roots and gaining unauthorised access or control over the system.
This means that the possibility of private key exploitation has more weight out of the two possibilities.
Despite this, there is no definitive proof that the private keys were stolen.
Possibilities of a rug pull or a compromised off-chain software running 3 out of 4 keepers still holds true for the scenario described above
In short,
Poly network had a simple 3 of 4 multisig arrangement.
The attacker used keys to sign proof that they owed BNB.
The header containing the state root was correctly signed by 3 out of 4 addresses. This leads us to the direction of a private key exploit.
The breakdown of assets minted by the hacker on different chains is as follows:
The attacker used multiple addresses to withdraw funds from cross-chain bridge contracts.
All cross-chain operations were directed towards chain ID 6.
These are the addresses that hold the majority of the portion of assets:
On Ethereum, assets worth $4.3 million were swapped for 674 ETH, with 1592 ETH unlocked, totalling 2267 ETH. The hacker still holds 10M BNB and 10B BUSD, which can’t be processed.
Here is a snippet of hacker’s wallet
July 2nd, 2023 06:47:20 PM UTC, the Project acknowledge the incident and announced it through their Twitter.
July 3rd, 2023 The project continues to suspend it’s services for the user as shared via Twitter.
Your weekly dose of Web3 innovation and security, featuring blockchain updates, developer insights, curated knowledge, security resources, and hack alerts. Stay ahead in Web3!