Platform: Code4rena
Start Date: 20/09/2022
Pot Size: $100,000 USDC
Total HM: 4
Participants: 109
Period: 7 days
Judge: GalloDaSballo
Id: 163
League: ETH
Rank: 17/109
Findings: 2
Award: $1,913.41
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: philogy
Also found by: KIntern_NA, auditor0517, bin2chen, cccz, hansfriese, hyh, ladboy233, m9800, pauliax, pedroais, ronnyx2017, wagmi, wastewa, zzykxx
https://github.com/code-423n4/2022-09-artgobblers/blob/d2087c5a8a6a4f1b9784520e7fe75afa3a9cbdbe/src/ArtGobblers.sol#L411 https://github.com/code-423n4/2022-09-artgobblers/blob/d2087c5a8a6a4f1b9784520e7fe75afa3a9cbdbe/src/utils/token/GobblersERC721.sol#L75 https://github.com/code-423n4/2022-09-artgobblers/blob/d2087c5a8a6a4f1b9784520e7fe75afa3a9cbdbe/src/ArtGobblers.sol#L889 https://github.com/code-423n4/2022-09-artgobblers/blob/d2087c5a8a6a4f1b9784520e7fe75afa3a9cbdbe/src/ArtGobblers.sol#L441
A User can mint a legendary Gobbler for free.
The problem lies in GobblersERC721 approval storage. A user can get approval for a specific id. This approval is granted by the owner of the id or by an "all-approved" user of the owner.
mapping(uint256 => address) public getApproved;
This approval is not deleted when a Gobbler is burned to pay for a legendary Gobbler. Instead, the ownership is set to address(0). The person having approval for an id has the power to transfer it.
for (uint256 i = 0; i < cost; ++i) { id = gobblerIds[i]; if (id >= FIRST_LEGENDARY_GOBBLER_ID) revert CannotBurnLegendary(id); require(getGobblerData[id].owner == msg.sender, "WRONG_FROM"); burnedMultipleTotal += getGobblerData[id].emissionMultiple; emit Transfer(msg.sender, getGobblerData[id].owner = address(0), id); }
function transferFrom( address from, address to, uint256 id ) public override { require(from == getGobblerData[id].owner, "WRONG_FROM"); require(to != address(0), "INVALID_RECIPIENT"); require( msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id], "NOT_AUTHORIZED" );
So the process to obtain a legendary gobbler for free would be :
When a gobbler is burned to mint a legendary Gobbler, delete the approval of the gobbler's id. (like it's done in transferFrom())
delete getApproved[id];
#0 - Shungy
2022-09-27T16:54:51Z
#1 - GalloDaSballo
2022-10-02T14:11:55Z
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0x4non, 0x52, 0x5rings, 0xNazgul, 0xRobocop, 0xSmartContract, 0xdeadbeef, 0xsanson, 8olidity, Amithuddar, Aymen0909, B2, B353N, CertoraInc, Ch_301, Chom, CodingNameKiki, Deivitto, ElKu, Funen, JC, JohnnyTime, Kresh, Lambda, Noah3o6, RaymondFam, ReyAdmirado, RockingMiles, Rolezn, Sm4rty, SuldaanBeegsi, Tadashi, TomJ, Tomio, V_B, Waze, __141345__, a12jmx, ak1, arcoun, asutorufos, aviggiano, berndartmueller, bharg4v, bin2chen, brgltd, bulej93, c3phas, catchup, cccz, ch0bu, cryptonue, cryptphi, csanuragjain, delfin454000, devtooligan, djxploit, durianSausage, eighty, erictee, exd0tpy, fatherOfBlocks, giovannidisiena, hansfriese, ignacio, joestakey, ladboy233, lukris02, m9800, malinariy, martin, minhtrng, obront, oyc_109, pedr02b2, pedroais, pfapostol, philogy, prasantgupta52, rbserver, ronnyx2017, rotcivegaf, rvierdiiev, sach1r0, shung, simon135, throttle, tnevler, tonisives, wagmi, yixxas, zkhorse, zzykxx, zzzitron
55.1985 USDC - $55.20
A gobbler con eat any contract implementing safeTransferFrom() or transferFrom() but not compliant with ERC721 or ERC1155.
gobble() is not performing any checks.
function gobble( uint256 gobblerId, address nft, uint256 id, bool isERC1155 ) external { // Get the owner of the gobbler to feed. address owner = getGobblerData[gobblerId].owner; // The caller must own the gobbler they're feeding. if (owner != msg.sender) revert OwnerMismatch(owner); // Gobblers have taken a vow not to eat other gobblers. if (nft == address(this)) revert Cannibalism(); unchecked { // Increment the # of copies gobbled by the gobbler. Unchecked is // safe, as an NFT can't have more than type(uint256).max copies. ++getCopiesOfArtGobbledByGobbler[gobblerId][nft][id]; } emit ArtGobbled(msg.sender, gobblerId, nft, id); isERC1155 ? ERC1155(nft).safeTransferFrom(msg.sender, address(this), id, 1, "") : ERC721(nft).transferFrom(msg.sender, address(this), id); }
check if the input nft contract is ERC721 or ERC1155 compliant.
#0 - Shungy
2022-09-28T09:49:32Z
Duplicate: https://github.com/code-423n4/2022-09-artgobblers-findings/issues/315
I think this is informational.
#1 - GalloDaSballo
2022-10-02T14:02:43Z
#2 - GalloDaSballo
2022-10-09T19:07:47Z
NC