Revisiting the Wormhole Attacks
Wormhole, which is also known as Einstein-Rosen bridge, is a speculative structure linking disparate points in space-time. In the world of blockchain, wormhole is used as the bridge between different chains (e.g., Solana and Ethereum. Users can transfer the tokenized assets across blockchains with wormhole.
On Februrary 2nd, 2022, Wormhole was hacked and the attacker managed to mint 120,000 wrapped Ether worth of $320 million, which is the second-largest loss after Poly Network in DeFi history.
2. How Wormhole works
Wormhole works by monitoring the messages emitted on each chain. The monitored message will be forwarded to the target chain so that a cross-chain communication protocol can be built.
The intuitive question is how to guarantee that the monitored message is trust. To solve this problem, Wormhole introduces 19 extra nodes, which are called guardians. The current guardian set can be checked in Wormhole Explorer. Each guardian can verify the monitored message independently and sign on message.
In Wormhole, the message is organized in VAA format. The VAA consists of two parts. One is the header, which collects the signatures from the guardians. The other one is the body, which contains the information for target chain, message payload, etc.
Once the sigantures from the guardians reach a consensus threshold, the VAA can be posted on chain.
In summary, guardians are responsible for the integrity of the transferred message.
3. Token Bridge
After introducing how the message is transferred between different chains, it will not be difficult to understand how the Token bridge, which is the main applications in wormhole, works.
To transfer tokens from chain A to chain B. Wormhole locks the tokens on A and mint them on B. This is the high level idea. In practical, this can be split into three steps. First, the tokens on chain A is locked. Second, the message that the tokens on chain A should be transferred into chain B is broadcasted. Third, chain B receives the message, the corresponding tokens are minted. Everything is done.
4. Solana Instructions
In Solana, a transaction consists of multiple instructions. Each instruction contains a program ID, accounts, and the data. The program ID represents the program (a smart contract) that will handle the instruction. The program will interpret the data and operates on the provided accounts.
5. The Wormhole Attack
In short, the attacker minted 120,000 ETH on Solana without locking any assets on Ethereum. The transaction is here.
Thus, the question is how the attacker is able to mint the 120,000 ETH on Solana. Let’s detail the steps. To mint the Token, instruction complete_wrapped is invoked. This instruction receives several addresses, and the third one is the address storing the signed message. Before minting the 120,000 ETH, the chain B (i.e., Solana) should receive the signed message (i.e., VAA) indicating that 120,000 ETH was locked in chain A (i.e., Ethereum).
To post the message,
post_vaa defined in post_vaa.rs is invoked. Consequently, an account will be created for storing the message. However,
post_vaa does not check the signatures from guardians. Instead,
verify_signaures defined in veryify_signatures.rs verifies the signatures.
The fourth account fed to
verify_signatures is the system instruction account. Now let's explore how
At line 103, function
load_instruction_at is invoked to load the previous executed instruction
secp_ix will invoke the Secp256k1 signature verification function. Thus, the
verify_signatures verify the signatures by checking the previous executed instruction
secp_ix. Now did you figure out everything? Function
load_instruction_at does not check where to load the instructions !!! You are expected to load the instruction from Sysvar:Instructions.
However, the fourth account of the attack transaction is 2tHS1cXX2h1KBEaadprqELJ6sV9wLoaSdX68FqsrrZRd rather than Sysvar:Instructions. In this case, the attacker successfully bypass the signature verification process. The wormhole thought the verification is passed and the message is posted to the chain, resulting in 120K ETH minted without locking anything!
Let’s look at a legal verification instruction. This transaction consists of two instructions. The first one invokes the Secp256k1 verification function while the second one invokes
verify_signatures instruction. Note the fourth account here is Sysvar:Instructions.
After minting the 120K ETH, the attacker is able to withdraw it back to Ethereum and change it into the other tokens to get the profit.
As mentioned in the repo, since version
load_instruction_at is not safe and the Sysvar accounts address is not checked. Instead,
load_instruction_at_checked is recommended.
7. Our Thought
- Developers should be very familiar with the external functions they used.
- Keep focusing on any important changes of the used libraries. If the library changes, the code using the library may need to be changed.
- The library maintainer should be aware the potential risks for specified changes and notify the whole community in time. Simply adding annotations may not work and is not enough.
- Your contract code needs to be audited if the versions of the library and the code are changed.