04 April 2019

Angeblich schwere Sicherheitslücke in PostgreSQL

Kategorien: Aktuelles PostgreSQL
Tags: PostgreSQL Sicherheit

In den letzten Tagen berichteten verschiedene Quellen von einer angeblich schwereren Sicherheitslücke in PostgreSQL. Mittlerweile wurde genannter Artikel ebenfalls analog zu den untenstehenden Ausführungen korrigiert.

Konkret geht es um ein ungeprüftes Ausführen von Executable Code im Kontext des PostgreSQL Dienstes mit Hilfe des Befehls

COPY <table> FROM|TO PROGRAM

Die Details hierzu werden in CVE-2019-9193 beschrieben.

Stellungnahme und Erläuterung

Diese Darstellung ist unter sachlicher Betrachtung allerdings keine Sicherheitslücke im eigentlichen Sinn. Vielmehr handelt es sich bei dem betroffenen COPY-Kommando um eine privilegierte Datenbankoperation, die unter allen Umständen entweder Superuserberechtigungen (in der Regel z.B. der Benutzer postgres) oder Mitgliedschaft in der Datenbankrolle pg_execute_server_program erfordert. In dieser Hinsicht enthält der im Link angegebene CVE auch einen Fehler, denn die Rolle pg_read_server_files ist nicht ausreichend, um als unprivilegierter Datenbankbenutzer überhaupt dieses Kommando ausführen zu können.

Gegeben sind in den folgenden Beispielen die Rollen bernd und test, wobei bernd eine Datenbankrolle mit Superuserprivileg ist und test lediglich das LOGIN-Privileg besitzt (also ein normaler Datenbankbenutzer).

bernd@db=# \duS bernd
                                   List of roles
 Role name │                         Attributes                         │ Member of 
───────────┼────────────────────────────────────────────────────────────┼───────────
 bernd     │ Superuser, Create role, Create DB, Replication, Bypass RLS │ {}
 
bernd@db=# \duS test
           List of roles
 Role name │ Attributes │ Member of 
───────────┼────────────┼───────────
 test      │            │ {}

Im Folgenden wird nun versucht, als Benutzer bernd die Ausgabe des Linux-Kommandos echo in eine Tabelle zu schreiben:

bernd@db=# CREATE TABLE test(val text);
CREATE TABLE
bernd@db=# SELECT current_role;
 current_role 
--------------
 bernd
(1 row)
bernd@db=# COPY test FROM PROGRAM '/bin/echo hallo welt';
COPY 1
bernd@db=# SELECT * FROM test;
    val     
------------
 hallo welt
(1 row)

Das hat funktioniert, da die Superuserprivilegien des Datenbankrolle bernd dies explizit erlauben. Anders sieht dies mit der unprivilegierten Rolle test aus:

test@db=> SELECT current_role;
 current_role 
--------------
 test
(1 row)
test@db=> COPY test FROM PROGRAM 'echo hallo welt';
FEHLER:  nur Superuser oder Mitglieder von pg_execute_server_program können COPY mit externen Programmen verwenden
HINT:  Jeder kann COPY mit STDOUT oder STDIN verwenden. Der Befehl \copy in psql funktioniert auch für jeden.

Das Ausführen von COPY FROM PROGRAM ist der Rolle test nicht gestattet. Man kann es jetzt wie im CVE beschrieben mit der Mitgliedschaft in der Rolle pg_read_server_files versuchen:

bernd@db=# GRANT pg_read_server_files TO test;
 
bernd@db=# SET ROLE test;
 
test@db=> COPY test FROM PROGRAM 'echo hallo welt';
FEHLER:  nur Superuser oder Mitglieder von pg_execute_server_program können COPY mit externen Programmen verwenden
HINT:  Jeder kann COPY mit STDOUT oder STDIN verwenden. Der Befehl \copy in psql funktioniert auch für jeden.

Auch das ist offensichtlich nicht ausreichend. Mit der Mitgliedschaft pg_execute_server_program kommt man dann jedoch an das Ziel:

bernd@db=# GRANT pg_execute_server_program TO test;
 
bernd@db=# SET ROLE test;
 
test@db=> COPY test FROM PROGRAM 'echo hallo welt';
 
test@db=> SELECT * FROM test;
    val     
────────────
 hallo welt
 hallo welt
(2 rows)

Normale Datenbankrollen mit entsprechend fehlenden Berechtigungen sind folglich nicht in der Lage, dieses Kommando auszuführen. Dies ist das Standardverhalten und benötigt keine entsprechenden Änderungen an der Datenbankkonfiguration. Nur Superuser der PostgreSQL-Instanz besitzen standardmäßig die Berechtigung für das erfolgreiche Ausführen von COPY TO|FROM PROGRAM. Dieser Sachverhalt ist auch entsprechend in der PostgreSQL Dokumentation beschrieben.

Das mit COPY TO|FROM angegebene Executable wird immer im Kontext des Betriebssystem-Benutzers ausgeführt, unter dem die jeweilige PostgreSQL-Instanz läuft (in der Regel eigentlich immer postgres). D.h. die Ausführung des Executable unterliegt immer dem Berechtigungskontexts dieses Benutzers. Dieser ist in der Regel eher eingeschränkt, da PostgreSQL bspw. als root nicht gestartet werden kann. Das heißt, beliebige Zugriffe sind somit ausgeschlossen. Folgendes Beispiel versucht nun mit der Rolle test die Datei /etc/shadow mit den Passwörtern des Betriebssystems zu lesen:

test@db=> COPY test FROM PROGRAM 'cat /etc/shadow';
FEHLER:  Programm »cat /etc/shadow« fehlgeschlagen
DETAIL:  Kindprozess hat mit Code 1 beendet

Dies schlägt fehl, denn der angesprochene Berechtigungskontext des Betriebsystem-Benutzers, unter dem die PostgreSQL-Instanz ausgeführt wird, hat keine Zugriffsberechtigung auf /etc/shadow.

Zusammenfassung

Es ist nicht möglich als Standard-Datenbankrolle ohne entsprechend erteilte Berechtigungen ohne weiteres die angebliche Sicherheitslücke wie im CVE beschrieben auszunutzen. Datenbankrollen müssen entgegen der empfohlenen Praxis entweder über SUPERUSER Privilegien verfügen oder explizit die Berechtigung der Rolle pg_execute_server_program erhalten. Daher ist es wichtig bei PostgreSQL Installationen beim Anlegen und Verteilen von Berechtigungen entsprechend sorgfältig vorzugehen. Der Blogartikel des Core Committee Mitglieds Magnus Hagander (in englischer Sprache) beinhaltet ebenfalls eine entsprechende Erläuterung zum Sachverhalt und empfiehlt sich zur weiteren Lektüre.

An dieser Stelle soll explizit von der Verwendung von Datenbankrollen mit SUPERUSER Privileg für Anwendungen oder Nutzern abgeraten werden. Superuser verfügen noch über viel weitreichendere Berechtigungen als COPY TO|FROM PROGRAM. Sie können beliebige Shared Libraries laden, beliebige Objekte ändern und beliebige Konfigurationsänderungen vornehmen. Daher ist die Verwendung von derart privilegierten Rollen außerhalb des Administrationskontextes dringenst zu vermeiden.

Kategorien: Aktuelles PostgreSQL
Tags: PostgreSQL Sicherheit


Beitrag teilen: