Back to all stories
Blogs
Incident Analysis
Omnipus Incident Analysis
9/25/2024
Omnipus Incident Analysis

Incident Summary

On 11 September 2024, Omnipus contracts were drained of ~$30k received during the presale of the OPUS token.

Omnipus 1

The attack exploited a vulnerability in which the contracts mistakenly believed that the attackers had sent too much ETH to the contract and then refunded them. Omnipus were quick to halt their contracts and refund presale participants.

Key Transactions

Attack Transactions

Arbitrum:

0xd72c36dedb6cdc3ec0ed0dbf41005126957c91bb1a2ef005253ba4db52cb34c5

Base:

0x89aef9cbdf71ea39bf751b86fc4ee9e6e0640c61a4b67847ad6b8530214ed486

Ethereum:

0xef3fc934bc7dcdc5d68c66ab1cba7ac572411a1671a0a7c88d1cbaa114ac3b70

Attack Flow and Vulnerability

Addresses

Attacker 1: 0x101723dEf8695f5bb8D5d4AA70869c10b5Ff6340 (Base / Arbitrum)

Attacker 2: 0x81b29Be344BEc9045E2c699205C6Ad6b30cc88E3 (Ethereum)

Vulnerability

Omnipus contract is used to stake and claim rewards earned from extracting bridging fee from the cross-chain transfers.

Omnipus 2

Image Source: https://omnipus.io/omnipus-whitepaper-2024.pdf

It functions as a message relayer to other staking / layerzero endpoint contracts. In part of this contract OAppSender.sol, payNative() function ensures the msg.value from the sender aligns with declared nativeFee().

However the check was commented out so that two messages can be sent in the same transaction.

image

Step by Step

The following analysis is based on Base transaction: 0x89aef9cbdf71ea39bf751b86fc4ee9e6e0640c61a4b67847ad6b8530214ed486

  1. The attacker called Omnipus.stakeRewards() which takes a fee argument that can be specified by the caller. MessageFee is a struct containing nativeFee and lzTokenFee.

Omnipus 3

The attacker specified a nativeFee of 11.879 ETH, which was the whole balance of the presale contract, and a lzTokenFee of zero.

Omnipus 4

Notably, the refundAddress was specified as the attacker’s address.

  1. The _lzSend function then called endpoint.send with a messageValue equal to the nativeFee.

Omnipus 5

As the payNative() check was overriden, the messageValue (the ETH being sent) was sent from the Omnipus contract without checking it had received any ETH from the attacker.

  1. The endpoint.send() function processes the ETH and a small amount of fees are deducted but as stated in the @dev comments (screenshot in step 2) any “excess” funds are sent back to the refundAddress.

Omnipus 6 The refundAddress in this instance was specified as the attacker’s address. They then received 11.878 ETH after fees.

Omnipus 7

Fund Flow

Wallet 0x101723dEf8695f5bb8D5d4AA70869c10b5Ff6340 bridged funds to a new address, 0x72c6E593562Ef4400c9E4f92C96dA11b93859BA2, before sending them to privacy service Railgun.

f0dc21d3-9ccd-4a84-97dd-fee36bfe7110

Following this incident, the project announced that it was on hold in its Telegram group.

Telegram

The Stats

Issues related to code vulnerabilities are quite frequent due to the complexities in smart contract programming. Having code audited is an important step in keeping contracts secure. So far in 2024, we have registered 142 incidents as a result of coding vulnerabilities, resulting in a loss of just under $116M.

image

In 2023, over the same period, we recorded 168 incidents with a loss of ~$283M. This difference demonstrates the efforts made to develop increasingly resilient smart contracts. To keep up to date on the latest incident alerts and statistics follow @certikalert on X, or read our latest analysis on certik.com.