No description
  • Go 99.2%
  • Makefile 0.5%
  • Dockerfile 0.3%
Find a file
Pierre-Olivier Mercier 258d799a97 checker: implement ShareKey to mutualise SSH probes across targets
An SSH probe (reachability, banner, KEX/host-key algorithm posture, host keys)
depends only on the set of addresses and ports dialed and the probe knobs,
never on which domain name points at the server: SSH has no SNI, so the same
daemon answers identically behind every name. Implement sdk.ObservationSharer
so the host can probe an address set once and serve every target (of the same
user) that points at it, instead of re-connecting per record.

The share key sorts the resolved addresses and ports and folds in the probe
timeout, the auth-probe flag, and the declared SSHFP fingerprints — the latter
live in the observation and drive the SSHFP-match rule, so two services with
the same endpoints but different SSHFP must not share a verdict. The
host/Domain label is intentionally excluded, mirroring the ping checker's
exclusion of which domain the addresses belong to: it does not change
reachability, the negotiated algorithms, the host keys, or the SSHFP
comparison. Inputs with no probable address yield "" so the host falls back to
per-target caching.
2026-06-18 15:28:28 +09:00
checker checker: implement ShareKey to mutualise SSH probes across targets 2026-06-18 15:28:28 +09:00
plugin Initial commit 2026-04-26 16:23:21 +07:00
.drone-manifest.yml Add CI/CD pipeline 2026-05-10 19:30:20 +08:00
.drone.yml Add CI/CD pipeline 2026-05-10 19:30:20 +08:00
.gitignore Initial commit 2026-04-26 16:23:21 +07:00
Dockerfile Initial commit 2026-04-26 16:23:21 +07:00
go.mod Update go mod 2026-05-10 19:37:19 +08:00
go.sum Update go mod 2026-05-10 19:37:19 +08:00
LICENSE Initial commit 2026-04-26 16:23:21 +07:00
main.go Initial commit 2026-04-26 16:23:21 +07:00
Makefile Initial commit 2026-04-26 16:23:21 +07:00
NOTICE Initial commit 2026-04-26 16:23:21 +07:00
README.md Include rules section 2026-04-30 08:46:17 +07:00

checker-ssh

Deep SSH security checker for happyDomain.

Given an abstract.Server service (A / AAAA / SSHFP records), the checker connects to the advertised SSH port(s) and produces a comprehensive audit: reachability, banner-to-CVE matches, full algorithm posture (KEX / host-key / cipher / MAC / compression), observed host keys, SSHFP fingerprint validation, and authentication method exposure.

What it checks

Reachability

  • TCP connect to port 22 (and optionally extra ports) on every A/AAAA address of the service.
  • SSH-2.0 protocol banner read.

Banner / CVE

The banner is parsed into an OpenSSH_X.Ypz tuple and matched against a bundled subset of the ssh-audit vulnerability database, including:

CVE Issue
CVE-2024-6387 regreSSHion - unauth RCE as root (8.5p1 <= v < 9.8p1)
CVE-2023-38408 ssh-agent PKCS#11 RCE (5.5 ≤ v < 9.3p2)
CVE-2023-48795 Terrapin prefix-truncation (v < 9.6p1)
CVE-2021-41617 AuthorizedKeysCommand privdrop (6.2 ≤ v < 8.8p1)
CVE-2020-15778 scp command injection (v < 8.4p1)
CVE-2018-15473 username enumeration (v < 7.8p1)

Algorithm posture

A raw SSH_MSG_KEXINIT is exchanged with the server to enumerate every algorithm it advertises. Each entry is graded against a curated table inspired by ssh-audit:

  • crit: diffie-hellman-group1-sha1 (Logjam), 3des-cbc (Sweet32), arcfour*, hmac-md5*, hmac-sha1-96, ssh-dss, none.
  • warn: ssh-rsa (RFC 8332 deprecated), diffie-hellman-group14-sha1, AES-CBC, non-ETM MACs, hmac-sha1, missing strict-KEX marker (CVE-2023-48795 mitigation).
  • ok: curve25519-sha256, sntrup761x25519-sha512@openssh.com, mlkem768x25519-sha256, ssh-ed25519, AES-GCM/ChaCha20-Poly1305, SHA-2 ETM MACs.

SSHFP validation

For each observed host key, the checker:

  • computes SHA-1 and SHA-256 fingerprints,
  • matches them against the abstract.Server.SSHFP records declared in the zone,
  • flags sshfp_missing, sshfp_not_covered, sshfp_only_sha1 or sshfp_mismatch as appropriate, with copy-pasteable fix snippets.

Authentication methods

A second connection is opened with a dummy user and no credentials. The server replies with the auth-method list, which is surfaced as password, publickey, keyboard-interactive chips. Password authentication triggers a password_auth_enabled warning.

