Closed code423n4 closed 2 years ago
This issue seems similar to a project forking another project and rugging with different code. Users should confirm the basket they are interacting with is a legitimate basket created from the correct factory, similar to using a uniswap pool or router contract.
Agree with the sponsor, there is no reason why users would interact with a malicious fork of these contracts.
Handle
broccolirob
Vulnerability details
A malicious "publisher" can deploy a manipulated spoof of
Factory.sol
that includes adelegatecall
to the realFactory.sol
contract for invokingcreateBasket()
.https://github.com/code-423n4/2021-12-defiprotocol/blob/main/contracts/contracts/Factory.sol#L97-L120
When
newAuction.initialize(address(newBasket), address(this));
is run, the spoofed version's address will be passed to the newly clonedAuction
contract instead of the real one. Also, wheninitialize()
is called on the newly clonedBasket
contract,msg.sender
will be equal to the spoofed contract, so that factory will be set incorrectly as well.Impact
The
Auction
contract uses its factory reference for important calculations inbondForRebalance()
andsettleAuction()
. https://github.com/code-423n4/2021-12-defiprotocol/blob/main/contracts/contracts/Auction.sol#L65-L67factory.bondPercentDiv()
can return0
so that bonds are free.https://github.com/code-423n4/2021-12-defiprotocol/blob/main/contracts/contracts/Auction.sol#L97-L111
factory.auctionMultiplier()
andfactory.auctionDecrement()
can be manipulated to effect theibRatio
variable in the basket, setting it very high. This would allow the malicious "publisher" to burn a small number of basket tokens in exchange for all underlying tokens, thus draining the actual tokens provided by other basket holders.https://github.com/code-423n4/2021-12-defiprotocol/blob/main/contracts/contracts/Basket.sol#L144-L145
handleFees()
in theBasket
contract can be manipulated to return0
for theownerSplit()
or, simply return the malicious "publisher" address as the owner.Since view functions have access to
msg.sender
, the spoof contract can return certain values selectively. It might function normally for all typical users, giving the appearance everything is fine, but then return incorrect values whenmsg.sender == publisher
.Proof of Concept
proposeBasketLicense()
on realFactory
.MalloryFactory.sol
that conforms to theIFactory
interface and mirrors the realFactory.sol
contract's methods and state values.attack()
method that delegates a call to the real factory.address(realFactory).delegatecall(abi.encodeWithSignature("createBasket(uint256)", proposalId));
.publishNewIndex()
flow.bondForRebalance()
.transfer
to send them directly to the basket contract.settleAuction()
.factory.auctionMultiplier()
is called on shadow factory and it see'smsg.sender == address(mallory)
so it returns a large number.factory.auctionDecrement()
is called on shadow factory and returns0
.basket.updateIBRatio()
sets basket's ratio to value, much higher than it should be.burn()
to drain underlying tokens.Tools Used
Manual review and Hardhat.
Recommended Mitigation Steps
Create an immutable variable that is set to the
Factory
contract's address when it gets deployed. Then, inline or in a modifier, check to make sure thataddress(this) == originalAddress
.