Skip to content

SSH connection-state scan skips the final 6-byte packet window (off-by-one loop bound) #405

@0xghost42

Description

@0xghost42

In crates/rustnet-core/src/network/dpi/ssh.rs, analyze_ssh scans the payload for an SSH packet signature to set the connection state:

for i in 0..payload.len().saturating_sub(6) {
    if payload.len() >= i + 6 {
        if is_valid_ssh_packet_at_offset(payload, i) { ... }
    }
}

A signature occupies 6 bytes (4-byte length, 1-byte padding length, 1-byte message type), so the last valid start offset is len - 6. Because the range is exclusive, it must end at len - 5 to include that offset. saturating_sub(6) ends the range at len - 6 exclusive, i.e. the loop stops at len - 7 and never inspects the final 6-byte window.

Effect: when a valid SSH packet's signature lands in the last 6 bytes of the payload (including a payload that is exactly 6 bytes long), it is never validated, so found_packet_state stays false and the connection state falls back to Banner even though a KEXINIT/NEWKEYS/USERAUTH/etc. message is present. The code comment says it scans "throughout the payload", which it does not.

Fix: use saturating_sub(5); the inner payload.len() >= i + 6 guard still bounds the access.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions