Privilegienerweiterung zum sysadmin über die Trustworthy-Datenbank-Option

In diesem Blog-Artikel, dem letzten, bevor ich zum Microsoft SQL Server Sicherheitsteam wechsele, werde ich ein altes, aber wichtiges Thema behandeln: Die Gefahr, eine Datenbank als vertrauenswürdig („trustworthy“) einzustellen.

– Auf der SQL PASS Rally Amsterdam 2013 habe ich dieses Thema zuerst vorgestellt, und seitdem auf mehreren anderen Konferenzen, es ist also nichts Neues an sich.
Seitdem bin ich nicht mehr dazu gekommen, darüber zu schreiben. Da ich immer mehr Datenbanken mit aktiviertem CLR oder Service Broker sehe, glaube ich, dass dies ein Angriffsvektor ist, dessen man sich wirklich bewusst sein sollte – sowohl Administratoren als auch Entwickler.

Kurzgefasst: die Option der vertrauenswürdigen Datenbank ist Teil der Ermöglichung eines Privilegien-Erweiterungs-Pfades vom Anwendungsnutzer zum sysadmin.

Die Einstellung

Im Grunde benötigt diese Form der Privilegien-Erweiterung (Privilege-Elevation oder Escalation) 3 Voraussetzungen:

1) Einen Datenbankbesitzer mit einem hohen Level von Server-Scope-Berechtigungen wie sysadmin – unser Ziel.

2) Ausreichende Berechtigungen für den Angreifer

3) Die Datenbank-Option Trustworthy auf „an“ gestellt

Voraussetzung Nr. 1 – hochprivilegierte Datenbankbesitzer:

Stellt euch selbst die Frage: Welches Konto benutzt ihr als Datenbankbesitzer?

– Um eine komplette Liste all eurer Datenbänke mit Besitzern und anderen sicherheitskritischen Einstellungen zu erhalten, könnt ihr meinen Skript von Technet verwenden: https://gallery.technet.microsoft.com/scriptcenter/Database-Owners-role-3af181f5/

Wenn ich raten darf: Mehr als die Hälfte von euch verwendet „sa“ (siehe: SQL Server Datenbankbesitz: Umfrageergebnisse und Empfehlungen ). Die meisten der anderen werden ein Windows-Konto mit sysadmin-Mitgliedschaft verwenden.

Hier könnt ihr die Datenbankbesitzer in SSMS finden:

Ich habe immer gegen den Gebrauch von sa als Datenbankbesitzer plädiert, und hier ist jetzt ein weiteres Puzzleteil dafür, weswegen.

Voraussetzung Nr. 2 – Berechtigungen zu impersonieren:

Dies mag zunächst etwas komplexer scheinen. Aber am Ende ist auch das sehr einfach:

Wir müssen dies unter einem Konto laufen lassen, das gerade genügend Berechtigungen hat, den Datenbankbesitzer zu impersonieren.

Frage 1: Wer kann dbo impersonieren?

Antwort: Jeder mit einer IMPERSONATE-Berechtigung auf dbo. Ihr werdet wahrscheinlich nicht sehen, dass diese explizite Berechtigung oft verwendet wird.
ABER: Die eingebaute Rolle “db_owner” hat diese Berechtigung (!).

Frage 2: Von welchen Datenbankrollen sind eure Datenbankanwendungen Mitglied?

Basierend darauf, was ich in der Praxis sehe, verwenden Anwendungen meistens eins der folgenden:

1) Mitgliedschaft bei db_datareader und db_datawriter-Rollen + eine Form von einer “db_executor” Rolle.

2) Einige benutzerdefinierte Rollen

3) db_owner – traurigerweise und meistens, da es als zu zeitintensiv betrachtet wird über benutzerdefinierte Berechtigungssets und Schema-Einschränkungen nachzudenken.

Voraussetzung Nr. 3 – Datenbank vertrauenswürdig:

Nun der letzte Puzzleteil: Der letzte Mechanismus, der uns davon abhält, Zugriff auf Objekte außerhalb der Datenbank zu erhalten, ist, dass dem Datenbankcode expliziert vertraut werden muss, um außerhalb der Datenbankebene zu laufen. Die „saubere“ Art, dies zu tun, ist es, Module, die mit Zertifikaten signiert wurden, zu verwenden.

