Aus dem Server ausgesperrt
Posted on Fr 30 Juni 2023 in Computer & Electronics
Kürzlich habe ich meinem Heimserver ein Update auf Debian 12 spendiert. Das ging ganz wunderbar und auf den ersten Blick schien alles auf Anhieb zu funktionieren. Etwas später hatte ich dann aber doch ein Problem: Mein Dokumentenscanner konnte keine sFTP-Verbindung mehr herstellen. Also habe ich ein wenig in meiner ssh config gewühlt und ein paar Sachen ausprobiert. Und dabei muss ich das Config File kaputt gemacht haben – jedenfalls komme ich nicht mehr rein:
❯ ssh hal
ssh: connect to host hal port 22: Connection refused
Hm – schlecht.
In der Tat läuft da offenbar kein sshd
mehr:
❯ nmap hal
Starting Nmap 7.93 ( https://nmap.org ) at 2023-06-29 19:21 CEST
Nmap scan report for hal (192.168.0.10)
Host is up (0.0061s latency).
rDNS record for 192.168.0.10: hal.fritz.box
Not shown: 997 closed tcp ports (conn-refused)
PORT STATE SERVICE
80/tcp open http
443/tcp open https
Garnicht gut. Nun könnte man einfach via Tastatur und Monitor direkt an der Maschine einloggen und das Problem beheben, nur steht der Server in einem Netzwerkschränkchen das unter der Decke hängt und ich verspüre gerade sehr wenig Lust, auf eine Leiter zu steigen und dabei mit Monitor und Tastatur zu jonglieren. Und außerdem ist das gegen die Hacker-Ehre. Was kann man da also machen?
iLO
In meinem Fall habe ich Glück, denn mein Server ist ein echter Server (HP Microserver Gen8) und besitzt ein separates System zur Systemadministration: iLO4. Und damit kann man z.B. das System reseten und noch ein paar coole Dinge. U.a. bietet es eine Remote-Konsole an:
.Net habe ich nicht. Also das Java Applet. Leider läuft sowas aber heutzutage auch nicht mehr in meinem Firefox. Grumpf!
Aber da steht ja noch was von einer HP iLO mobile App. Also auf in den Playstore! Jedoch:
Na super... Aber so schnell gebe ich nicht auf! Ich meine mich zu erinnern, dass man auch per ssh in das iLO System reinkommt. Also versuchen wir das:
❯ ssh administrator@hal-ilo
Unable to negotiate with 192.168.0.11 port 22: no matching key exchange method found.
Their offer: diffie-hellman-group14-sha1,diffie-hellman-group1-sha1
WTF??? Klar – sha1 ist nicht mehr empfehlenswert und daher wird es nicht akzeptiert. Also nochmal:
❯ ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 administrator@hal-ilo
administrator@hal-ilo's password: ************************
User:administrator logged-in to HAL-iLO.fritz.box(192.168.0.11 / FE80::D2BF:9CFF:FE46:6606)
iLO 4 Advanced 2.30 at Aug 19 2015
Server Name: HAL
Server Power: On
Based on customer feedback, we will be enhancing the SSH command line
interface in a future release of the iLO 4 firmware. Our future CLI will
focus on increased usability and improved functionality. This message is
to provide advance notice of the coming change. Please see the iLO 4
Release Notes on www.hp.com/go/iLO for additional information.
hpiLO->
Besser!
hpiLO-> help
[...]
HP CLI Commands:
POWER : Control server power.
UID : Control Unit-ID light.
ONETIMEBOOT: Access One-Time Boot setting.
NMI : Generate an NMI.
VM : Virtual media commands.
LANGUAGE : Command to set or get default language
VSP : Invoke virtual serial port.
TEXTCONS : Invoke Remote Text Console.
TESTTRAP : Sends a test SNMP trap to the configured alert destinations.
Ah – TEXTCONS
klingt gut. Damit werden wir bestimmt ins System kommen!
Oder auch nicht:
hpiLO-> TEXTCONS
Monitor is in graphics mode or an unsupported text mode.
Aaaaaargh! Ja – vermutlich verwendet die Konsole nicht den Standard-0815 VGA mode, sondern einen der ein bisschen mehr Zeichen auf den Bildschirm bringt.
Theoretisch wäre auch VSP
eine Möglichkeit, aber leider hätte ich das zuvor
entsprechend konfigurieren müssen damit da auch ein getty
Prozess lauscht.
Und das habe ich nicht, also:
hpiLO-> VSP
Virtual Serial Port Active: COM2
Starting virtual serial port.
Press 'ESC (' to return to the CLI Session.
... und sonst kommt nix.
So langsam wird es eng und ich sehe mich schon mit dem Monitor auf der Klappleiter, als mir noch eine Idee kommt: Ich könnte das System von einem USB-Stick booten, die System-Platte mounten und das Config File so editieren! Aber auch dazu müsste ich auf die Leiter. Also leicht anders: das iLO kann auch virtuelle Medien einbinden:
Dazu muss man nur das ISO Image auf einen lokalen Webserver legen und die URL im iLO eintragen. Als ISO Image verwende ich ein debian-headless Installations-Image, denn sonst bekomme ich ja keinen Remote-Zugriff.
Mein Webserver läuft auf dem Heimserver – auf den ich ja keinen Zugriff habe, also muss das anders gehen. Python bringt einen schönen simplen Spontan-Webserver mit. Also in das Verzeichnis mit dem Image gehen und dort:
❯ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
Leider funktioniert das aber nur lokal – versuche ich vom Handy aus auf den Server zuzugreifen findet das nix. Also anders:
❯ python3 -m http.server -b 192.168.0.84
Serving HTTP on 192.168.0.84 port 8000 (http://192.168.0.84:8000/) ...
Wobei ich hier die IP Adresse meines Laptops verwende. Nun klappt der Handy-Test.
Und so tragen wir das dann ins iLO ein:
http://192.168.0.84:8000/debian-12.0.0-amd64-netinst-hl.iso
Nun noch Boot on next reset auswählen und auf Insert Media klicken. Und schon
sind wir bereit, den Server neu zu starten – auch wieder über das iLO.
Luft anhalten und hoffen. Nix war's! Der Server ist einfach ganz normal hochgefahren. Und unser ad hoc http Server hat einen Fehler geschmissen:
192.168.0.11 - - [29/Jun/2023 21:06:01] "GET /debian-12.0.0-amd64-netinst-hl.iso HTTP/1.1" 200 -
----------------------------------------
Exception occurred during processing of request from ('192.168.0.11', 60361)
Traceback (most recent call last):
File "/usr/lib/python3.11/socketserver.py", line 691, in process_request_thread
self.finish_request(request, client_address)
File "/usr/lib/python3.11/http/server.py", line 1306, in finish_request
self.RequestHandlerClass(request, client_address, self,
File "/usr/lib/python3.11/http/server.py", line 667, in __init__
super().__init__(*args, **kwargs)
File "/usr/lib/python3.11/socketserver.py", line 755, in __init__
self.handle()
File "/usr/lib/python3.11/http/server.py", line 432, in handle
self.handle_one_request()
File "/usr/lib/python3.11/http/server.py", line 420, in handle_one_request
method()
File "/usr/lib/python3.11/http/server.py", line 674, in do_GET
self.copyfile(f, self.wfile)
File "/usr/lib/python3.11/http/server.py", line 873, in copyfile
shutil.copyfileobj(source, outputfile)
File "/usr/lib/python3.11/shutil.py", line 200, in copyfileobj
fdst_write(buf)
File "/usr/lib/python3.11/socketserver.py", line 834, in write
self._sock.sendall(b)
BrokenPipeError: [Errno 32] Broken pipe
----------------------------------------
Was soll das denn jetzt??? Nach einiger Recherche habe ich herausgefunden, dass
- der Server den korrekten mime type (
application/octet-stream
) liefern und range requests
unterstützen und dann partial-content zurücksenden muss.
Ich werde wahnsinnig! Beides tut unser ad hoc Server natürlich nicht einfach so. Ersteres ist machbar, aber Zweiteres unterstützt das Python Modul meines Wissens einfach nicht.
D.h. wir brauchen allen Ernstes einen echten Webserver! Letzter Versuch, bevor ich den Server mit der Axt umprogrammiere: NGINX als Docker Container.
Schnell ein kleines Dockerfile
bauen:
FROM nginx
COPY debian-12.0.0-amd64-netinst-hl.iso /usr/share/nginx/html
Und in den Ordner mit dem ISO Image legen. Dort dann das Docker Image bauen:
docker build -t nginx-iso .
Und schließlich können wir es starten:
docker run -p 8080:80 -d nginx-iso
Die URL für unser Image lautet dann:
http://192.168.0.84:8080/debian-12.0.0-amd64-netinst-hl.iso
Diese kopieren
wir in das Feld für das virtuelle Medium und starten den Server mal wieder neu.
Und man glaubt es kaum – er bootet das Installer Image.
Nun also ein paar Minuten abwarten, bis der Installer das Netzwerk konfiguriert hat und dann versuchen wir einzuloggen:
ssh installer@hal
Es klappt – puh – ich bin drin.
Reparatur
Jetzt wo wir endlich Zugriff haben starten wir den Installationsprozess und
brechen ihn sofort wieder ab (Go Back
) und gehen dann zu Detect disks
. Dort
können wir uns orientieren welches Device eigentlich die gesuchte Platte ist.
Wie vermutet ist /dev/sda1
die gesuchte Partition. Nun in den Tab mit der
Shell wechseln (CTRL-a 2
) und die Systemplatte mounten:
mount /dev/sda1 /mnt/
vi
gibt es leider nicht in der Installer Shell, aber nano
ist vorhanden.
Also editieren wir das verfluchte Config-File so:
nano /mnt/etc/ssh/sshd_config
Fehlerhafte Zeile korrigieren, speichern und den Server neu starten. Ein paar
Minuten abwarten und versuchen per ssh
einzuloggen. Es geht wieder – hurra!
Serial Login konfigurieren
Und damit mir so eine Sch***e nie wieder passiert, konfigurieren wir nun den seriellen Login als Notfallzugang.
Und das ist eigentlich recht einfach. Der virtuelle Serial Port im iLO ist
COM2
, also /dev/ttyS1
. Und auf diesem Device wollen wir einen getty
Prozess haben:
systemctl enable serial-getty@ttyS1.service
systemctl start serial-getty@ttyS1.service
Und sicherstellen, dass auch alles geklappt hat:
hal:~$ systemctl status serial-getty@ttyS1.service
● serial-getty@ttyS1.service - Serial Getty on ttyS1
Loaded: loaded (/lib/systemd/system/serial-getty@.service; enabled; preset: enabled)
(HP Microserver Gen8) Active: active (running) since Fri 2023-06-30 20(HP Microserver Gen8) :19:22 CEST; 2min ago
Docs: man:agetty(8)
man:systemd-getty-generator(8)
http://0pointer.de/blog/projects/serial-console.html
Main PID: 852 (agetty)
Tasks: 1 (limit: 19068)
Memory: 280.0K
CPU: 3ms
CGroup: /system.slice/system-serial\x2dgetty.slice/serial-getty@ttyS1.service
└─852 /sbin/agetty -o "-p -- \\u" --keep-baud 115200,57600,38400,9600 - vt220
Sehr gut!
Bleibt noch das zu testen:
ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 administrator@hal-ilo
[...]
hpiLO-> VSP
Virtual Serial Port Active: COM2
Starting virtual serial port.
Press 'ESC (' to return to the CLI Session.
hal login: root
Password: **************
Linux hal 6.1.0-9-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.27-1 (2023-05-08) x86_64
Passt!
Wichtig: Serial Login ist was anderes als Serial Console – ersteres haben wir gerade eingerichtet. Zweiteres ist einfach die Möglichkeit, alle Kernel-Messages auf dem virtuellen seriellen Port zu sehen. Das kann nützlich sein, erlaubt aber keinen Login! Man kann auch beides aktivieren, aber dann besteht die Gefahr, dass im Falle eines größeren Problems das serielle Terminal mehr oder weniger unbrauchbar wird, wenn der Bildschirm mit Kernel Messages überflutet wird. Deshalb aktiviere ich das nicht.
iLO update
Außerdem habe ich mal geschaut, ob mein uraltes iLO nicht evtl. auf einen neuern Stand gebracht werden kann. Und in der Tat gibt es inzwischen die Version 2.82. Also habe ich mal ein Firmware-Update gemacht und nun schaut das iLO sehr viel moderner aus und ist stinklangsam. Immerhin bietet es nun eine HTML5-Konsole über die man den Bootvorgang beobachten kann – auch im Grafikmodus etc. Am Ende des Boots sieht man dann auch den Login-Prompt:
Leider funktioniert die Tastatur-Eingabe weder in Firefox, noch in Chromium. Keine Ahnung, was da los ist.
Und wo ich schon dabei war wollte ich auch das BIOS mal auf einen neueren Stand bringen, aber HPE listet die entsprechenden Files zwar noch munter auf der Support-Seite, bietet die entsprechenden Images aber nicht mehr um Download an. Also musste ich ein wenig googeln, um sie mir us zweifelhaften Quellen zu besorgen. Zum Glück stehen auf den Support-Seiten noch die sha256 sums, so dass ich immerhin verifizieren konnte, dass die images unverändert sind.
Irgendwie wird mir HP immer unsympathischer – deren Drucker kann man ohnehin schon lange nicht mehr empfehlen und wer auf den Gedanken kommt, BIOS Updates & Co bewusst zurück zu ziehen, obwohl da draußen zahlende Kunden leben, die das brauchen, um Ihre Systeme zu pflegen verdient eigentlich keinen Umsatz mehr.
Fazit
Was ein Aufwand für so eine simple Sache! Ich hätte auf die Leiter steigen sollen...