Sandclock contest - cccz's results

The Next Generation of Wealth Creation.

General Information

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

Sandclock

Findings Distribution

Researcher Performance

Rank: 23/33

Findings: 3

Award: $195.56

🌟 Selected for report: 0

πŸš€ Solo Findings: 0

Findings Information

🌟 Selected for report: camden

Also found by: Ruhum, WatchPug, cccz, cmichel, danb, defsec, harleythedog, hyh, kenzo, leastwood, palina, pauliax, pmerkleplant, ye0lde

Labels

bug
duplicate
3 (High Risk)

Awards

90.0579 USDC - $90.06

External Links

Handle

cccz

Vulnerability details

Impact

There is no slippage control on _swapUstToUnderlying of NonUSTStrategy.sol, which expose strategy to sandwich attack.

And since finishRedeemStable lacks access control, anyone can do a sandwich attack by calling the _swapUstToUnderlying function.

function finishRedeemStable(uint256 idx) public override(BaseStrategy) { super.finishRedeemStable(idx); _swapUstToUnderlying(); } ... function _swapUstToUnderlying() internal { uint256 ustBalance = _getUstBalance(); if (ustBalance > 0) { // slither-disable-next-line unused-return curvePool.exchange_underlying(ustI, underlyingI, ustBalance, 0); } }

Proof of Concept

https://github.com/code-423n4/2022-01-sandclock/blob/main/sandclock/contracts/strategy/NonUSTStrategy.sol#L107-L110

https://github.com/code-423n4/2022-01-sandclock/blob/main/sandclock/contracts/strategy/NonUSTStrategy.sol#L90-L96

Tools Used

Manual analysis

Replace 0 in the parameter of exchange_underlying with minout

#0 - naps62

2022-01-11T18:38:41Z

duplicate of #8

#1 - dmvt

2022-01-27T11:42:04Z

duplicate of #7

Findings Information

Awards

90.0579 USDC - $90.06

Labels

bug
duplicate
3 (High Risk)

External Links

Handle

cccz

Vulnerability details

Impact

The mint function of the Depositors contract uses the _safeMint function of the ERC721 contract. And there is a reentrancy vulnerability in the _safeMint function

function _safeMint( address to, uint256 tokenId, bytes memory _data ) internal virtual { _mint(to, tokenId); require( _checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer" ); } ... function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory _data ) private returns (bool) { if (to.isContract()) { try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { return retval == IERC721Receiver.onERC721Received.selector;

The deposit function of the Vault contract will call the _createDeposit and _createClaim functions, and the mint function of the Depositors contract will be called in the _createClaim function. Because the _transferAndCheckUnderlying function will be called after the mint function to increase the underlying tokens in the contract. The user can reenter the deposit function in the mint function. In the _createDeposit function, since the underlying tokens are less than normal, the localTotalUnderlying variable will be smaller. Later, when the mint function of the Claimers contract is called in the _createClaim function, the user will get more share tokens.

function deposit(DepositParams calldata _params) external { _createDeposit(_params.amount, _params.lockedUntil, _params.claims); _transferAndCheckUnderlying(_msgSender(), _params.amount); } ... function _createDeposit( uint256 _amount, uint256 _lockedUntil, ClaimParams[] calldata claims ) internal { if (_lockedUntil == 0) _lockedUntil = block.timestamp + minLockPeriod; else require( _lockedUntil >= block.timestamp + minLockPeriod, "Vault: lock time is too small" ); uint256 localTotalShares = totalShares(); uint256 localTotalUnderlying = totalUnderlyingMinusSponsored(); uint256 pct = 0; for (uint256 i = 0; i < claims.length; ++i) { ClaimParams memory data = claims[i]; _createClaim( _depositGroupIds.current(), _amount, _lockedUntil, data, localTotalShares, localTotalUnderlying ); pct += data.pct; } ... function _createClaim( uint256 _depositGroupId, uint256 _amount, uint256 _lockedUntil, ClaimParams memory _claim, uint256 _localTotalShares, uint256 _localTotalPrincipal ) internal { uint256 amount = _amount.percOf(_claim.pct); uint256 newShares = _computeShares( amount, _localTotalShares, _localTotalPrincipal ); uint256 claimerId = claimers.mint( _claim.beneficiary, amount, newShares ); uint256 tokenId = depositors.mint(

Proof of Concept

https://github.com/code-423n4/2022-01-sandclock/blob/main/sandclock/contracts/vault/Depositors.sol#L53 https://github.com/code-423n4/2022-01-sandclock/blob/main/sandclock/contracts/Vault.sol#L160-L163 https://github.com/code-423n4/2022-01-sandclock/blob/main/sandclock/contracts/Vault.sol#L438 https://github.com/code-423n4/2022-01-sandclock/blob/main/sandclock/contracts/Vault.sol#L476

Tools Used

Manual analysis

Use the _mint function of the ERC721 contract in the mint function of the Depositors contract.

#0 - r2moon

2022-01-07T15:46:06Z

Findings Information

🌟 Selected for report: Dravee

Also found by: 0x1f8b, camden, cccz, certora, defsec, jayjonah8, kenzo, p4st13r4, palina, pauliax, robee

Labels

bug
duplicate
1 (Low Risk)
disagree with severity

Awards

15.442 USDC - $15.44

External Links

#0 - r2moon

2022-01-11T16:06:13Z

#1 - dmvt

2022-01-28T14:42:24Z

duplicate of #96

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