Aber es gibt noch eine andere Methode, und das ist das Trustworthy-bit. Im Wesentlichen bedeutet dies, dass jedem Code, der aus innerhalb dieser Datenbank entstammt, vertraut werden kann und er ausgeführt werden kann. Dann ist es nur eine Frage der Berechtigungen (was der Grund dafür ist, weshalb sa so praktisch für einen Angreifer ist).
Lasst uns dies einmal demonstrieren:

Trustworthy_ALTER_DATABASE

Diese Eigenschaft ist auch innerhalb von SSMS sichtbar:

Trustworthy_DB_Option

Unter Verwendung meines obigen Skripts werdet ihr sofort die problematische Einstellung sehen:

Database_Properties_Owner

Und wenn wir Code als sysadmin laufen lassen, haben wir ALLE Berechtigungen, stimmt‘s?

Alles, was man braucht, um Code als Datenbankbesitzer ausführen zu können, der wiederum sysadmin ist. Dafür haben wir den Befehl „EXECUTE AS“.

Wenn wir all diese Puzzleteile zusammensetzen, können wir wie folgt vorgehen:

Angriff

Nehmen wir SQL-Injection, eine uralte Angriffsmethode, die bis jetzt nicht verschwunden ist (wenn ich einen Wunsch frei hätte: „Bitte schult eure neuen Entwickler.“) Stellt euch vor, dass der Angreifer in der Lage ist, SQL Code mit seinen eigenen Befehlen zu injizieren. So wie im Folgenden:

  ?‘ UNION SELECT IS_SRVROLEMEMBER (’sysadmin‘) , IS_MEMBER (‚db_owner‘) , USER_NAME() — checking the account this command is running under

Wenn der gegenwärtige Anwendungsnutzer, in meinem Fall ein SQL-Konto „WebAppOwner“ Mitglied der Rolle „db_owner“ ist, kann er den folgenden Befehl via SQL-Injection ausführen:

privilege_elevation_SQL

Und FERTIG!

Er hat sich gerade selbst zum sysadmin gemacht.

Alternativ könnte er ein anderes Login für seine eigenen Bedürfnisse kreieren und versuchen, es zu verstecken, indem er Systemcode manipuliert (das ist eine andere Geschichte, aber ich werde höchstwahrscheinlich niemals dazu kommen, darüber zu bloggen ;-)).

Von hier aus kann er alles tun, wonach ihm ist. Eine fachkundige Person kann dann sogar Windows Services auf der Maschine installieren (in meinen Demo-Sessions habe ich eine FTP-Server-Rolle zum System hinzugefügt, nur um euch eine Ahnung davon zu vermitteln). Nur Eure Fantasie ist die Grenze. Sogar eine Erweiterung bis hin zum Windows-Domänenadministrator ist sehr gut möglich, wenn ihr einmal den SQL Server besitzt. Dies werde ich jedoch nicht weiter ausführen.

Ich hoffe, ich habe euch überzeugt:

BITTE VERWENDET NICHT „TRUSTWORTHY” als Abkürzung, um bestimmten Code zu ermöglichen. Verwendet ordnungsgemäß signierten Code. Verwendet Zertifikate.

Übrigens:

Jetzt kennt ihr den Grund dafür, warum diese Einstellung NICHT während einer Datenbank-Wiederherstellung oder Attach weitergegeben wird: Es ist einfach zu gefährlich und muss explizit von einem sysadmin eingestellt werden, nachdem er die Datenbank online gebracht hat (das müsst ihr auch berücksichtigen, wenn ihr Verfügbarkeitsgruppen (Availability Groups) verwendet!).

Hoffentlich habe ich einige von euch erreicht, die sich unsicher waren, ob trustworthy wirklich bedeutsam ist, und habe euch überzeugt, es zu vermeiden. Selbst wenn ihr gerade nicht die Kombination all dieser 3 Voraussetzungen aktiv habt: Systeme neigen dazu, sich zu verändern, und ihr könnt es aus den Augen verlieren und den Zeitpunkt verpassen, wenn alles zusammenkommt. Am Ende sich zu entschuldigen hilft nicht, beugt vor.

 

Fröhliches Sichern eurer Datenbanken

Andreas

0 Kommentare

Dein Kommentar

An Diskussion beteiligen?
Hinterlasse uns Deinen Kommentar!

Schreibe einen Kommentar

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