Predictable Exact Value from Previous Values

Description

Predictable Exact Value from Previous Values is a vulnerability that occurs when an exact value or random number can be precisely predicted by observing previous values generated by the system. This weakness indicates a fundamental flaw in the random number generation scheme where the sequence follows a deterministic pattern that attackers can analyze and exploit. Common manifestations include linear congruential generators with observable output, sequential counters with minor obfuscation, TCP sequence numbers with predictable increments, and other schemes where mathematical relationships between consecutive outputs allow prediction of future values with complete accuracy.

Risk

When exact values can be predicted from previous observations, security mechanisms relying on those values are completely compromised. Predictable TCP initial sequence numbers enable connection hijacking and IP spoofing attacks. Predictable DNS query IDs allow DNS cache poisoning, redirecting victims to malicious servers. Sequential transaction IDs enable transaction forgery and replay attacks. Authentication tokens that follow predictable patterns allow account takeover. The risk is severe because prediction is exact rather than probabilistic - attackers don't need to brute force a range of values but can precisely calculate the next value. Historical attacks on TCP sequence number prediction led to widespread security improvements in operating systems, demonstrating the real-world impact of this vulnerability.

Solution

Use cryptographically secure random number generators that produce outputs with no observable mathematical relationship between consecutive values. Ensure each generated value has at least 128 bits of entropy from proper entropy sources. For protocols requiring sequence numbers, incorporate random components that cannot be inferred from previous values. Implement FIPS 140-2 compliant random number generators. If using PRNGs, ensure proper seeding from hardware entropy sources and implement periodic reseeding. Avoid linear congruential generators and other weak PRNGs for any security-sensitive purpose. Conduct security analysis of number generation schemes to identify potential prediction attacks.

Common Consequences

ImpactDetails
Access ControlScope: Access Control

Attackers can predict authentication tokens, session IDs, and sequence numbers, enabling session hijacking, connection spoofing, and unauthorized access.
IntegrityScope: Integrity

Predictable transaction or message identifiers enable request forgery, replay attacks, and injection of malicious data into communication streams.
AvailabilityScope: Availability

Predictable sequence numbers in protocols can enable connection reset attacks and other denial of service techniques.

Example Code

Vulnerable Code (C/Python)

The following examples demonstrate predictable value generation:

// Vulnerable: Predictable sequence numbers
#include <stdio.h>
#include <stdlib.h>

// Vulnerable: Simple incrementing sequence
static unsigned int sequence_number = 0;

unsigned int vulnerable_get_sequence() {
    // Vulnerable: Next value is exactly current + 1
    return ++sequence_number;
}

// Vulnerable: Linear Congruential Generator (LCG)
static unsigned int lcg_state = 1;

unsigned int vulnerable_lcg_next() {
    // Vulnerable: State can be calculated from any observed value
    lcg_state = lcg_state * 1103515245 + 12345;
    return lcg_state;
}

// Vulnerable: Predictable TCP-like sequence number
static unsigned int tcp_seq = 0;

unsigned int vulnerable_tcp_sequence() {
    // Vulnerable: Increment is predictable
    tcp_seq += 64000;  // Fixed increment
    return tcp_seq;
}

// Vulnerable: Time-based with fixed increment
static unsigned int counter = 0;

unsigned int vulnerable_time_counter() {
    // Vulnerable: Both time and increment are predictable
    counter++;
    return (unsigned int)time(NULL) * 1000 + counter;
}

// Vulnerable: XOR with predictable key
static unsigned int obfuscated_counter = 0;
const unsigned int XOR_KEY = 0xDEADBEEF;

unsigned int vulnerable_obfuscated() {
    // Vulnerable: XOR is reversible, sequence still predictable
    obfuscated_counter++;
    return obfuscated_counter ^ XOR_KEY;
}

// Vulnerable: Modular arithmetic sequence
static unsigned int mod_counter = 0;

unsigned int vulnerable_modular() {
    // Vulnerable: Next = (current + 7) mod 256
    mod_counter = (mod_counter + 7) % 256;
    return mod_counter;
}
# Vulnerable: Predictable value generation in Python
import time

# Vulnerable: Simple sequential generator
class VulnerableSequential:
    def __init__(self):
        self.counter = 0

    def next(self):
        # Vulnerable: Exactly predictable
        self.counter += 1
        return self.counter

# Vulnerable: LCG implementation
class VulnerableLCG:
    def __init__(self, seed=1):
        self.state = seed

    def next(self):
        # Vulnerable: Standard LCG parameters
        # Next state = (a * state + c) mod m
        self.state = (self.state * 1103515245 + 12345) & 0x7FFFFFFF
        return self.state

    def predict_next(self, observed):
        # Attack: Can predict next from any observed value
        return (observed * 1103515245 + 12345) & 0x7FFFFFFF

# Vulnerable: Alternating increment pattern
class VulnerableAlternating:
    def __init__(self):
        self.counter = 0
        self.increment = 1

    def next(self):
        # Vulnerable: Pattern is alternating +1, +2, +1, +2...
        self.counter += self.increment
        self.increment = 3 - self.increment  # Toggles between 1 and 2
        return self.counter

# Vulnerable: Time-division multiplexed
class VulnerableTimeDivision:
    def __init__(self):
        self.sequence = 0

    def next(self):
        # Vulnerable: Time component is observable
        self.sequence += 1
        timestamp = int(time.time())
        return (timestamp << 16) | (self.sequence & 0xFFFF)

# Vulnerable: LFSR (Linear Feedback Shift Register)
class VulnerableLFSR:
    def __init__(self, seed=1):
        self.state = seed

    def next(self):
        # Vulnerable: LFSR is mathematically predictable
        bit = ((self.state >> 0) ^ (self.state >> 2) ^
               (self.state >> 3) ^ (self.state >> 5)) & 1
        self.state = (self.state >> 1) | (bit << 15)
        return self.state
// Vulnerable: Predictable value generation in Java
public class VulnerablePredictable {

    // Vulnerable: Sequential counter
    private static long counter = 0;

    public static long vulnerableSequential() {
        // Vulnerable: Next is exactly current + 1
        return ++counter;
    }

    // Vulnerable: java.util.Random is LCG-based
    private java.util.Random rand = new java.util.Random();

    public long vulnerableRandom() {
        // Vulnerable: Random uses 48-bit LCG internally
        // State can be recovered from observed outputs
        return rand.nextLong();
    }

    // Vulnerable: Predictable hash-based sequence
    private long hashCounter = 0;

    public String vulnerableHashSequence() {
        // Vulnerable: Hash of sequential input is still sequential
        hashCounter++;
        return Integer.toHexString((int)hashCounter);
    }

    // Vulnerable: Time-based with counter
    private int timeCounter = 0;

    public long vulnerableTimeCounter() {
        // Vulnerable: Both components are predictable
        timeCounter++;
        return System.currentTimeMillis() * 1000 + timeCounter;
    }

    // Vulnerable: Fixed offset sequence
    private long offsetCounter = 1000000;

    public long vulnerableOffset() {
        // Vulnerable: Fixed offset doesn't add entropy
        return offsetCounter++;
    }
}

Fixed Code (C/Python)

// Fixed: Unpredictable value generation
#include <openssl/rand.h>
#include <stdio.h>

// Fixed: Cryptographically random sequence numbers
int secure_sequence(unsigned int *seq) {
    // Fixed: Each value is independent and unpredictable
    unsigned char bytes[4];
    if (RAND_bytes(bytes, sizeof(bytes)) != 1) {
        return -1;
    }
    *seq = (bytes[0] << 24) | (bytes[1] << 16) |
           (bytes[2] << 8) | bytes[3];
    return 0;
}

// Fixed: Random with counter for uniqueness
typedef struct {
    unsigned int random_base;
    unsigned int counter;
} SecureSequence;

int secure_init(SecureSequence *seq) {
    unsigned char bytes[4];
    if (RAND_bytes(bytes, sizeof(bytes)) != 1) {
        return -1;
    }
    seq->random_base = (bytes[0] << 24) | (bytes[1] << 16) |
                       (bytes[2] << 8) | bytes[3];
    seq->counter = 0;
    return 0;
}

unsigned int secure_next(SecureSequence *seq) {
    // Fixed: Random base ensures unpredictability
    // Counter ensures uniqueness
    seq->counter++;
    return seq->random_base ^ seq->counter;
}

// Fixed: TCP-like sequence with random increment
int secure_tcp_sequence(unsigned int *current_seq) {
    unsigned char random_increment[4];
    if (RAND_bytes(random_increment, sizeof(random_increment)) != 1) {
        return -1;
    }

    // Fixed: Random increment between 1 and 2^31
    unsigned int increment = (random_increment[0] << 24) |
                             (random_increment[1] << 16) |
                             (random_increment[2] << 8) |
                             random_increment[3];
    increment = (increment & 0x7FFFFFFF) | 1;  // At least 1

    *current_seq += increment;
    return 0;
}

// Fixed: Fully random values
int secure_random_value(unsigned char *buffer, size_t len) {
    // Fixed: No mathematical relationship between values
    return RAND_bytes(buffer, len) == 1 ? 0 : -1;
}
# Fixed: Unpredictable value generation in Python
import secrets
import os
import hashlib

# Fixed: Cryptographically secure random
class SecureRandom:
    @staticmethod
    def next():
        # Fixed: Each value independent and unpredictable
        return secrets.randbits(64)

# Fixed: Secure sequence with random base
class SecureSequence:
    def __init__(self):
        # Fixed: Random base prevents prediction
        self.random_base = secrets.randbits(64)
        self.counter = 0

    def next(self):
        self.counter += 1
        # Fixed: Even knowing counter, random_base prevents prediction
        combined = f"{self.random_base}:{self.counter}"
        return hashlib.sha256(combined.encode()).hexdigest()

# Fixed: Secure TCP-like sequence
class SecureTCPSequence:
    def __init__(self):
        self.sequence = secrets.randbits(32)

    def next(self):
        # Fixed: Random increment
        increment = secrets.randbelow(2**31) + 1
        self.sequence = (self.sequence + increment) & 0xFFFFFFFF
        return self.sequence

# Fixed: Token generation with no predictability
class SecureTokenGenerator:
    @staticmethod
    def generate():
        # Fixed: Pure random, no sequential component
        return secrets.token_hex(32)

# Fixed: UUID-based identifiers
import uuid

class SecureIdentifier:
    @staticmethod
    def generate():
        # Fixed: UUID4 uses secure random
        return str(uuid.uuid4())

# Fixed: HMAC-based sequence
class SecureHMACSequence:
    def __init__(self):
        import hmac
        self.key = os.urandom(32)
        self.counter = 0

    def next(self):
        self.counter += 1
        # Fixed: HMAC ensures unpredictability without key
        import hmac
        h = hmac.new(self.key, str(self.counter).encode(), hashlib.sha256)
        return h.hexdigest()
// Fixed: Unpredictable value generation in Java
import java.security.SecureRandom;
import java.util.UUID;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class SecurePredictable {

    private static final SecureRandom secureRandom = new SecureRandom();

    // Fixed: Cryptographically secure random
    public static long secureRandom() {
        // Fixed: SecureRandom provides unpredictable values
        return secureRandom.nextLong();
    }

    // Fixed: Secure sequence with random base
    private long randomBase;
    private long counter;

    public SecurePredictable() {
        this.randomBase = secureRandom.nextLong();
        this.counter = 0;
    }

    public long secureNext() {
        counter++;
        // Fixed: Random base prevents prediction
        return randomBase ^ counter ^ secureRandom.nextLong();
    }

    // Fixed: UUID for identifiers
    public static String secureIdentifier() {
        // Fixed: UUID4 uses SecureRandom
        return UUID.randomUUID().toString();
    }

    // Fixed: HMAC-based sequence
    private byte[] hmacKey;

    public void initHMAC() {
        hmacKey = new byte[32];
        secureRandom.nextBytes(hmacKey);
    }

    public String secureHMACNext() throws Exception {
        counter++;
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec keySpec = new SecretKeySpec(hmacKey, "HmacSHA256");
        mac.init(keySpec);
        byte[] result = mac.doFinal(Long.toString(counter).getBytes());
        return bytesToHex(result);
    }

    // Fixed: Secure TCP-like sequence
    private int tcpSequence;

    public int secureTcpNext() {
        // Fixed: Random increment
        int increment = secureRandom.nextInt(Integer.MAX_VALUE) + 1;
        tcpSequence += increment;
        return tcpSequence;
    }

    private String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
}

The fix uses cryptographically secure random generation where values have no mathematical relationship to previous outputs.


Exploited in the Wild

Predictable TCP Sequence Numbers (CVE-2002-1463)

A firewall generated predictable TCP initial sequence numbers, enabling attackers to inject packets into established connections or hijack sessions.

DNS Query ID Prediction (CVE-2000-0335)

DNS resolvers using predictable query IDs allowed attackers to spoof DNS responses, redirecting victims to malicious servers.


Tools to Test/Exploit


CVE Examples


References

  1. MITRE Corporation. "CWE-342: Predictable Exact Value from Previous Values." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/342.html

  2. Bellovin, S. "Defending Against Sequence Number Attacks." RFC 1948. https://tools.ietf.org/html/rfc1948

  3. NIST. "Recommendation for Random Number Generation." SP 800-90A. https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final