# SSH User Enumeration

> Detect valid system usernames via SSH timing attacks and error-based responses using tools like Metasploit, ssh-audit, and custom timing scripts.

- **URL:** https://hackindex.io/services/ssh/enumeration/ssh-user-enumeration
- **Path:** SSH > Enumeration
- **Up:** [Enumeration](https://hackindex.io/services/ssh/enumeration.md)
- **Published:** 2026-03-16
- **Updated:** 2026-04-24

OpenSSH versions before 7.7 respond differently to public key authentication attempts for valid versus invalid usernames. Valid usernames trigger a longer processing time because the server checks the key against stored authorized keys. Invalid usernames fail immediately. This timing difference confirms whether an account exists without completing authentication.

First confirm the version is in the vulnerable range. See [SSH Version-Based Vulnerability Check](https://hackindex.io/services/ssh/vulnerability-discovery/ssh-version-vulnerability-check).

Vulnerable range: OpenSSH < 7.7

## Enumerate Users with ssh-user-enum

`ssh-user-enum` automates the timing-based check against a username list:

```bash
ssh-user-enum -U /usr/share/seclists/Usernames/top-usernames-shortlist.txt -t $TARGET_IP
ssh-user-enum -U /usr/share/seclists/Usernames/top-usernames-shortlist.txt -t $TARGET_IP -p $PORT
# [+] root -- found!
# [+] admin -- found!
# [-] test -- not found
# [-] oracle -- not found
# [+] www-data -- found!
```

`found!` means the account exists on the system. The output is a confirmed list of valid usernames to use for password or key attacks.

## Nmap Script

```bash
nmap -p $PORT --script ssh-brute --script-args userdb=/usr/share/seclists/Usernames/top-usernames-shortlist.txt,passdb=/dev/null $TARGET_IP
```

The `ssh-brute` script also leaks valid usernames via timing on vulnerable versions during the user validation phase even when no password matches.

## Manual Timing Check

For a single username test without tools:

```bash
time ssh -o BatchMode=yes -o ConnectTimeout=5 -i /dev/null testuser@$TARGET_IP 2>&1
time ssh -o BatchMode=yes -o ConnectTimeout=5 -i /dev/null invalidxyz99@$TARGET_IP 2>&1
```

A valid username takes measurably longer to reject because the server processes the key lookup. An invalid username fails immediately. The difference is typically 200ms to several seconds depending on authorised keys configuration. Manual timing is unreliable on high-latency connections: use `ssh-user-enum` for consistent results.

## What Valid Usernames Enable

A confirmed username list feeds directly into password attacks and key-based authentication testing. Priority usernames to test immediately:

- `root`: direct root access if password auth is enabled
- Service accounts (`www-data`, `git`, `postgres`): often have weaker passwords or accessible key files
- Any username matching application or database accounts discovered elsewhere in the target

Take confirmed usernames into [SSH Password Credential Attacks](https://hackindex.io/services/ssh/exploitation/ssh-password-credential-attacks).

## References

- [ssh-brute NSE Script](https://github.com/nmap/nmap/blob/master/scripts/ssh-brute.nse) - Nmap script source for SSH brute force and user validation
- [CVE-2018-15919](https://nvd.nist.gov/vuln/detail/CVE-2018-15919) - NVD entry for the OpenSSH timing-based username enumeration vulnerability
