Background

On March 14, 2025, we detected an attack on the BNB Smart Chain project H2O . The attack hash was:

https://bscscan.com/tx/0x729c502a7dfd5332a9bdbcacec97137899ecc82c17d0797b9686a7f9f6005cb7

https://bscscan.com/tx/0x994abe7906a4a955c103071221e5eaa734a30dccdcdaac63496ece2b698a0fc3

The project attacked was H2O, and the attack caused a total loss of 22,000 USD.

Attack and incident analysis

In the first attack, the attacker first borrowed 100,000 USDT from PancakeSwapV3 Pool using flashloan as the initial capital for the attack.

Zero Hour Technology || Analysis of the H2O attack

Subsequently, the initial borrowed funds were used to exchange 66,439,209 H2O in the USDT-H2O PancakeSwap Pair.

Zero Hour Technology || Analysis of the H2O attack

The attacker then frequently transferred H2O to the PancakeSwap Pair USDT-H2O, causing an imbalance between the USDT reserve and the H2O reserve in the Pair, and then used skim to balance reserve0 and reserve1 in the Pair to carry out the attack. The vulnerability of H2O appears in the transfer function, and we can see the specific implementation of the transfer function.

Zero Hour Technology || Analysis of the H2O attack

The problem specifically occurs in the function. When from is a PancakeSwap Pair, the _calulate function is called. Since the attacker uses the imbalance between Reserve0 and Reserve1 of the Pair to call skim to transfer to itself, the sender of the transfer is the Pair address. Next, let's take a look at the specific implementation of this function.

Zero Hour Technology || Analysis of the H2O attack

The logic of this function is very simple. It dynamically sets the reward rate (1%-5%, the lower the balance, the lower the rate) according to the balance of H2O tokens held by the contract itself, and distributes H2 or O2 tokens to users in proportion through on-chain random numbers. When a user holds at least 10 H2 and 5 O2, he can destroy tokens in a 2:1 ratio (simulating the chemical reaction 2H₂+O₂→2H₂O) and redeem the H2O tokens in the contract. The actual redemption amount is limited by the contract balance.

The logic of the contract to generate random numbers on the chain is as follows:

Zero Hour Technology || Analysis of the H2O attack

Calculated based on blocktime, blocknumber and keccak256 of msg.sender. In the first attack, since the attacker did not have H2 Token and O2 Token, 169,731,921 O2 Token were obtained in this attack. Next, the attacker only needs to make getRandomOnchain()%2 == 1 to complete the attack. The attacker then made three more attempts, but the first two getRandomOnchain()%2 were both 0, resulting in the failure of the attack. The fourth attempt was the final one.

Zero Hour Technology || Analysis of the H2O attack

In the fourth attack, the attacker first borrowed 100,000 USDT from PancakeSwapV3 Pool using flashloan as the initial capital for the attack.

Zero Hour Technology || Analysis of the H2O attack

Subsequently, the initial borrowed funds were used to exchange 66,439,209 H2O in the USDT-H2O PancakeSwap Pair.

Zero Hour Technology || Analysis of the H2O attack

The attacker then frequently transferred H2O to the PancakeSwap Pair USDT-H2O, causing an imbalance between the USDT reserve and H2O reserve in the Pair, and then used skim to balance reserve0 and reserve1 in the Pair to carry out the attack.

Zero Hour Technology || Analysis of the H2O attack

According to our analysis above, getRandomOnchain()%2 is 1 in this attack, so H2O will mint H2Token. Because the attacker used getRandomOnchain()%2 to be 0 during the first attack, a large number of O2 Tokens were minted. Therefore, H2O burned H2 and O2 and transferred its own H2O to the attacker.

Finally, the attacker exchanged 122,820 USDT with the H2O that came out of thin air, and after paying off the 100,000 USDT flash loan and 50 USDT interest, he finally made a profit of 22,770 USDT.

Summarize

The main cause of this vulnerability is that when the H20 Token contract designed the economic model of buying from PancakeSwap Pair, it did not consider that skim could also achieve the same purpose when modifying the ERC20 transfer function, resulting in the attacker using skim to obtain a large amount of incentives out of thin air. It is recommended that the project party should conduct multi-party verification when designing the economic model, price calculation mechanism and code operation logic, and try to select multiple audit companies for cross-audit when auditing the contract before it goes online.