Platform: Code4rena
Start Date: 06/01/2022
Pot Size: $60,000 USDC
Total HM: 20
Participants: 33
Period: 7 days
Judge: LSDan
Total Solo HM: 9
Id: 67
League: ETH
Rank: 2/33
Findings: 6
Award: $5,270.10
π Selected for report: 3
π Solo Findings: 0
π Selected for report: camden
Also found by: cmichel, harleythedog
1594.3424 USDC - $1,594.34
camden
The impact of this is that users can get significantly more UST withdrawn than they would be alotted if they had done non-reentrant withdraw calls.
Here's an outline of the attack:
Assume the vault has 100 UST in it.
The attacker makes two deposits of 100UST and waits for them to be withdrawable.
The attacker triggers a withdraw one of their deposit positions.
The vault code executes until it reaches this point: https://github.com/code-423n4/2022-01-sandclock/blob/a90ad3824955327597be00bb0bd183a9c228a4fb/sandclock/contracts/Vault.sol#L565
Since the attacker is the claimer, the vault will call back to the attacker.
Inside onDepositBurned
, trigger another 100 UST deposit.
Since claimers.onWithdraw
has already been called, reducing the amount of shares, but the UST hasn't been transferred yet, the vault will compute the amount of UST to be withdrawn based on an unexpected value for _totalUnderlyingMinusSponsored
(300).
https://github.com/code-423n4/2022-01-sandclock/blob/a90ad3824955327597be00bb0bd183a9c228a4fb/sandclock/contracts/Vault.sol#L618
After the attack, the attacker will have significantly more than if they had withdrawn without reentrancy.
Here's my proof of concept showing a very similar exploit with deposit
, but I think it's enough to illustrate the point. I have a forge repo if you want to see it, just ping me on discord.
https://gist.github.com/CamdenClark/abc67bc1b387c15600549f6dfd5cb27a
Forge
Reentrancy guards.
Also, consider simplifying some of the shares logic.
#0 - naps62
2022-01-13T11:28:21Z
90.0579 USDC - $90.06
camden
In short, the NonUSTStrategy is vulnerable to attacks by flash loans on curve pools.
Here's an outline of the attack:
Here is my proof of concept: https://gist.github.com/CamdenClark/932d5fbeecb963d0917cb1321f754132
I can provide a full forge repo. Just ping me on discord.
Exploiting this line: https://github.com/code-423n4/2022-01-sandclock/blob/a90ad3824955327597be00bb0bd183a9c228a4fb/sandclock/contracts/strategy/NonUSTStrategy.sol#L135
Forge
Use an oracle
90.0579 USDC - $90.06
camden
The impact of this is that users can get significantly more shares than they would be alotted if they had done non-reentrant deposit calls.
Here's an outline of the attack:
Assume the vault has 100 UST in it.
The attacker triggers a deposit of 100UST.
The vault code executes until it reaches this point: https://github.com/code-423n4/2022-01-sandclock/blob/a90ad3824955327597be00bb0bd183a9c228a4fb/sandclock/contracts/Vault.sol#L484
Since the attacker is marked as a beneficiary, the vault will call back to the attacker.
Inside onDepositMinted
, trigger another 100 UST deposit.
Since the claim shares have already been minted, but the UST hasn't been transferred yet, the vault will give out 200 shares for this deposit, as opposed to 100, because _totalUnderlyingMinusSponsored
still has the unexpected value of 100.
https://github.com/code-423n4/2022-01-sandclock/blob/a90ad3824955327597be00bb0bd183a9c228a4fb/sandclock/contracts/Vault.sol#L618
After the attack, the attacker will have 300 of 400 total shares, but only have contributed 200 of 300 UST principal.
Here's my proof of concept. I have a forge repo if you want to see it, just ping me on discord. https://gist.github.com/CamdenClark/abc67bc1b387c15600549f6dfd5cb27a
Forge
Reentrancy guards.
Also, consider simplifying some of the shares logic.
#0 - r2moon
2022-01-07T16:14:49Z
camden
The impact of this is that a user could lock sponsorship money permanently and be unable to unlock it. No other users' funds are at risk.
Here's an outline of the attack:
The attacker makes a sponsor deposit. The attacker gets an ERC721 safe transfer call. The attacker uses this to reenter with an unsponsor on the token id used with the sponsor deposit. The token minted for the sponsor deposit is burned by unsponsor. The UST is transferred anyways.
Here's my proof of concept showing a very similar exploit with deposit
, but I think it's enough to illustrate the point. The main difference is that you would have to use the onERC721Received
call to perform reentrancy. I have a forge repo if you want to see it, just ping me on discord.
https://gist.github.com/CamdenClark/abc67bc1b387c15600549f6dfd5cb27a
Forge
Reentrancy guards.
#0 - r2moon
2022-01-07T16:16:42Z
π Selected for report: jayjonah8
Also found by: bugwriter001, camden, palina, sirhashalot
camden
Ideally use _safeMint everywhere and make sure you're safe against reentrancy.
https://github.com/code-423n4/2022-01-sandclock/blob/a90ad3824955327597be00bb0bd183a9c228a4fb/sandclock/contracts/vault/Claimers.sol#L63 https://github.com/code-423n4/2022-01-sandclock/blob/a90ad3824955327597be00bb0bd183a9c228a4fb/sandclock/contracts/vault/Depositors.sol#L53
#0 - r2moon
2022-01-11T15:22:11Z
15.442 USDC - $15.44
camden
Just a no-longer-relevant TODO
#0 - r2moon
2022-01-07T16:38:38Z
it does not involves any risk
#1 - dmvt
2022-01-28T15:02:41Z
duplicate of #96
π Selected for report: camden
590.4972 USDC - $590.50
camden
Just a confusing comment here: "Unlike withdrawToVault
", but this is the withdrawToVault function.
#0 - r2moon
2022-01-07T15:58:54Z
agree with this issue, but this is not a risk.
#1 - dmvt
2022-01-28T15:05:22Z
1 β Low: Low: Assets are not at risk. State handling, function incorrect as to spec, issues with comments.