Platform: Code4rena
Start Date: 23/06/2023
Pot Size: $60,500 USDC
Total HM: 31
Participants: 132
Period: 10 days
Judge: 0xean
Total Solo HM: 10
Id: 254
League: ETH
Rank: 50/132
Findings: 3
Award: $171.84
🌟 Selected for report: 0
🚀 Solo Findings: 0
143.4901 USDC - $143.49
https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/token/PeUSDMainnetStableVision.sol#L129 https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/token/PeUSDMainnetStableVision.sol#L132
Maliciuos user can use executeFlashloan()
and steal all available EUSD tokens.
Here is a vulnerable function:
function executeFlashloan(FlashBorrower receiver, uint256 eusdAmount, bytes calldata data) public payable { uint256 shareAmount = EUSD.getSharesByMintedEUSD(eusdAmount); EUSD.transferShares(address(receiver), shareAmount); receiver.onFlashLoan(shareAmount, data); bool success = EUSD.transferFrom(address(receiver), address(this), EUSD.getMintedEUSDByShares(shareAmount)); require(success, "TF"); uint256 burnShare = getFee(shareAmount); EUSD.burnShares(address(receiver), burnShare); emit Flashloaned(receiver, eusdAmount, burnShare); }
It allows to pass an arbitrary bytes calldata data
as one of the arguments. Later it calls receiver
, that can be PeUSDMainnetStableVision
contract itself, with a malicious data
.
... receiver.onFlashLoan(shareAmount, data); ...
So malicious user can pass next arguments:
executeFlashloan( PeUSDMainnetStableVision , 1, abi.encodeWithSignature("approve(address,uint256)", attacker, amount));
Step by step:
data
;Right after that hacker will be approved and be able to transfer all EUSD tokens from the contract.
Sorry for no tests included. I was little bit confused with setting up all params.
P.S. The same issue was in Damn Vulnerably DeFi Challenges (Truster).
Manual review.
You can provide an additional checks to prohibit calls for approve functions or receiver should not be the same as PeUSDMainnetStableVision
contract.
Other
#0 - c4-pre-sort
2023-07-04T14:00:02Z
JeffCX marked the issue as primary issue
#1 - c4-sponsor
2023-07-14T09:45:27Z
LybraFinance marked the issue as sponsor confirmed
#2 - c4-judge
2023-07-26T00:30:05Z
0xean marked the issue as satisfactory
#3 - c4-judge
2023-07-28T19:51:56Z
0xean marked issue #769 as primary and marked this issue as a duplicate of 769
🌟 Selected for report: alexweb3
Also found by: D_Auditor, DedOhWale, DelerRH, LuchoLeonel1, Musaka, Neon2835, Silvermist, Timenov, TorpedoPistolIXC41, adeolu, cartlex_, hals, josephdara, koo, lanrebayode77, mahyar, mladenov, mrudenko, pep7siup, zaevlad, zaggle
18.4208 USDC - $18.42
https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/configuration/LybraConfigurator.sol#L85 https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/configuration/LybraConfigurator.sol#L90 https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/governance/GovernanceTimelock.sol#L25 https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/governance/GovernanceTimelock.sol#L29
Core functions are unprotected due to a missing require check in the modifier, so malicious user can call them and break the protocol.
LybraConfigurator contract has two modifiers that should check the specific role of the user to have an ability to call some core functions. For example:
modifier onlyRole(bytes32 role) { GovernanceTimelock.checkOnlyRole(role, msg.sender); _; }
However checkOnlyRole()
only returns a bool whether a user has or has not a role.
function checkOnlyRole(bytes32 role, address _sender) public view returns(bool){ return hasRole(role, _sender); } AccessControl.sol function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; }
So all functions that should be protected by these modifiers stay unprotected to anyone.
Manual review.
Developers should add a require check to the modifiers, like:
modifier onlyRole(bytes32 role) { require(GovernanceTimelock.checkOnlyRole(role, msg.sender), "Not a role"); _; }
Access Control
#0 - c4-pre-sort
2023-07-08T15:20:15Z
JeffCX marked the issue as duplicate of #704
#1 - c4-judge
2023-07-28T15:24:22Z
0xean changed the severity to 3 (High Risk)
#2 - c4-judge
2023-07-28T17:18:56Z
0xean marked the issue as satisfactory
🌟 Selected for report: 0xnev
Also found by: 0xRobocop, 0xbrett8571, 0xkazim, 0xnacho, 3agle, 8olidity, ABAIKUNANBAEV, Bauchibred, Co0nan, CrypticShepherd, D_Auditor, DelerRH, HE1M, Iurii3, Kaysoft, MrPotatoMagic, RedOneN, RedTiger, Rolezn, SanketKogekar, Sathish9098, Timenov, Toshii, Vagner, bart1e, bytes032, codetilda, devival, halden, hals, kutugu, m_Rassska, naman1778, nonseodion, seth_lawson, solsaver, squeaky_cactus, totomanov, y51r, yudan, zaevlad
9.931 USDC - $9.93
https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L67 https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L181 https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/interfaces/IPeUSD.sol#L11 https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/token/PeUSD.sol#L8 https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L200
Users will not be able to mint or burn PeUSD tokens and use core functions of the protocol.
When a user want to deposit his assets via LybraPeUSDVaultBase contract he calls depositAssetToMint
function that has internal call to _mintPeUSD()
.
MintPeUSD should forward a call to a mint function of PeUSD contract:
... PeUSD.mint(_onBehalfOf, _mintAmount); ...
However that specific mint()
function can be found only in interface contract, but not in the main PeUSD contract. So any call will revert.
The same situation with a burn function when user wants to get his colateral back via repay()
. Here is a call to the absence function:
... PeUSD.burn(_provider, amount - totalFee); ...
Manual review
Provide a mint()
and burn()
functions with required logic for that token. Base on the developers needs it can be similar to EUSD token.
ERC20
#0 - c4-pre-sort
2023-07-08T19:12:40Z
JeffCX marked the issue as duplicate of #958
#1 - c4-judge
2023-07-28T18:21:13Z
0xean changed the severity to QA (Quality Assurance)
#2 - c4-judge
2023-07-28T18:21:48Z
0xean marked the issue as grade-b