
Paralleler SSH-Dienst-Erkennungs- und Sicherheitsauditor, der jeden Port scannt, SSH-Banner validiert und Authentifizierungsmethoden, schwache Kryptografie, die Terrapin-Schwachstelle sowie wiederverwendete Host-Keys über Hosts und CIDR-Bereiche hinweg prüft.
Finde jeden SSH-Dienst in deinem Netzwerk, beurteile, ob er deinem Standard entspricht, und erfahre, wenn sich das ändert.
sshfinder ist eine einzelne Python-Datei ohne erforderliche Abhängigkeiten. Richte es auf
einen CIDR-Bereich und es entdeckt SSH überall dort, wo es tatsächlich lauscht – nicht nur
auf Port 22 – bestätigt, dass jeder wirklich SSH spricht, bewertet seine kryptografische
Haltung und gibt einen Nicht-Null-Exit-Code zurück, wenn etwas deine Richtlinie verletzt.
Die meisten Teams können drei Fragen zu ihrem eigenen SSH-Bestand nicht beantworten:
Die vorhandenen Tools beantworten jeweils einen Teil davon und hören dann auf:
| Tool | Entdeckt SSH | Bewertet es | Über eine Flotte |
|---|---|---|---|
nmap | ja | oberflächlich, über NSE-Skripte | ja |
ssh-audit | nein – du gibst ihm einen Host | tiefgehend | nein |
masscan / zmap | im Internet-Maßstab | nein | ja |
sshfinder | ja | ja | ja |
Diese Lücke – Entdeckung und Bewertung und ein Urteil, in einem Artefakt – ist
das, was dieses Tool füllen soll. Wenn du nur einen Host prüfen musst, den du bereits
kennst, verwende ssh-audit; es geht
bei einem einzelnen Dienst tiefer als dieses Tool.
Penetrationstester werden die Prüfung und den SOCKS-Pivot nützlich finden, aber das Tool ist darauf ausgerichtet, denselben Scan wiederholt gegen einen Bestand auszuführen, den du besitzt, nicht auf ein einmaliges Engagement.
git clone https://github.com/kabiri-labs/sshfinder.git
cd sshfinder
python sshfinder.py 10.0.0.0/24 -p 22,2222
Keine Installation, keine Abhängigkeiten. Erfordert Python 3.9+.
Die drei Dinge, die es tut, in drei Befehlen:
# 1. INVENTAR – welches SSH ist da draußen?
python sshfinder.py 10.0.0.0/24 --audit --format csv -o ssh-inventory.csv
# 2. URTEIL – entspricht es unserem Standard? (beendet mit 3, wenn nicht)
python sshfinder.py 10.0.0.0/24 -p 22,2222 --policy baseline
# 3. ABWEICHUNG – was hat sich seit letzter Nacht geändert?
python sshfinder.py 10.0.0.0/24 -p 22,2222 --baseline yesterday.json \
--fail-on-drift
Das Scannen aller 65535 Ports ist die Standardeinstellung, weil ein SSH-Dienst auf einem nicht standardmäßigen Port genau der ist, den niemand aufgeschrieben hat. Jeder offene Port wird beschriftet, sodass ein offener Port nie stillschweigend als SSH-Port gezählt wird:
=== 10.0.0.5 ===
open: 10.0.0.5:22 [SSH], 10.0.0.5:8080 [not ssh]
SSH 10.0.0.5:22 (SSH-2.0-OpenSSH_7.4)
Die Bestätigung ist ein echter RFC-4253-Identifikationsaustausch, kein Blick auf die ersten Bytes auf der Leitung. Server, die zuerst einen rechtlichen Banner drucken, die darauf warten, dass sich der Client identifiziert, oder deren Banner über mehrere TCP-Segmente verteilt ankommt, werden alle korrekt erkannt – jeder davon ist eine falsch-negative Erkennung in einer naiven Implementierung.
Füge --audit hinzu, um das vollständige Bild jedes Dienstes zu erhalten:
SSH 10.0.0.5:22 (SSH-2.0-OpenSSH_7.4)
host key: ssh-ed25519 SHA256:T/ZM4jOL4amTsO5K3AaCdg2...
auth: publickey, password [!] password auth enabled
[!] Terrapin (CVE-2023-48795): VULNERABLE
[!] weak ciphers: aes128-cbc
aes128-cbc [weak]: CBC mode is vulnerable to the SSH plaintext-recovery attack (CVE-2008-5161) und, …
Geteilte SSH-Host-Keys (mögliche geteilte/geklonte Hosts):
SHA256:T/ZM4jOL4amTsO5K3AaCdg2...
-> 10.0.0.5:22, 10.0.0.9:22
Dieser letzte Block ist wissenswert: Ein Host-Key, das über Maschinen wiederverwendet wird, bedeutet normalerweise geklonte VMs oder ein geteiltes Image, und es bedeutet, dass die Kompromittierung eines Hosts die Identität aller kompromittiert.
OpenSSH 10.0 machte mlkem768x25519-sha256 zum Standard-Schlüsselaustausch, und 10.1
warnt, dass klassische Sitzungen für store now, decrypt later-Erfassung offen sind.
--pq-report beantwortet die Frage auf Flottenebene direkt, nur mit dem
KEXINIT – es benötigt also keine Drittanbieter-Bibliothek:
python sshfinder.py 10.0.0.0/24 -p 22,2222 --pq-report
Post-quantum readiness:
1/3 service(s) negotiate post-quantum key exchange with a current client
[!] no PQ key exchange offered (1):
10.0.0.2:22
[!] pre-standard PQ only (1) - looks post-quantum but is not:
10.0.0.3:22
2 service(s) exposed to store-now-decrypt-later capture; upgrade to OpenSSH 9.0+
Die Kategorie pre-standard ist die, die Leute überrascht. Ein Server,
der [email protected] oder einen Kyber-Entwurf bewirbt, sieht
in einem Algorithmus-Dump post-quantum aus, aber OpenSSH hat diesen zurückgezogenen
Parametersatz 2020 entfernt – ein aktueller Client findet also keine gemeinsame Methode und fällt
auf klassische Krypto zurück. Als bereit gezählt, wäre es schlimmer als gar nicht hinzusehen.
Ein Bericht beschreibt ein Problem. Eine Richtlinie behauptet eines und kann einen Build zum Scheitern bringen:
python sshfinder.py 10.0.0.0/24 -p 22,2222 --policy baseline; echo "exit $?"
Policy 'baseline':
No password login, no Terrapin exposure, no weak algorithms.
1/3 service(s) pass
[FAIL] 1 service(s):
10.0.0.3:22
- password_auth: password login accepted: publickey, password
- terrapin: vulnerable to Terrapin (CVE-2023-48795)
- post_quantum (warn): post-quantum readiness is absent, ready required
[warn] 1 service(s):
10.0.0.2:22
- post_quantum (warn): post-quantum readiness is absent, ready required
exit 3
Drei Richtlinien sind eingebaut – baseline, strict und pq – benannt nach dem
Ergebnis, das sie durchsetzen, nicht nach einer Distribution. Regeln tragen eine fail- oder
warn-Schwere und --fail-on entscheidet, welche Tore greifen, sodass ein Team eine
strengere Messlatte zuerst als Warnung übernehmen und später ohne Bearbeitung befördern kann.
Schreibe deine eigene als JSON:
{
"name": "house-rules",
"description": "What we expect of every SSH service.",
"rules": [
{"check": "password_auth", "severity": "fail"},
{"check": "terrapin", "severity": "fail"},
{"check": "post_quantum", "require": "ready", "severity": "warn"},
{"check": "forbid", "field": "ciphers",
"algorithms": ["3des-cbc", "arcfour"], "severity": "fail"},
{"check": "require", "field": "kex_algorithms",
"algorithms": ["curve25519-sha256"], "severity": "fail"}
]
}