Beatland Festival

First Flight #44
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: high
Valid

Malicious Attendee can obtain unlimited rewards by sending PASS to different address

Root + Impact

Description

Due to the fact that PASS can be freely transferred,malicious attendee can obtain unlimited rewards by sending PASS to different address to attend performance and earn BEAT .

// Attend a performance to earn BEAT
function attendPerformance(uint256 performanceId) external {
require(isPerformanceActive(performanceId), "Performance is not active");
require(hasPass(msg.sender), "Must own a pass");
require(!hasAttended[performanceId][msg.sender], "Already attended this performance");//@> audit: bypass
require(block.timestamp >= lastCheckIn[msg.sender] + COOLDOWN, "Cooldown period not met");
hasAttended[performanceId][msg.sender] = true;
lastCheckIn[msg.sender] = block.timestamp;
uint256 multiplier = getMultiplier(msg.sender);
BeatToken(beatToken).mint(msg.sender, performances[performanceId].baseReward * multiplier);
emit Attended(msg.sender, performanceId, performances[performanceId].baseReward * multiplier);
}

Risk

Likelihood:High

  • This is a very easy attack to launch.

Impact:High

  • Malicious Attendee can obtain unlimited rewards.

Proof of Concept

function test_AttendPerformance_repeatedly() public {
// only buy one GENERAL_PASS
vm.prank(user1);
festivalPass.buyPass{value: GENERAL_PRICE}(1);
// Create a performance
vm.startPrank(organizer);
uint256 perf1 = festivalPass.createPerformance(block.timestamp + 1 hours, 4 hours, 100e18);
vm.stopPrank();
//user1 Attend performance
vm.warp(block.timestamp + 90 minutes);
vm.prank(user1);
festivalPass.attendPerformance(perf1);
//send GENERAL_PASS to user2
vm.prank(user1);
festivalPass.safeTransferFrom(user1,user2,1,1,"");
//user2 Attend performance
vm.prank(user2);
festivalPass.attendPerformance(perf1);
assertEq(beatToken.balanceOf(user1), 100e18);
assertEq(beatToken.balanceOf(user2), 100e18);
}

Recommended Mitigation

Overrite function safeTransferFrom and safeBatchTransferFrom in the contract FestivalPass.

+ function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) public virtual override {
+ require(msg.sender == organizer, "Only organizer can call this");
+ address sender = _msgSender();
+ if (from != sender && !isApprovedForAll(from, sender)) {
+ revert ERC1155MissingApprovalForAll(sender, from);
+ }
+ _safeTransferFrom(from, to, id, value, data);
+ }
+
+ function safeBatchTransferFrom(
+ address from,
+ address to,
+ uint256[] memory ids,
+ uint256[] memory values,
+ bytes memory data
+ ) public virtual override {
+ require(msg.sender == organizer, "Only organizer can call this");
+ address sender = _msgSender();
+ if (from != sender && !isApprovedForAll(from, sender)) {
+ revert ERC1155MissingApprovalForAll(sender, from);
+ }
+ _safeBatchTransferFrom(from, to, ids, values, data);
+ }
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Unlimited beat farming by transferring passes to other addresses.

Support

FAQs

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