-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathwithdraw_vulnerable.rs
More file actions
66 lines (59 loc) · 2.26 KB
/
Copy pathwithdraw_vulnerable.rs
File metadata and controls
66 lines (59 loc) · 2.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
use anchor_lang::prelude::*;
use crate::state::TokenAccount;
/// ⚠️ VULNERABLE: Withdraw with Unchecked Arithmetic
///
/// This instruction uses the standard subtraction operator (-) which does NOT
/// check for underflow in release builds with default Rust settings.
///
/// THE PROBLEM:
/// - When you subtract a larger number from a smaller number in unsigned integers,
/// it wraps around to a huge positive number instead of going negative
/// - Example: 0 - 1 = 18,446,744,073,709,551,615 (u64::MAX)
/// - This is called "integer underflow"
///
/// THE EXPLOIT:
/// An attacker with 0 balance can withdraw 1 token, and their balance becomes
/// u64::MAX (18.4 quintillion tokens!) - instant infinite money!
///
/// REAL-WORLD IMPACT:
/// This exact vulnerability has drained millions of dollars from DeFi protocols.
/// Examples include various token contracts and vaults that didn't use checked math.
///
#[derive(Accounts)]
pub struct WithdrawVulnerable<'info> {
#[account(
mut,
seeds = [b"token", token_account.owner.as_ref()],
bump = token_account.bump
)]
pub token_account: Account<'info, TokenAccount>,
/// The account owner
#[account(
constraint = owner.key() == token_account.owner @ crate::error::ErrorCode::Unauthorized
)]
pub owner: Signer<'info>,
}
pub fn handler(ctx: Context<WithdrawVulnerable>, amount: u64) -> Result<()> {
let token_account = &mut ctx.accounts.token_account;
// ⚠️ VULNERABILITY: Using unchecked subtraction!
//
// In release builds, if balance < amount, this will UNDERFLOW instead of panicking.
//
// Example attack:
// - User has balance = 0
// - User calls withdraw(1)
// - 0 - 1 = 18,446,744,073,709,551,615 (wraps around to u64::MAX)
// - User now has virtually infinite tokens!
//
// NOTE: In debug builds, this WOULD panic, but release builds
// (which are used in production) silently wrap around!
token_account.balance = token_account.balance - amount;
msg!(
"⚠️ VULNERABLE: Withdrew {} tokens using unchecked math. New balance: {}",
amount,
token_account.balance
);
// If you see a balance of 18,446,744,073,709,551,615 here,
// you've just witnessed the underflow exploit!
Ok(())
}