Maia DAO - Ulysses - zzzitron's results

Harnessing the power of Arbitrum, Ulysses Omnichain specializes in Virtualized Liquidity Management.

General Information

Platform: Code4rena

Start Date: 22/09/2023

Pot Size: $100,000 USDC

Total HM: 15

Participants: 175

Period: 14 days

Judge: alcueca

Total Solo HM: 4

Id: 287

League: ETH

Maia DAO

Findings Distribution

Researcher Performance

Rank: 158/175

Findings: 1

Award: $0.11

🌟 Selected for report: 0

🚀 Solo Findings: 0

Lines of code

https://github.com/code-423n4/2023-09-maia/blob/f5ba4de628836b2a29f9b5fff59499690008c463/src/RootBridgeAgent.sol#L175-L199 https://github.com/code-423n4/2023-09-maia/blob/f5ba4de628836b2a29f9b5fff59499690008c463/src/RootBridgeAgent.sol#L233-L271 https://github.com/code-423n4/2023-09-maia/blob/f5ba4de628836b2a29f9b5fff59499690008c463/src/VirtualAccount.sol#L85-L112

Vulnerability details

Impact

When a user wants to send funds from Root to Branch they call RootBridgeAgent.callOutAndBridge(). In the case of where this transferral of funds fails, the user can call RootBridgeAgent.retrySettlement(). However, an attacker can abuse the VirtualAccount from the victim by calling VirtualAccount.payableCall() in order to subsequently call RootBridgeAgent.retrySettlement() to claim the funds for themselves by specifying the _recipient to be themself. Thus the attacker steals funds from the user.

Note that the VirtualAccount from the victim user is allowed to call RootBridgeAgent.retrySettlement() because of line 248-250 in RootBridgeAgent:

// RootBridgeAgent.sol
248            if (msg.sender != address(IPort(localPortAddress).getUserAccount(settlementReference.owner))) {
249                revert NotSettlementOwner();
250            }

Proof of Concept

The POC below is doing the following:

  • Funds are first bridged from the AVAX branch to root.

  • Then subsequently bridged back from root to AVAX branch by MulticallRootRouter using RootBridgeAgent.callOutAndBridge(), which is failing.

  • Then the attacker calls VirtualAccount.payableCall() which calls RootBridgeAgent.retrySettlement() and specifying themself as recipient.

  • As a result the attacker gets minted the victim users funds on the branch.

https://gist.github.com/zzzitron/ce2a744c3cbe1e4028d650da683d7f13

Tools Used

Manual review

Consider adding the requiresApprovedCaller access control modifier to VirtualAccount.payableCall() so that the attacker can't abuse this function.

<!-- zzzitron H01 -->

Assessed type

Access Control

#0 - c4-pre-sort

2023-10-08T14:06:01Z

0xA5DF marked the issue as duplicate of #888

#1 - c4-pre-sort

2023-10-08T14:38:11Z

0xA5DF marked the issue as sufficient quality report

#2 - c4-judge

2023-10-26T11:29:37Z

alcueca marked the issue as satisfactory

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter