CONTROL SERVER gegen Sysadmin/sa:
Berechtigungen, Systemprozeduren, DBCC, automatische Schema-Erstellung und Privilegienausweitung – Fallstricke
Seit SQL Server 2005 gibt es die Serverweite Berechtigung CONTROL SERVER. Prinzipiell eine Alternative zur sysadmin-Mitgliedschaft, blieb sie dennoch nicht viel mehr als ein Ladenhüter – kaum bekannt und noch weniger verwendet.
Einer der Hauptgründe dafür war die fehlende Möglichkeit, dieses Recht einer Gruppe von Prinzipalen/Logins auf Server-Ebene zu geben.
Seit SQL Server 2012 ist es ja nun möglich, eigene Server-Rollen zu definieren, so dass diese Berechtigung nun immer mehr Verwendung findet.
Dennoch ist sie kein vollständiger Ersatz für sysadmin. Warum das so ist wo die Unterschiede liegen und wo es sogar ein Risiko sein kann, möchte ich im Folgenden für meine Leser festhalten und demonstrieren.
Grundlegende Kenntnisse über das Verhalten von sysadmin und dbo setze ich als hinreichend bekannt voraus, und konzentriere mich auf das, was bei der Verwendung von CONTROL SERVER anders ist.
Zunächst wird ein neuer Login, „DBA_TheDude“, angelegt – das Passwort natürlich streng meinen Richtlinien (für Blogs) entsprechend. 😉
Es folgen eine neue Serverrolle, „Role_DBA“, in die der Login als Mitglied aufgenommen wird.
Und da diese Rolle für Administratoren gedacht ist, erhält sie die weitest-möglichen Rechte: CONTROL SERVER.
Als nächstes melden wir uns als DBA am System an und lassen uns „die (effektiven) Rechte verlesen“ 🙂
entity_name | permission_name |
server | CONNECT SQL |
server | SHUTDOWN |
server | CREATE ENDPOINT |
server | CREATE ANY DATABASE |
server | CREATE AVAILABILITY GROUP |
server | ALTER ANY LOGIN |
server | ALTER ANY CREDENTIAL |
server | ALTER ANY ENDPOINT |
server | ALTER ANY LINKED SERVER |
server | ALTER ANY CONNECTION |
server | ALTER ANY DATABASE |
server | ALTER RESOURCES |
server | ALTER SETTINGS |
server | ALTER TRACE |
server | ALTER ANY AVAILABILITY GROUP |
server | ADMINISTER BULK OPERATIONS |
server | AUTHENTICATE SERVER |
server | EXTERNAL ACCESS ASSEMBLY |
server | VIEW ANY DATABASE |
server | VIEW ANY DEFINITION |
server | VIEW SERVER STATE |
server | CREATE DDL EVENT NOTIFICATION |
server | CREATE TRACE EVENT NOTIFICATION |
server | ALTER ANY EVENT NOTIFICATION |
server | ALTER SERVER STATE |
server | UNSAFE ASSEMBLY |
server | ALTER ANY SERVER AUDIT |
server | CREATE SERVER ROLE |
server | ALTER ANY SERVER ROLE |
server | ALTER ANY EVENT SESSION |
server | CONTROL SERVER |
Klingt gut. Scheint Nichts zu fehlen. Oder doch?
Vergleichen wir es mal mit der Liste aller Rechte, die es auf Server-Ebene überhaupt gibt:
Ok, also wir haben wirklich alle Rechte, die man (auf Serverebene) vergeben kann. Das ist auch dokumentiert: Permissions (Database Engine) und hier: GRANT Server Permissions (Transact-SQL)
Diese Berechtigungen und Kommandos funktionieren auch wie dokumentiert.
Wie sieht es aber mit gespeicherten Systemprozeduren aus?
Warum das jetzt?
Ganz einfach. Sicher ist es den meisten noch gut aus SQL Server 2000-Zeiten bekannt, dass sicherheitskritische Systemprozeduren einen Check auf Mitgliedschaft in bestimmten Rollen enthalten. Und das tun die meisten derer auch heute noch. Ein Artefakt der damaligen unflexiblen Rechte-Verwaltung, kann man sagen.
Wenn man in den Code der sp_readerrorlog schaut, wird es dort genau so gemacht:
Okay. Natürlich könnten wir diesen Code umgehen und die xp_readerrorlog direkt aufrufen.
In der GUI-Anzeige im Management Studio hilft uns das nicht, wir können es als manuellen Workaround verwenden.
Weitere Systemprozeduren, die über SSMS aufgerufen werden und die Ausführung verweigern sind unter anderem: sp_addumpdevice – für Backup-Devices sp_enum_oledb_providers – wird beim Konfigurieren und Betrachten von Linked Servers verwendet.
sp_addlinkedserver lässt sich dafür ohne Probleme ausführen – nur eben nicht über die GUI wegen eben genannter Prozedur.
Die Einrichtung von Database-Mail über die GUI bleibt ebenfalls den sysadmins vorbehalten. Via Script sollte es jedoch funktionieren (ungetestet).
Auch die Konfiguration des Distributors für die Replikation mittels sp_adddistributor ist ohne den sysadmin-Bit nicht möglich. Andere Replikationskonfigurationsaufgaben sind teilweise sogar über die GUI möglich.
Unter SQL Server 2005 – 2008R2 gibt es für das Hinzufügen/Entfernen von (Server-)Rollenmitgliedern nur die Prozedur sp_addsrvrolemember / sp_dropsrvrolemember. Diese führt ebenfalls eine Serverrollen-Mitgliedschafts-Prüfung durch. – Unter SQL Server 2012 ist diese Prozedur aus Rückwärtskompatibilitätsgründen noch vorhanden, jedoch wurde dieser Check aus dem Code entfernt. Damit verhält sie sich in dieser Hinsicht somit wie der direkte Aufruf von ALTER SERVER ROLE {RoleName} ADD MEMBER {Loginname}.
Das gleiche gilt für sp_addrolemember / sp_droprolemember für Datenbankrollen.
Soweit zu Systemprozeduren. Eigentlich ziemlich simpel, wenn man die Hintergründe kennt.
Daher, wo möglich: DDL-Kommandos verwenden, wie seit SQL Server 2005 nahegelegt wird.
Randnotiz: Es gibt mindestens 7 Variationen der Prüfung auf sysadmin-Mitgliedschaft. 🙂 🙁
Eine Kostprobe:
Die häufigsten Fehlermeldungen, die dann ggfls. ausgelöst werden, sind:
message_id | text |
14126 | Sie haben nicht die erforderlichen Berechtigungen, um den Vorgang abzuschließen. |
14260 | Sie haben nicht die erforderliche Berechtigung, um diesen Befehl auszuführen. Wenden Sie sich an den Systemadministrator. |
15003 | Nur Mitglieder der %1!-Rolle können diese gespeicherte Prozedur ausführen. |
15247 | Der Benutzer besitzt nicht die Berechtigung zum Ausführen dieser Aktion. |
21089 | Nur Mitglieder der festen Serverrolle ’sysadmin‘ können diesen Vorgang ausführen. |
22904 | Der Aufrufer ist nicht zum Initiieren der angeforderten Aktion berechtigt. Es sind DBO-Privilegien erforderlich. |
Das geht ja gut los.
Die „Regel“ ist bei DBCC noch einfacher: Fast jedes DBCC-Kommando prüft auf sysadmin.
Von DBCC CHECKDB über DBCC LOGINFO bis zu DBCC TRACEON. Also auch durchaus wertvolle Kommandos auch für den externen Support. – Tatsächlich ist selbst DBCC HELP nur für sysadmins zugelassen…
Die einzigen Ausnahmen, die mir bekannt sind: DBCC SHOW_STATISTICS
- man muss jedoch mindestens ddl_admin oder Besitzer der Tabelle sein
DBCC DETACHDB
- das ist ein spezieller Fall, da es über sp_detach_db ausgeführt wird
- db_owner oder dbo der datenbank ist ausreichend
DBCC FREEPROCCACHE und DBCC SQLPERF
- Diese setzen lediglich die ALTER SERVER STATE Berechtigung voraus.
DBCC DROPCLEANBUFFERS wiederum setzt die sysadmin-Rollenmitgliedschaft voraus.
Diese Berechtigungen sind übrigens recht gut dokumentiert.
Datenbankberechtigungen
Mit CONTROL SERVER hat ein Prinzipal auch vollen Zugriff auf alle Datenbanken. Fast, aber auch nur fast wie sysadmins, die bekanntlich auf den „dbo“ gemappt werden.
Logins mit lediglich CONTROL SERVER-Berechtigung werden nicht(!) zu dbo gemapped.
Welche Auswirkungen das hat, sieht man im Folgenden:
Was ist passiert?
Erinnern Sie sich noch an das pre-SQL 2012 Problem, dass man Windows-Gruppen kein Default Schema zuweisen konnte? Und was passierte, wenn ein Entwickler über solch eine Gruppe vergaß, beim Anlegen eines Objektes das Schema anzugeben?
Richtig. Das ist genau das gleiche: es wurde ein Schema mit dem Login-Namen des Entwicklers angelegt. Eine reine Freude für spätere Aufräumarbeiten, die „richtigen falschen“ Schemas zu identifizieren und zu löschen. Dieses Issue (eines der am höchsten votierten Connect-Items) wurde mit SQL Server 2012 ja gelöst.
Leider wurde dabei verpasst, auch die Behandlung von CONTROL SERVER Berechtigten anzupassen. Dazu hatte ich ebenfalls ein Connect-Item erstellt.: „Login with CONTROL SERVER Permission Creating an Object without specifying Schema leads to creation of new Schema with Login-Name”. – Leider zu spät. :-/
Vermutlich wird dazu ein identischer Code-Block verwendet, denn genau wie in dem Windows-Gruppen-Szenario ist dieses implizite Anlegen des Schemas nicht abfangbar.
Fazit: Immer ein Schema angeben, wenn man als CONTROL Server Berechtigter Objekte anlegt – am besten einfach wirklich immer ein Schema angeben (es gibt noch andere Gründe dafür).
Privilege-Escalation-Risiko:
Abschließen möchte ich mit einem sicherheitstechnisch extrem wichtigen Hinweis:
Logins mit CONTROL SERVER Berechtigung können standardmäßig JEDEN Login impersonifizieren. JEDEN. Also auch alle Sysadmins und sa selber! – Und auch wenn SQL Authentifizierung nicht aktiv ist!
Und so lässt sich das wunderbar ausnutzen:
Wer sich also gegenüber dieser Form von Privilege-Escalation schützen möchte, muss das impersonate (mithilfe von DENY) verbieten. – Und warum sollte man das nicht wollen, würde es doch ggfl. das gesamte Konzept von CONTROL SERVER in Frage stellen (?! ) – Denn das ist der finale und entscheidende Unterschied:
Sysadmin-Mitglieder können nicht mit DENY eingeschränkt werden. Prinzipale mit bloßer CONTROL SERVER Berechtigung jedoch schon.
So funktionieren alle reinen DDL/DML Kommando-Berechtigungen eben.
Also, um es noch einmal klar zu sagen, da es so entscheidend ist:
Ein Login mit CONTROL SERVER Recht macht nur dann Sinn, wenn ihm gleichzeitig verboten wird, andere sysadmins (oder am besten: alle Logins) zu impersonifizieren. Andernfalls kann man ihn gleich zum sysadmin machen!
Dummerweise geht das nur über „DENY IMPERSONATE ON LOGIN::[Loginname]“. Denn IMPERSONATE ist hierarchisch direkt CONTROL SERVER untergeordnet!
Bei einer sich ändernden Liste an Systemadministratoren hat man ein Problem, wenn man nicht an dieses Deny denkt! (Nächstes Risiko!)
– Spätestens an dieser Stelle sollte man sich mit dem Überwachungs-Feature von SQL Server befassen.
Mein Fazit und Lessons-learned daher:
CONTROL-SERVER selber ist eine konsequente Fortführung der Bemühungen des Sicherheits-Teams, SQL Server sicherheitstechnisch noch einfacher und damit robuster zu machen.
Jedoch ist aus dem Grund der Impersonate-Rechte eine Privilege Escalation zu sysadmin sehr einfach. Um diese zu verhindern, sollte man gut mit der Berechtigungs-Hierarchie von SQL Server vertraut sein. – Wie immer: „Wissen schafft Sicherheit.“
Was wirklich schmerzt, ist eines der besten Anwendungsszenarien: Rechte für Support-Personal, intern oder Extern. Das Fehlen der Möglichkeit, DBCC-Kommandos direkt zu berechtigen, macht uns hier einen Strich durch die Rechnung. Wenn man nicht jedes wichtige DBCC-Kommando in eine eigene Prozedur wrappen und somit berechtigen möchte, führt am sysadmin in diesen Anwendungsfällen nichts vorbei. (!)
Im Endeffekt ist eine strikte „Separation of Duties“, die Funktionstrennung auf verschiedene „Rollen“ das eherne Ziel.
Hier kann man dazu Nachlesen – auch das „SQL Server Separation of Duties Framework“ von codeplex, mit vielen guten Ideen kann ich empfehlen einmal anzusehen:
https://techcommunity.microsoft.com/t5/SQL-Server/Separation-of-Duties-for-DBA-s/ba-p/383915
Update 04-2014:
Mit SQL Server 2014 wird CONTROL Server etwas sicherer. Hier kann man mehr zu den neuen Möglichkeiten lesen:
Eine Ablösung des „sa“ ist übrigens nicht geplant, jedoch sinkt mit jedem Release die Anzahl der Szenarien, wo sa/sysadmin zwingend benötigt wird.
Happy securing,
Andreas
Anbei die komplette Liste aller Systemprozeduren unter SQL Server 2012, die auf sysadmin-Rollenmitgliedschaft prüfen (171 – gegenüber 173 unter SQL Server 2008R2. SQL Server 2014 CTP1 ist noch das Gleiche):
(Hinweis: Insgesamt 197 Systemprozeduren prüfen auf Serverrollenmitgliedschaft, wie diskadmin oder serveradmin usw.)
Module_Name |
fn_yukonsecuritymodelrequired |
sp_add_agent_parameter |
sp_add_agent_profile |
sp_adddatatype |
sp_adddistributiondb |
sp_adddistributor |
sp_addqreader_agent |
sp_addsubscriber |
sp_addsubscriber_schedule |
sp_addtabletocontents |
sp_attachsubscription |
sp_cdc_cleanup_change_table |
sp_cdc_disable_db |
sp_cdc_disable_table |
sp_cdc_drop_job |
sp_cdc_enable_db |
sp_cdc_enable_table |
sp_cdc_restoredb |
sp_cdc_vupgrade |
sp_certify_removable |
sp_change_agent_parameter |
sp_change_agent_profile |
sp_change_subscription_properties |
sp_change_users_login |
sp_changedistpublisher |
sp_changedistributiondb |
sp_changedistributor_password |
sp_changedistributor_property |
sp_changemergesubscription |
sp_changeqreader_agent |
sp_changereplicationserverpasswords |
sp_changesubscriptiondtsinfo |
sp_checkinvalidivarticle |
sp_copysubscription |
sp_create_removable |
sp_cycle_errorlog |
sp_dbcmptlevel |
sp_dbmmonitoraddmonitoring |
sp_dbmmonitorchangealert |
sp_dbmmonitordropalert |
sp_dbmmonitordropmonitoring |
sp_dbmmonitorhelpalert |
sp_dbmmonitorhelpmonitoring |
sp_dbmmonitorresults |
sp_dbmmonitorupdate |
sp_dbremove |
sp_drop_agent_parameter |
sp_drop_agent_profile |
sp_dropdatatypemapping |
sp_dropdistpublisher |
sp_dropdistributiondb |
sp_dropdistributor |
sp_dropmergepullsubscription |
sp_droppullsubscription |
sp_dropsubscriber |
sp_dsninfo |
sp_enumdsn |
sp_flush_commit_table_on_demand |
sp_generate_agent_parameter |
sp_get_distributor |
sp_get_Oracle_publisher_metadata |
sp_getagentparameterlist |
sp_getdefaultdatatypemapping |
sp_grant_publication_access |
sp_help_agent_default |
sp_help_agent_parameter |
sp_help_agent_profile |
sp_helpdistpublisher |
sp_helpdistributor |
sp_helpmergesubscription |
sp_helpqreader_agent |
sp_helpreplicationdboption |
sp_identitycolumnforreplication |
sp_IHValidateRowFilter |
sp_IHXactSetJob |
sp_link_publication |
sp_monitor |
sp_MSadd_distribution_agent |
sp_MSadd_logreader_agent |
sp_MSadd_merge_agent |
sp_MSadd_snapshot_agent |
sp_MSadd_subscriber_schedule |
sp_MSadd_tracer_history |
sp_MSadd_tracer_token |
sp_MScdc_cleanup_job |
sp_MScdc_db_ddl_event |
sp_MScdc_ddl_event |
sp_MSchange_distribution_agent_properties |
sp_MSchange_logreader_agent_properties |
sp_MSchange_merge_agent_properties |
sp_MSchange_snapshot_agent_properties |
sp_MSchangedynamicsnapshotjobatdistributor |
sp_MSchangedynsnaplocationatdistributor |
sp_MScheck_pull_access |
sp_MScleanupmergepublisher_internal |
sp_MSclear_dynamic_snapshot_location |
sp_MScreate_dist_tables |
sp_MSdbuserpriv |
sp_MSdeletefoldercontents |
sp_MSdrop_6x_replication_agent |
sp_MSdrop_merge_agent |
sp_MSdrop_snapshot_dirs |
sp_MSdropmergedynamicsnapshotjob |
sp_MSdynamicsnapshotjobexistsatdistributor |
sp_MSenumallpublications |
sp_MSfetchAdjustidentityrange |
sp_MSfix_6x_tasks |
sp_MSforce_drop_distribution_jobs |
sp_MSget_agent_names |
sp_MSget_jobstate |
sp_MSget_oledbinfo |
sp_MSget_publication_from_taskname |
sp_MSgetdbversion |
sp_MSgetmaxsnapshottimestamp |
sp_MShelp_repl_agent |
sp_MShelp_replication_status |
sp_MShelp_snapshot_agent |
sp_MShelpconflictpublications |
sp_MShelpdynamicsnapshotjobatdistributor |
sp_MShelplogreader_agent |
sp_MShelpsnapshot_agent |
sp_MShelptranconflictcounts |
sp_MSinit_publication_access |
sp_MSreinit_failed_subscriptions |
sp_MSremoveoffloadparameter |
sp_MSrepl_backup_complete |
sp_MSrepl_backup_start |
sp_MSrepl_createdatatypemappings |
sp_MSrepl_dropdatatypemappings |
sp_MSrepl_enumarticlecolumninfo |
sp_MSrepl_enumpublications |
sp_MSrepl_enumpublishertables |
sp_MSrepl_enumsubscriptions |
sp_MSrepl_enumtablecolumninfo |
sp_MSrepl_getdistributorinfo |
sp_MSrepl_startup_internal |
sp_MSreplagentjobexists |
sp_MSreplcheck_permission |
sp_MSreplcheck_pull |
sp_MSreplcheck_subscribe |
sp_MSreplcheck_subscribe_withddladmin |
sp_MSreplcopyscriptfile |
sp_MSreplremoveuncdir |
sp_MSsetalertinfo |
sp_MSSetServerProperties |
sp_MSsetupnosyncsubwithlsnatdist |
sp_MSsetupnosyncsubwithlsnatdist_cleanup |
sp_MSsetupnosyncsubwithlsnatdist_helper |
sp_MSstartdistribution_agent |
sp_MSstartmerge_agent |
sp_MSstartsnapshot_agent |
sp_MSstopdistribution_agent |
sp_MSstopmerge_agent |
sp_MSstopsnapshot_agent |
sp_MSupdate_agenttype_default |
sp_oledbinfo |
sp_procoption |
sp_removedbreplication |
sp_removesrvreplication |
sp_replication_agent_checkup |
sp_replicationdboption |
sp_resetstatus |
sp_restoredbreplication |
sp_SetAutoSAPasswordAndDisable |
sp_setdefaultdatatypemapping |
sp_updatestats |
sp_validatelogins |
sp_vupgrade_mergeobjects |
sp_vupgrade_replication |
sp_vupgrade_replsecurity_metadata |
xp_repl_convert_encrypt_sysadmin_wrapper |
Hinterlasse einen Kommentar
An der Diskussion beteiligen?Hinterlasse uns deinen Kommentar!