Beginner FriendlyFoundryNFT
100 EXP
View results
Submission Details
Severity: high
Valid

No revert after the function selector in `HorseStore.huff::MAIN()` may lead to the execution of an unintended function, causing unexpected behavior.

Summary

The HorseStore.huff::MAIN() macro is missing a revert statement after the function selector, leaving the protocol vulnerable to
unintended function calls. If an nonexistent function is invoked, it could lead to the execution of the wrong function.

Vulnerability Details

When the protocol is called with a nonexistent function, it defaults to calling GET_TOTAL_SUPPLY(). Due to the absence of a revert
statement after the selector checks and not finding a matching function, it falls through to GET_TOTAL_SUPPLY().
To rectify this, a revert should be added after the checks.
Additionally, there is a reference to MINT_HORSE() at the end of the functions, which should be removed.

#define macro MAIN() = takes (0) returns (0) {
// Identify which function is being called.
0x00 calldataload 0xE0 shr
dup1 __FUNC_SIG(totalSupply) eq totalSupply jumpi
....
dup1 __FUNC_SIG(ownerOf)eq ownerOf jumpi
@> missing revert after no function match the unexsistent function, will hit the first one
totalSupply:
GET_TOTAL_SUPPLY()

Impact

Calling the protocol with an existing function may lead to an unintended function being executed, potentially causing issues.
While the current scenario with GET_TOTAL_SUPPLY() is harmless, if a critical function were in its place, it could pose a significant
security risk to the protocol.

A test scenario demonstrates calling the protocol with a non-existing function, such as thisFunctionNotExists,
resulting in the execution of the GET_TOTAL_SUPPLY() function and retrieving the total supply as a result.

function testMint() public {
vm.startPrank(user);
horseStoreHuff.mintHorse(); //Mint an NFT
(bool success, bytes memory result) = address(horseStoreHuff).call(abi.encodeWithSignature("thisFunctionNotExists()"));
uint256 totalSupply = abi.decode(result, (uint256));
console.log("RESULT ", totalSupply);
}

Output

RESULT 1

Tools Used

Manual review

Recommendations

Please consider adding a revert statement after the selectors check to enhance security. Additionally, remove the reference to
MINT_HORSE() at the end.

#define macro MAIN() = takes (0) returns (0) {
// Identify which function is being called.
0x00 calldataload 0xE0 shr
dup1 __FUNC_SIG(totalSupply) eq totalSupply jumpi
dup1 __FUNC_SIG(feedHorse) eq feedHorse jumpi
dup1 __FUNC_SIG(isHappyHorse) eq isHappyHorse jumpi
dup1 __FUNC_SIG(horseIdToFedTimeStamp) eq horseIdToFedTimeStamp jumpi
dup1 __FUNC_SIG(mintHorse) eq mintHorse jumpi
dup1 __FUNC_SIG(HORSE_HAPPY_IF_FED_WITHIN) eq horseHappyIfFedWithin jumpi
dup1 __FUNC_SIG(approve) eq approve jumpi
dup1 __FUNC_SIG(setApprovalForAll) eq setApprovalForAll jumpi
dup1 __FUNC_SIG(transferFrom) eq transferFrom jumpi
dup1 __FUNC_SIG(name) eq name jumpi
dup1 __FUNC_SIG(symbol) eq symbol jumpi
dup1 __FUNC_SIG(tokenURI) eq tokenURI jumpi
dup1 __FUNC_SIG(supportsInterface)eq supportsInterface jumpi
dup1 __FUNC_SIG(getApproved) eq getApproved jumpi
dup1 __FUNC_SIG(isApprovedForAll) eq isApprovedForAll jumpi
dup1 __FUNC_SIG(balanceOf) eq balanceOf jumpi
dup1 __FUNC_SIG(ownerOf)eq ownerOf jumpi
+ 0x00 0x00 revert //Revert if no match found
totalSupply:
GET_TOTAL_SUPPLY()
feedHorse:
FEED_HORSE()
isHappyHorse:
IS_HAPPY_HORSE()
mintHorse:
MINT_HORSE()
horseIdToFedTimeStamp:
GET_HORSE_FED_TIMESTAMP()
horseHappyIfFedWithin:
HORSE_HAPPY_IF_FED_WITHIN()
approve:
APPROVE()
setApprovalForAll:
SET_APPROVAL_FOR_ALL()
transferFrom:
TRANSFER_FROM()
name:
NAME()
symbol:
SYMBOL()
tokenURI:
TOKEN_URI()
supportsInterface:
SUPPORTS_INTERFACE()
getApproved:
GET_APPROVED()
isApprovedForAll:
IS_APPROVED_FOR_ALL()
balanceOf:
BALANCE_OF()
ownerOf:
OWNER_OF()
- MINT_HORSE()
}
Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

MAIN() macro is not properly implemented

Any call data sent to the contract that doesn't contain a function selector will randomly mint a horse.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.