Aus dem Server ausgesperrt

Posted on Fri 30 June 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

  1. der Server den korrekten mime type (application/octet-stream) liefern und
  2. 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...