Skip to content

SSH login scanner platform fingerprint is trivially detectable #21220

@bcoles

Description

@bcoles

Summary

The SSH login scanner's post-authentication platform fingerprinting (get_platform_info) executes a deterministic, highly distinctive command sequence on every Linux target — most notably grep unifi.version /tmp/system.cfg. This command has zero legitimate use on non-Ubiquiti hosts, making it a near-perfect detection signature. Defenders can use auditd to detect and automatically terminate sessions within ~1 second of successful login.

Additionally, setting GatherProof to false does not prevent the fingerprinting since 6.1.21 — the sequence still runs unconditionally during session bootstrap.

Why this matters

SSH brute-force attacks are inherently noisy and well-defended — fail2ban, rate limiting, and account lockout policies handle them effectively. But the fingerprinting occurs after successful authentication, meaning the attacker already has valid credentials (obtained through credential stuffing, phishing, password reuse, or a prior breach). At that point, traditional brute-force defenses have already been bypassed.

The fingerprint sequence is the earliest observable indicator that a compromised credential is being used by Metasploit — and it occurs before the attacker can pivot, escalate privileges, or exfiltrate data. Detecting it enables an automated response (session kill + account lock) within ~1 second of login, turning a successful compromise into a failed one. Without fingerprint detection, the attacker's session proceeds silently with no alert beyond a normal successful login in auth.log.

Detectable behavior

After successful SSH authentication, Metasploit::Framework::Ssh::Platform.get_platform_info (lib/metasploit/framework/ssh/platform.rb) executes:

id
uname -a
grep unifi.version /tmp/system.cfg    # ← unique to Metasploit

The grep unifi.version /tmp/system.cfg command is the primary indicator. It runs on every Linux target regardless of whether it is a Ubiquiti device. On a standard Linux host, this command is never executed by any legitimate software, giving it an effectively zero false-positive rate as a detection rule.

ssh-probe-guard is a simple proof-of-concept detector using auditd rules + a lightweight daemon which can detect the sequence & kill the SSH session + lock the compromised account in under 1 second:

ssh-probe-guard detected a successful SSH login from Metasploit, terminated the SSH session, and locked the user's account. Metasploit session is terminated and user can no longer log in.

GatherProof false does not prevent the fingerprint

The fingerprinting runs from two independent code paths:

  1. gather_proof in Metasploit::Framework::LoginScanner::SSH#attempt_login (lib/metasploit/framework/login_scanner/ssh.rb#L96) — controlled by GatherProof
  2. SshCommandShellBind#bootstrap (lib/msf/base/sessions/ssh_command_shell_bind.rb#L241) — runs unconditionally during session setup to determine Unix vs. Windows shell escaping

Path #2 was added in commit 726c5f26 (6.1.21, October 2021). Since then, set GatherProof false only skips path #1 — path #2 still executes the full sequence. With both defaults (GatherProof true + CreateSession true), the fingerprint runs twice.

The only way to fully suppress the fingerprint is set CreateSession false, which prevents getting a session entirely.

Suggested improvements

AI suggested improvements:

  1. Respect GatherProof in bootstrap: If GatherProof is false, SshCommandShellBind#bootstrap should skip get_platform_info and either default to a safe assumption (e.g., POSIX/Unix escaping) or use a less distinctive detection method.

  2. Reduce the fingerprint's distinctiveness: The Ubiquiti check (grep unifi.version /tmp/system.cfg) could be made conditional — only run it if prior output suggests a Ubiquiti device (e.g., uname -a contains UBNT or Linux USG), or check for /tmp/system.cfg existence first using a less distinctive method.

  3. Randomize or obfuscate the probe sequence: The fixed ordering (iduname -agrep unifi.version) and exact command strings make signature-based detection trivial. Varying the order, using alternatives (e.g., cat /tmp/system.cfg | grep unifi vs. grep unifi.version /tmp/system.cfg), or combining commands into a single sh -c invocation would increase detection difficulty.

  4. Don't run the fingerprint twice: When GatherProof true and CreateSession true, the proof gathered in attempt_login could be passed through to bootstrap rather than re-executing the entire sequence.

Versions affected

  • grep unifi.version /tmp/system.cfg present since 5.0.11 (March 2019, commit a0b1ca17)
  • Duplicate execution via bootstrap since 6.1.21 (October 2021, commit 726c5f26)
  • Confirmed on current release (6.4.124+)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions