Platform: Code4rena
Start Date: 06/12/2022
Pot Size: $36,500 USDC
Total HM: 16
Participants: 119
Period: 3 days
Judge: berndartmueller
Total Solo HM: 2
Id: 189
League: ETH
Rank: 40/119
Findings: 2
Award: $88.79
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: ladboy233
Also found by: 0x1f8b, Matin, UniversalCrypto, gzeon, karanctf, minhquanym, obront, rvierdiiev, seyni, slvDev, yixxas
57.6274 USDC - $57.63
In the OpenEdition
contract, the user can buy a different amount than expected.
The following proof of concept wants to demonstrate how if a user buys (16777215) + 2
with a price of 1, it should cost 16777217
in ether, but instead they will buy only one for one satoshi, which is incorrect. to what was said buy(16777217)
Keep in mind that the version of solidity used, despite being greater than 0.8
, does not prevent integer overflows during casting, it only does so in mathematical operations.
It is necessary to safely convert between the different numeric types. The problem lies in an unsafe cast on uint24 quantity = uint24(_quantity);
.
contract POCTest is EscherTest { OpenEdition public sale; OpenEditionFactory public openSales; OpenEdition.Sale public openSale; function setUp() public virtual override { super.setUp(); openSales = new OpenEditionFactory(); openSale = OpenEdition.Sale({ price: 1, // <- PRICE 1 currentId: uint24(1), edition: address(edition), startTime: uint96(block.timestamp), saleReceiver: payable(address(69)), endTime: uint96(block.timestamp + 1 days) }); } function test_POC() public { sale = OpenEdition(openSales.createOpenEdition(openSale)); edition.grantRole(edition.MINTER_ROLE(), address(sale)); (uint72 price, uint24 currentId, address edition, uint96 startTime, address payable saleReceiver, uint96 endTime) = sale.sale(); assertEq(currentId, 1); assertEq(address(sale).balance, 0); sale.buy{value: 1}((16777215) + 2); // Amount overflow assertEq(address(sale).balance, 1); (price, currentId, edition, startTime, saleReceiver, endTime) = sale.sale(); assertEq(currentId, 2); } }
#0 - c4-judge
2022-12-10T17:11:51Z
berndartmueller marked the issue as duplicate of #369
#1 - c4-judge
2023-01-03T13:53:28Z
berndartmueller marked the issue as satisfactory
🌟 Selected for report: 0xSmartContract
Also found by: 0x1f8b, 0x4non, 0xA5DF, 0xNazgul, 0xRobocop, 0xfuje, Bnke0x0, HollaDieWaldfee, Lambda, RaymondFam, TomJ, _Adam, adriro, ajtra, carrotsmuggler, cccz, danyams, gasperpre, hansfriese, helios, immeas, joestakey, ladboy233, nameruse, obront, oyc_109, rvierdiiev, saian, sakshamguruji, seyni, slvDev, yixxas, zaskoh
31.1555 USDC - $31.16
tokenURI
logicThe tokenURI
method does not check that _tokenId
exists, so it might return uris for invalid tokens. This behavior should be copied from the logic of Open Zeppelin where they check if the token was minted before returning a valid result.
Affected source code:
initialize
methodThe methods that inherit the Base
contract have a method that is susceptible to front-running attacks, which allows an attacker to obtain ownership and take advantage of the contract as soon as it is deployed, it is convenient to protect this type of initializations making sure that only a specific sender can call said method.
In the case of the 'Generative' contract, the attacker can call setScriptPiece
with arbitrary data and exploit or combine other attacks.
Affected source code:
If the owner calls cancel
, it will not pass any fees to feeReceiver
, so it is possible for the owner to avoid this commitment to the fee manager. All this fees will be transfered to saleReceiver
instead of the feeReceiver
as was agreed during the deployment.
Affected source code:
Some contracts do not implement good upgradeable logic.
Upgrading a contract will need a __gap
storage in order to avoid storage collisions.
Proxied contracts MUST include an empty reserved space in storage, usually named __gap
, in all the inherited contracts.
For example, the contract Governed
or GraphUpgradeable
are inherited by upgradeable contracts, but these contracts don't have a __gap
storage, so if a new variable is created it could lead to storage collisions that will produce a contract disaster, including loss of funds.
Reference:
Affected source code:
Recommended Mitigation Steps:
uint256[50] private __gap;
to all upgradable contracts.Keep in mind that the version of solidity used, despite being greater than 0.8
, does not prevent integer overflows during casting, it only does so in mathematical operations.
It is necessary to safely convert between the different numeric types.
Recommendation:
Use a safeCast from Open Zeppelin.
uint80 price = uint80(getPrice()) * r.amount;
Affected source code:
abstract
for base contractsabstract
contracts are contracts that have at least one function without its implementation. An instance of an abstract cannot be created.
Reference:
Affected source code:
#0 - c4-judge
2023-01-04T10:45:08Z
berndartmueller marked the issue as grade-b