code-423n4 / 2022-03-lifinance-findings

6 stars 4 forks source link

Anyone can use all token hold by Li.Fi contract #123

Closed code423n4 closed 2 years ago

code423n4 commented 2 years ago

Lines of code

https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Libraries/LibAsset.sol#L59-L70 https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Libraries/LibSwap.sol#L33-L35 https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Facets/GenericSwapFacet.sol#L28-L30

Vulnerability details

Impact

Any malicious user can call LibSwap.sol execute to swap all token balance hold by Li.Fi contract to another token. Which can be used to transfer all token hold by Li.Fi contract to another address.

Proof of Concept

This only show the most simple, direct way to withdraw ERC20 token from contract. Consider Li.Fi already implement Whitelist function and token whitelist.

Do this again with USDC and USDT to withdraw all USDC leftover.

Note: there are many more ways to exploit this using the same generic LibSwap.swap function. As long as Li.Fi contract hold ERC-20 token, there is no safe or fair way to prevent attacker make unfair trade with token.

Tools Used

Manual

Recommended Mitigation Steps

The best fix from my experience is to remove LibSwap.sol and restart from scratch. Try different approach instead of generic arbitrary call to mitigate this. Spending time on securing LibSwap.sol is simply not worth it.

From LibSwap documentation here, A library used to perform multiple swaps given an array of DEX addresses and calldata. This makes it very flexible but also dangerous in that it allows arbitrary calls to any contract

This is a wrong approach with diamond facet. Diamond facets are already flexible, no need for arbitrary call. Diamond allow adhoc implementation for each chain, different contracts which give flexibility to implement new features or new DEX. Sharing all swap logic into one single function and reuse it everywhere is not a good idea.

Current implementation, Swapper.sol raw call in loop, is no different from a multicall function to different DEX to swap and then cross bridge. Might as well use a multicall into facets function instead of facet use same lib function. It is much simpler structure wise.

For flashloan swap, as long as Li.Fi not check correct amount of token being swapped, attacker can use other people token like token hold by LiFi contract.

H3xept commented 2 years ago

Duplicate of #66

We are aware that the contract allows users to use latent funds, although we disagree on it being an issue as no funds (ERC20 or native) should ever lay in the contract. To make sure that no value is ever kept by the diamond, we now provide refunds for outstanding user value (after bridges/swaps).