HTML report

The iframe report is structured for "fix me fast":

  1. Overall status banner + SSHFP verdict chips.
  2. What to fix: top issues (crit -> warn), each with a copy-pasteable remediation snippet (sshd_config lines, SSHFP DNS records, ssh-keygen invocations).
  3. SSHFP table with per-record match status.
  4. Per-endpoint details: expandable sections with host-key fingerprints, algorithm tables (broken entries highlighted), and advertised auth methods.

Usage

Standalone HTTP server

make
./checker-ssh -listen :8080

Endpoints:

  • GET /health
  • GET /definition
  • POST /collect
  • POST /evaluate
  • POST /report

Docker

make docker
docker run -p 8080:8080 happydomain/checker-ssh

happyDomain plugin

make plugin
# produces checker-ssh.so, loadable as a Go plugin

Options

Option Type Default Description
ports string "" Comma-separated extra ports (port 22 is always probed).
probeTimeoutMs number 10000 Per-endpoint dial + handshake timeout.
includeAuthProbe bool true Open a second connection to enumerate auth methods.

Rules

Code Description Severity
ssh.tcp_reachable Verifies that every probed (address, port) pair accepts a TCP connection. CRITICAL
ssh.handshake Verifies that the SSH banner exchange and KEXINIT parse succeed on every reachable endpoint. CRITICAL
ssh.protocol_version Verifies every endpoint advertises SSH-2 and rejects the legacy SSH-1 protocol. CRITICAL
ssh.banner_software Flags servers whose banner is not a recognised OpenSSH build. INFO
ssh.known_vulnerabilities Matches the advertised OpenSSH version against a curated catalog of remotely-observable CVEs. CRITICAL
ssh.host_key_strength Flags SSH host keys whose size is below the currently accepted minimum (e.g. RSA < 2048 bits). CRITICAL
ssh.kex_algorithms Flags key-exchange algorithms advertised by the server that are weak or broken. CRITICAL
ssh.host_key_algorithms Flags server host-key algorithms that are weak or deprecated (ssh-rsa/SHA-1, ssh-dss, ...). CRITICAL
ssh.cipher_algorithms Flags symmetric ciphers advertised by the server that are weak or broken (CBC, 3DES, RC4, ...). CRITICAL
ssh.mac_algorithms Flags MAC algorithms advertised by the server that are weak (SHA-1, non-ETM, ...). CRITICAL
ssh.strict_kex Verifies the server advertises the strict-KEX marker (CVE-2023-48795 Terrapin mitigation). WARNING
ssh.preauth_compression Flags servers that offer pre-authentication zlib compression (prefer zlib@openssh.com). INFO
ssh.auth_methods Reviews the advertised authentication methods (password exposure, public-key availability). WARNING
ssh.sshfp_alignment Compares published SSHFP records against the observed host keys (match, missing, mismatch). CRITICAL
ssh.sshfp_hash Flags SSHFP record sets that only publish SHA-1 (type 1) fingerprints instead of SHA-256. WARNING

Observation key

Writes a single observation under ssh:

{
  "domain": "...",
  "endpoints": [
    {
      "host": "...", "port": 22, "address": "...",
      "banner": "SSH-2.0-OpenSSH_9.3p1",
      "kex_algorithms": ["curve25519-sha256", "..."],
      "host_keys": [{"type": "ssh-ed25519", "sha256": "abc..."}],
      "auth_methods": ["publickey"],
      "issues": [ { "code": "...", "severity": "warn", ... } ]
    }
  ],
  "sshfp": { "present": true, "records": [...] },
  "collected_at": "..."
}

License & licensing roadmap

This project is currently licensed under the GNU Affero General Public License v3.0 (see LICENSE), because it still imports happydns.ServiceMessage and abstract.Server from the happyDomain server module (git.happydns.org/happyDomain/model and git.happydns.org/happyDomain/services/abstract), which are themselves distributed under AGPL-3.0 and a commercial license.

The core checker types (CheckerOptions, CheckerDefinition, ObservationProvider, CheckRule, …) have already been migrated to checker-sdk-go; only the service-message types remain on the AGPL side.

Planned relicensing: as soon as the remaining ServiceMessage / abstract.Server dependency has been removed (moved into a dedicated permissively licensed module), this project will be relicensed under the MIT License, in line with the rest of the happyDomain checker ecosystem (see checker-dummy for the target shape).

Contributors notice: by submitting a contribution to this repository, you accept that your contribution will be relicensed from AGPL-3.0 to MIT at the time of the relicensing described above. If you do not agree with this, please do not submit contributions until the relicensing has taken place.

The third-party Apache-2.0 attributions for checker-sdk-go are recorded in NOTICE and must accompany any binary or source redistribution of this project.