One Shot: Reloaded

First Flight #47
Beginner FriendlyNFT
100 EXP
Submission Details
Impact: high
Likelihood: medium

[H-03] Battle RNG Manipulation Through Timestamp Control

Author Revealed upon completion

Root + Impact

Description

The battle outcome determination uses timestamp::now_seconds() as a source of randomness, which creates predictable and manipulatable outcomes. This allows attackers to calculate battle results in advance and potentially force specific outcomes by timing their transactions.

The battle resolution logic relies on the current timestamp modulo total skill to determine winners, making the "random" selection cryptographically insecure and vulnerable to manipulation.

// In rap_battle.move
@> let rnd = timestamp::now_seconds() % (if (total_skill == 0) { 1 } else { total_skill });
@> let winner = if (rnd < defender_skill) { defender_addr } else { chall_addr };

Risk

Likelihood:

  • Validators and sophisticated users can predict battle outcomes by analyzing the current timestamp

  • Attackers can monitor the mempool and time transactions to force specific outcomes

  • The timestamp-based RNG is deterministic and can be calculated in advance

Impact:

  • Economic exploitation of the battle betting system

  • Loss of fairness in battle outcomes

  • Users lose trust in the protocol's randomness guarantees

Proof of Concept

This PoC demonstrates how attackers can predict and manipulate battle outcomes:

// Complete attack demonstration
let defender_skill = 70;
let challenger_skill = 30;
let total_skill = defender_skill + challenger_skill;
// Attack methodology:
// 1. Monitor current blockchain timestamp
let current_time = timestamp::now_seconds();
// 2. Calculate outcomes for next 10 seconds
let i = 0;
while (i < 10) {
let future_time = current_time + i;
let future_rnd = future_time % total_skill;
let future_winner = if (future_rnd < defender_skill) { defender_addr } else { challenger_addr };
// 3. Identify favorable timestamps
if (future_winner == attacker_address) {
// 4. Time attack transaction
// Submit transaction at exactly future_time
// This guarantees victory for the attacker
break;
};
i = i + 1;
};
// 5. Execute attack
// Attacker waits for favorable timestamp and submits battle transaction
// The deterministic nature guarantees the predicted outcome

Recommended Mitigation

The mitigation replaces timestamp-based RNG with cryptographically secure randomness:

+ use aptos_framework::randomness;
+
public entry fun go_on_stage_or_battle(
player: &signer,
rapper_token: Object<Token>,
bet_amount: u64
) acquires BattleArena {
// ... setup code ...
let defender_skill = one_shot::skill_of(arena.defender_token_id);
let challenger_skill = one_shot::skill_of(chall_token_id);
let total_skill = defender_skill + challenger_skill;
- let rnd = timestamp::now_seconds() % (if (total_skill == 0) { 1 } else { total_skill });
+ let rnd = randomness::u64_range(0, total_skill);
let winner = if (rnd < defender_skill) { defender_addr } else { chall_addr };
// ... rest of battle resolution ...
}

This mitigation uses Aptos' cryptographically secure randomness module, making battle outcomes unpredictable and preventing timestamp-based manipulation attacks.

Support

FAQs

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