Kritische Mysql-Lücke?

Gestern stand es groß auf Heise „Kritische MySQL-Lücke erlaubt das Kapern von Servern“. Und zwar bezieht sich heise hier auf den folgenden Proof-Of-Concept, der angeblich alle aktuellen Mysql-/Mariadb-/Percona-Server Installationen betrifft: http://legalhackers.com/advisories/MySQL-Exploit-Remote-Root-Code-Execution-Privesc-CVE-2016-6662.html
Nun also die Frage: Ist es denn wirklich so schlimm?

Ich hab mir also den Proof-Of-Concept mal genau durchgelesen, und kann nun berichten:
Grundsätzlich setzt der Exploit darauf dass Mysql über das Script ‚/usr/bin/mysqld_safe‘ gestartet wird. Dieses Script wird nämlich als root ausgeführt (zumindest auf einem aktuellen Ubuntu 16.04 wo es auch von systemd verwendet wird) und beachtet eine Konfigurationsvariable ‚malloc_lib‘. Diese Variable erlaubt es in irgendeiner Konfigurationsdatei von Mysql eine Library zu definieren die von nun an von mysql genutzt wird.
Da mysqld_safe die Library läd, und das Script als root gestartet wird hat die Library auch root-Rechte.

Es geht also nun für den freundlichen Computersicherheitsspezialisten darum
a) Diese Library irgendwo aufs System zu kriegen. z.B. mittels einem PHP-Script welches die Library wahrscheinlich nach ‚/tmp‘ ablegt.
b) Die Konfigurationsvariable ‚malloc_lib‘ irgendwie in eine Konfigurationsdatei von mysql zu bringen.

Punkt ‚a‘ wird einfach mal still vorausgesetzt dass das geht. Somit sind -imho- schonmal nur Webserver betroffen die überhaupt die Möglichkeit eines Dateiuploads bieten. Oder aber man hat einen Useraccount auf dem Server. Das schließt also schonmal ne ganze Menge Server aus. Vorallem pure Datenbankserver.

Für Punkt ‚b‘ hat man sich nun drei Möglichkeiten einfallen lassen:
1. Wenn die Mysql-Konfigurationsdateien dem User mysql gehören kann man mit dem folgenden Mysql-Statement dort die eigene Library eintragen:

mysql> set global general_log_file = '/etc/my.cnf';
mysql> set global general_log = on;
mysql> select '
    '> 
    '> ; injected config entry
    '> 
    '> [mysqld]
    '> malloc_lib=/tmp/mysql_exploit_lib.so
    '> 
    '> [separator]
    '> 
    '> ';
1 row in set (0.00 sec)
mysql> set global general_log = off;

Natürlich ist die Datei dann nicht mehr komplett lesbar – die Library wird aber geladen, und sobald diese geladen ist kann man die Config-Datei wieder reparieren damit keine Spuren zurückbleiben.
Hier muss aber nun:
– Die Configdateien dem User mysql gehören
– Der Mysql-User das Recht für ’set global general_log_file‘ haben.
Beides Voraussetzungen die eher selten bis nie vorkommen werden.

Auf zu Methode 2:
Hier geht es drum dass das Script ‚mysqld_safe‘ die Konfigdateien auch aus der Datadirectory ‚/var/lib/mysql‘ liest. Dort hat der mysql-User natürlich Schreibrechte. Da Mysql sich nun aber weigert Konfig-Dateien zu lesen die rw-Rechte für Jeden haben, kann man die Datei aber nicht mit ‚SELECT xxx INTO OUTFILE yyy‘ erstellen. Man kann aber wieder ’set global general_log_file‘ verwenden.
Hier muss also:
– Der User das Recht für ’set global general_logfile‘ haben. Was bei mir selbstverständlich kein normaler User hat.
– Die Datei muss mit einem gültigten ‚[section]‘ Header anfangen, das ist mit ’set global general_logfile‘ nicht machbar da dieses Statement viel zusätzliche Daten ausgibt. Die Autoren behaupten aber dass sie dies umgehen könnten, aber noch nicht veröffentlichen wollen wie das geht.
Überraschend fand ich aber trotzdem dass meine aktuelle MariaDB 10.1 direkt aus den Repos von MariaDB tatsächlich eine Konfigdatei aus dem Datadir mit einliest…

