Beginner FriendlyFoundryNFT
100 EXP
View results
Submission Details
Severity: medium
Invalid

Timestamp Dependence Vulnerabilities in `Staking` Contract which can lead to Reward Manipulation

Summary

The timestamp dependence vulnerabilities in the Staking contract arise from direct use of block.timestamp for time-based calculations. This could lead to timestamp manipulation, allowing attackers to exploit time-sensitive functions. The impact includes potential manipulation of reward claimings.

Vulnerability Details

  1. Timestamp Dependence Vulnerability (Line : 81):

    • The vulnerability arises from using block.timestamp for time-based calculations. The timeInWeeksSinceLastClaim calculation and block.timestamp to lastClaim[msg.sender] are susceptible to manipulation by reward users.

Vulnerable Code
@> uint256 timeInWeeksSinceLastClaim = ((block.timestamp - lastClaim[msg.sender]) / 1 weeks);
  1. Timestamp Dependence Vulnerability (Line : 87):

    • The vulnerability arises from the assignment of block.timestamp to lastClaim[msg.sender], which relies solely on block timestamps that can be influenced by reward users.

Vulnerable Code
@> lastClaim[msg.sender] = block.timestamp;

Impact

These vulnerabilities can lead to inaccurate time calculations and potentially allow attacker to manipulate time-dependent functions in the contract. This could result in the incorrect distribution of staking rewards or exploitation of time-based conditions within the contract.

Proof of Concept

An attacker could manipulate the block timestamp to influence the timeInWeeksSinceLastClaim calculation or the assignment of lastClaim[msg.sender].

Malicious Contract:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.23;
import "./Staking.sol";
contract MaliciousContract {
Staking public stakingContract;
uint256 public lastClaimTimestamp;
constructor(Staking _stakingContract) {
stakingContract = _stakingContract;
}
// Function to manipulate the block timestamp
function manipulateTimestamp(uint256 timestamp) external {
lastClaimTimestamp = timestamp;
}
// Function to exploit the timestamp dependence vulnerabilities
function exploitVulnerability() external {
// Manipulate the last claim timestamp to a future time
stakingContract.lastClaim(msg.sender) = block.timestamp + 2 weeks;
}
}

In this malicious contract:

  • The manipulateTimestamp function allows the attacker to manually set the lastClaimTimestamp variable to a specific timestamp, potentially influencing the time-based calculations in the Staking contract.

  • The exploitVulnerability function exploits the vulnerability by directly modifying the lastClaim mapping in the Staking contract to set a future timestamp for the last claim of the attacker's address.

The attacker would deploy this malicious contract and specify the address of the deployed Staking contract when deploying the MaliciousContract. Then they call the manipulateTimestamp function with a manipulated timestamp, followed by the exploitVulnerability function to set a future last claim timestamp for their address in the Staking contract.

Tools Used

Manual review.

Recommended Mitigation Steps

  1. Avoid Timestamp Dependence:

    • Instead of directly using block.timestamp, use a library like OpenZeppelin's SafeMath to perform arithmetic operations on timestamps. This helps mitigate issues related to timestamp manipulation and ensures safer timestamp-based calculations.

import "@openzeppelin/contracts/utils/math/SafeMath.sol";
contract Staking {
using SafeMath for uint256;
// Use SafeMath for timestamp arithmetic
uint256 public lastClaimTimestamp;
function updateLastClaimTimestamp() internal {
lastClaimTimestamp = block.timestamp;
}
}
  1. Implement Thresholds and Checks:

    • Implement thresholds or minimum time requirements to restrict certain actions based on time. For example, impose a cooldown period between successive claims to prevent users from claiming rewards too frequently.

contract Staking {
uint256 public lastClaimTimestamp;
uint256 public claimCooldown = 1 weeks; // Set a cooldown period of 1 week
function claimRewards() external {
require(block.timestamp >= lastClaimTimestamp.add(claimCooldown), "Cooldown period not over yet");
// Perform claim operation
lastClaimTimestamp = block.timestamp;
}
}
  1. Use Relative Time Units:

    • Instead of relying on absolute timestamps, use relative time units like seconds, minutes, hours, or days for time-based calculations. This makes the contract behavior more predictable and less susceptible to timestamp manipulation.

  2. Use External Time-Source Contracts:

    • Use external contracts that provide reliable and tamper-proof timestamps. This external time sources can enhance the integrity of time-dependent operations in the contract.

@> interface TimeSource {
function getCurrentTime() external view returns (uint256);
}
contract Staking {
TimeSource public timeSource;
uint256 public lastClaimTimestamp;
constructor(TimeSource _timeSource) {
timeSource = _timeSource;
}
function claimRewards() external {
uint256 currentTime = timeSource.getCurrentTime();
// Perform claim operation
lastClaimTimestamp = currentTime;
}
}
  1. Use external timestamp services or oracles:

    • To prevent timestamp manipulation by miners, you can use oracles to fetch the current time. This service provides reliable and tamper-proof timestamps.

contract Staking {
// Import an external timestamp service or oracle contract
ITimestampService public timestampService;
function claimRewards() external {
@> require(timestampService.getCurrentTime() >= lastClaim[msg.sender] + 604800, "Wait for the required period");
// Perform reward calculations and update lastClaim
@> lastClaim[msg.sender] = timestampService.getCurrentTime();
// ... rest of the code
}
}
Updates

Lead Judging Commences

0xnevi Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Other

Support

FAQs

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