Notfallmässig eine Reverse Shell auf einem Linux-System aufbauen

Heute habe ich auf einem meiner Linux-Systems nach langer Zeit wieder einmal apt-get upgrade durchgeführt. Eines der wenigen System in meinem Fuhrpark, auf welchem noch Debian Stretch läuft.

Per SSH aus der Ferne eingeloggt, winkte ich die Meldungen durch — und musste offenbar übersehen haben, dass apt-get vor hatte, eine ganze Ladung kritischer Dienste zu entfernen. Unter anderem auch das Paket openssh-server. Nachdem das Update durch war, logge ich mich mittels Druck auf Ctrl-D aus. Und sah erst dann monits Warnmeldungen in meiner INBOX, dass auf TCP 22 kein SSH Daemon mehr lauschte. Doch dann war es bereits zu spät — ich hatte die letzte „Brücke“ zum Server soeben mit Ctrl-D in die Wüste geschickt.

Alle meine Systeme sysloggen via Site-to-Site-VPN auf einen zentralen ELK-Server. In Kibana dann die Hiobs-Botschaft:

sshd[10954]: error: rexec of /usr/sbin/sshd failed: No such file or directory

Sowie

sshd[10954]: fatal: chroot("/run/sshd"): No such file or directory [preauth]

Da der Server 13 Kilometer weit weg in der Wohnung eines Bekannten steht, hatte ich den Salat. Ich wollte eine Autofahrt vor Ort unbedingt vermeiden.

Glücklicherweise war der Bekannte gerade zu Hause und erklärte sich bereit, mir in diesem Notfall als manuelles, menschliches KVM zu helfen.

Als erstes leitete ich ihn via iMessage an, sich in den Laptop einzuloggen. Das klappte. Anschliessend wollte ich ihn zwei Befehle ausführen lassen:

$ sudo su -
# apt-get install openssh-server

Doch bereits der erste Befehl produzierte eine Fehlermeldung:

-bash: sudo: command not found

Himmelheiland, war sogar sudo deinstalliert worden?!

Immerhin su funktionierte, aber ich wollte dem Helfer nicht zumuten, das 32-stellige, zufällig generierte Passwort mühsam von iMessage auf die Laptop-Tastatur abzutippen.

Ich wollte schon aufgeben, da kam mir eine Blitzidee: Ich benötigte eine Reverse Shell unter dem nicht-privilegierten Benutzer, und dann könnte ich selber das Problem autonom lösen.

Das VPN war wegen eines Neustarts zusammengebrochen (genau dieser Server ist der entfernte Endpunkt), aber glücklicherweise hatte ich ein zweites System im entfernten Netzwerk, auf welchem ein SSH-Server mit einer öffentlichen IP lauscht. Ich war also zusätzlich parallel auf diesem zweiten Server eingeloggt. Zu diesem benachbarten Server sollte das Reverse Shell aufgebaut werden.

Eine Google-Suche lieferte folgende wichtigen Seiten zu Tage: Bind Shells and Reverse Shells with netcat, Hacking with Netcat part 2: Bind and reverse shells, Complete guide to Reverse Shells sowie Su: must be run from a terminal.

Der Bekannte gab nun auf dem zerschossenen Linux folgenden Befehl ein:

$ nc -lvp 12345 -e /bin/bash

Auf dem Schwester-Server gab ich dann ein:

$ nc -nv 10.1.2.3 12345

Wobei 10.1.2.3 die IP des zerschossenen Systems war.

Die Verbindung war zustande gekommen, aber ich sah keine richtige Shell. Befehle konnte ich eingeben (bspw. ls -l), und das Resultat wurde auf meinem Bildschirm angezeigt.

Problem: Als ich su ausführen wollte, wurde das mit der Fehlermeldung su : must be run from a terminal verhindert.

Zuerst überlegte ich mir den Weg über Scripts: How to pass the password to su/sudo/ssh without overriding the TTY? und su pass password to script.

Doch nach Konsultation von Getting around „su : must be run from a terminal“ schaffte ich eine wirklich vollständig brauchbare Shell nach Eingabe des folgenden Befehls:

python -c 'import pty; pty.spawn("/bin/bash")'

Einschub: Unter Stretch funktioniert das, unter Bullseye sollte man nun folgenden Befehle verwenden:

python3 -c 'import pty; pty.spawn("/bin/bash")'

Hurra, ich hatte eine Shell! Aber Achtung: Ein fahrlässiges, aus Gewohnheit gedrücktes Ctrl-C killt die netcat-Verbindung, nicht das laufende Programm.

Andere Varianten unter Zuhilfenahme anderer potentieller Bordmittel wie Perl, PHP etc. sind in Spawning a TTY Shell dokumentiert.

Nun also wollte ich su anwenden, realisierte erst dann aber, dass das in meiner Passwort-Datenbank hinterlegte 32 Zeichen lange Passwort nicht korrekt war. Ich hatte bei der Installation vergessen, dass viel zu einfache dummy-Passwort anzupassen … Als ich dieses eingegeben hatte, landete ich in einer root-Shell.

Doch oha: openssh-server liess sich wegen Abhängigkeitsproblemen nicht installieren.

Was nun? Ich musste irgendwie einen persistenten Server als ersten Brückenkopf einrichten, der beim versehentlichen Betätigen von Ctrl-C auf meiner Seite weiter lief und erneute Verbindungsversuche zuliess.

Ich überlegte mir, ein PHP-Backdoor-Script zu installieren (php-reverse-shell, Quellcode), doch wie konnte ich dieses so einrichten, dass es permanent oder periodisch automatisch Verbindungsversuche unternehmen würde?

Nach etwas tüfteln dann die viel einfachere Lösung:

# apt-get install telnetd

Besser wäre eigentlich gewesen:

# apt-get install telnetd-ssl

Via: How do I turn on telnet service on for a Linux / FreeBSD system?

Und nun hatte ich wieder einen „sauberen“ Zugang zum Server.

Die nachfolgenden Stunden verbrachte ich damit, den Server von Stretch auf Buster und dann auf Bullseye zu lüpfen und eine Ladung Pakete zu installieren, welche apt heimtückisch entfernt hatte: OpenSSH, sudo, cron, OpenVPN, Samba, monit.