Nun noch Methode 3:
Mysql-User die keinen Zugriff auf ’set global general_logfile‘ haben, aber das FILE-Recht haben, könnten mit folgendem Statement einen Trigger bauen der das General Logfile für sie als root mit dem gewünschten Text erzeugt:

CREATE DEFINER=`root`@`localhost` TRIGGER appendToConf
AFTER INSERT
   ON `active_table` FOR EACH ROW
BEGIN
   DECLARE void varchar(550);
   set global general_log_file='/var/lib/mysql/my.cnf';
   set global general_log = on;
   select "
[mysqld]
malloc_lib='/var/lib/mysql/mysql_hookandroot_lib.so'

" INTO void;   
   set global general_log = off;
END;

Da man als nicht SuperUser aber „Definer“ nicht verwenden darf, müssen sie das Statement in eine Datei rausschreiben, und zwar so:

SELECT '....trigger_code...' INTO DUMPFILE /var/lib/mysql/activedb/active_table.TRG'

Beim nächsten Flush der Tables würde dieser Triggercode dann aktiviert werden.
– Auch hier rettet uns dass der User das FILE Privileg haben muss.

In der Zusammenfassung (tl;dr):
Der Exploit ist nur gefährlich wenn ich einen User habe der
a) eine Library-Datei auf mein System schmuggeln kann, und
b) einen mysql-Account besitzt der mindestens das FILE-Recht hat.

Ich gehe hier davon aus dass man mit ‚SELECT xxx INTO OUTFILE yyy‘ keine Binärdaten (also eine Library) schreiben kann.

Kurzum:
Es mag sein dass dieser Exploit für bestimmte Shared-Systeme von Bedeutung ist – für normal abgesicherte Datenbankserver, und auch für meine Server, sehe ich keine große Gefahr. Meiner Meinung nach wird das etwas hochgekocht.

Wie immer: Wenn ich hier was falsch verstanden habe freue ich mich auf eine Korrektur oder eine Diskussion!

UPDATE: Es scheint als könnte man die Library mit ‚Select xxx INTO DUMPFILE yyy‘ auch binär schreiben.
Bleibt also als geringste Hürde für diesen Exploit: Ein Mysql-User der das FILE-Privileg besitzt.

UPDATE2: Die ersten Distributionen haben fixes ausgeliefert. Es wird nun ein Update der ‚libmysqlclient20‘ ausgeliefert. Inhalt vom Changelog:

  * SECURITY UPDATE: Update to 5.7.15 to fix security issues
    - CVE-2016-6662

Und bei MariaDB existiert der Fix schon seit 08.2016, hier: https://github.com/MariaDB/server/commit/0098d789c9d8be15d62230289f603ac8f3d5b275
Bzw. hier der BugReport: https://jira.mariadb.org/browse/MDEV-10465

 


Kommentare

3 Antworten zu „Kritische Mysql-Lücke?“

  1. Anonymous

    Die Frage bei so etwas ist nicht immer ob das realistisch ist sondern ob man es besser machen kann. Robustheit erlangt man indem man alle Eventualitäten in Betracht zieht.

  2. Du hast Recht, viel BUZZ um nichts. Auf einem Db_Server der nach Best Practice eingerichtet ist (Priviledge Separation) wird der Exploit nicht funktionieren.

    Alle anderen haben es nicht besser verdient.

    Schlimm ist, das die großen Newsportale kein Fachpersonal mehr haben um den Kram
    mal eben gegenzuprüfen und lieber dem BUZZ folgen.

    cheers,

    Markus // 8ackProtect

  3. marius

    Also grade Heise hat mit seiner Security Abteilung tatsächlich Leute, die das beurteilen können.
    Es muß sich natürlich nicht jeder davon mit MySQL auskennen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Time limit is exhausted. Please reload CAPTCHA.