Category: "Security"

SQL Server Database Ownership: survey results & recommendations

SQL Server Datenbankbesitz: Umfrageergebnisse und Empfehlungen

(en)
You may remember the survey on database ownership which I launched several months ago.

In the following, I am now presenting the results and giving my official recommendation for a best practice for security in terms of database ownership.
First, if you still need the script:

(de)
Ihr erinnert Euch vielleicht an die Umfrage zu Datenbankbesitz, die ich vor einigen Monaten gestartet habe.
Hier präsentiere ich nun die Ergebnisse und gebe meine offiziellen Empfehlungen für Sicherheits-Best Practice hinsichtlich Datenbankbesitz.
Zunächst, wer noch den Script benötigt:

 

Server 1: http://j.mp/13_SQL_DBO_Survey
Server 2: gallery.technet.microsoft.com/scriptcenter/Database-Owners-role-3af181f5/

 

Now first the results.
I received data from 58 different servers and 905 databases altogether.
That’s not bad, and sufficient for my purpose of giving you, my readers, the opportunity to find out how others configure their servers.

Many thanks to all those who submitted!
You may still share results but I can’t promise how soon I can include them. (Here is the survey plus the script for collection)
So now to the details. I put the most interesting data in charts.
The most obvious issue is that of the external owner’s account, which is most often and not very surprisingly sa:

Nun zuerst einmal die Ergebnisse.

Ich habe insgesamt von 58 verschiedenen Servern und 905 Datenbanken Daten erhalten.

Das ist nicht schlecht. Und es ist ausreichend für meine Zwecke – Euch, meinen Lesern, die Gelegenheit zu gegeben herauszufinden, wie andere ihre Server konfigurieren.

Vielen Dank an alle, die ihre Daten eingereicht haben!

Ihr könnt eure Ergebnisse immer noch mit mir teilen, aber ich kann euch nicht versprechen, wie bald ich sie mit einschließen kann. (Hier sind die Umfrage sowie das Skript für die Datenerfassung.)

Nun zu den Details. Ich habe die interessantesten Daten in Diagramme gesetzt.

Die offensichtlichste Frage ist die des Kontos des externen Besitzers, das am häufigsten und nicht überraschenderweise sa ist:

 SQL_Server_External_Database_Owner_pct

 

57% of all databases belong to sa himself. Actually, this is better than expected. But let’s dive further – what’s the server role behind the remaining 42%?

57% aller Datenbanken gehören sa selbst. Dies ist sogar besser als erwartet. Aber schauen wir mal genau hin – was ist die Server-Rolle hinter den verbleibenden 42%?

 SQL_Server_Role_Membership_of_Database_Owner_pct

 

Ok, that changes the picture quite a bit. Almost 80% of all Database owners are sysadmin. So that is by no means any better than sa.
Then some other accounts follow, which means those have low privileges (“excellent”), and then comes dbcreator, securityadmin, that are later followed by some other high privileged server roles, though with much less power.

So in other words: only 7% of all those databases have been looked at with security in mind by only using low privileged accounts as owners.

If you are interested in the plain numbers, here they go:

Ok, das verändert das Bild schon entscheidend. Fast 80% aller Datenbankenbesitzer sind sysadmin. Das ist also keineswegs besser als sa.
Es folgen einige andere Konten, das bedeutet, dass diese niedrige Privilegien (“hervorragend”) haben, und dann folgen dbcreator, securityadmin, auf die später einige andere hochprivilegierten Serverrollen folgen, doch mit weitaus weniger Privilegien.

Mit anderen Worten: nur 7% aller dieser Datenbanken wurden im Hinblick auf Sicherheit betrachtet, indem von Besitzern nur niedrigprivilegierte Konten verwendet wurden.

Wenn euch die genauen Zahlen interessieren, hier sind sie:

 SQL_Server_Role_Membership_of_Database_Owner_num

I did include some of the security-wise critical database- & server configurations:

  1. Is the database set to be “Trustworthy”?
  2. Is the database set to have “Database chaining on”?
  3. Is the Server set to have “cross database chaining on”?

Those are actually the even more important results.

Since the system databases need to have a different setting by default, I am excluding them, making it a total of 847 User databases.
Of which 30 have the trustworthy bit set to on, and 35 have the database chaining.
What you can’t see in this graph, but what I can tell from the raw data, is that those 30 “trustworthy” databases all are owned by a sysadmin.
And THIS now is the biggest security-hole in this area!
Here a graph on that:

Ich habe einige der sicherheitstechnisch kritischen Datenbank- und Serverkonfigurationen mit eingeschlossen:

  1. Ist die Datenbank auf „Trustworthy“ eingestellt?
  2. Ist in der Datenbank „Datenbank-Verkettung an“ eingestellt?
  3. Ist im Server „cross database chaining on“ eingestellt?

Diese sind eigentlich die wichtigeren Ergebnisse.

Da die Systemdatenbanken standardmäßig eine andere Einstellung haben müssen, schließe ich sie in meiner Bewertung aus, so dass ich auf insgesamt 847 Nutzer-Datenbanken komme.
30 von ihnen haben das Trustworth-Bit eingestellt, und 35 haben die Datenbanken-Verkettung eingeschaltet.
Was ihr in dieser Grafik nicht sehen könnt, aber was ich aus den Rohdaten erkennen kann, ist, dass diese 30 „vertrauenswürdigen“ Datenbanken alle im Besitz von einem sysadmin sind.
Und DAS ist das größte Sicherheitsloch in diesem Bereich!
Hier ein Diagramm dazu:

 

SQL_Server_Critical_Database_Settings 

In the interest of time I will focus this post on recommendation rather than explaining all the risks involved. At the end though I will provide some links for further reading.

Aus Zeitgründen werde ich diesen Eintrag auf Empfehlungen beschränken, als alle Risiken zu erklären. Am Ende werde ich jedoch einige Links für weiterführende Lektüre angeben.

Possibilities

So what are the general variations of database ownership?
Let me start with the most common and actually WORST possibilities (Yes, I mean it exactly as I say ;-) ):

  1. SA-Account
  2. Some other SQL-Account with sysadmin privileges
  3. Windows Login with sysadmin privileges

A first improvement(? – really?):

      4. Any of the above with Status = Disabled

 And then:

     5.   A ”shared” account without any special server role or permissions (aka “1 Account per Server”)

     6.   1 Account per Database

     7.    1 Account per Application

     8.   1 Account per Group of databases

 + all of them not only Disabled but with a Denied Connect-Permission

Möglichkeiten

Was sind also die allgemeinen Variationen von Datenbanken-Besitztum?

Fangen wir mit den häufigsten und eigentlich SCHLECHTESTEN Möglichkeiten an (Ja, das meine ich genau so, wie es hier steht ;-) ):

 

  1. SA-Konto
  2. Irgendein anderes SQL-Konto mit sysadmin-Privilegien
  3. Windows Login mit sysadmin-Privilegien

 Eine erste Verbesserung(? – wirklich?):

     4.   Alle der oben angegebenen mit Status = Deaktiviert

 Und dann:

     5.     Ein „geteiltes“ Konto ohne eine spezielle Serverrolle oder Rechte (Alias „1 Konto pro Server“)

     6.   1 Konto pro Datenbank

     7.   1 Konto pro Anwendung

     8.   1 Konto pro Datenbank-Gruppe

 + alle davon nicht nur Deaktiviert sondern mit einer verweigerten Verbindungs-Berechtigung 

My Recommendation:

Depending on your environment: Any of 5, 6, 7 or 8:

Create a specific Login without any extra permissions + Deny Connect.

The most simple approach and yet better than sa is: one database owner per server.
Example for (5):

  • Database1 owned by DBOwner
  • Database2 owned by DBOwner
  • Database3 owned by DBOwner

 Simple and self-explanatory.

The other extreme and most secure is: per database.
Example for (6):

  • Database1 owned by DBOwner_Database1
  • Database2 owned by DBOwner_Database2
  • Database3 owned by DBOwner_Database3
  • Database4 owned by  DBOwner_Database4

 Some applications use a number of different databases. For them it’s perfectly fine to use the same database owner account. So create an account per application.

Example for (7):

  • App1Database1 owned by DBOwner_App1
  • App1Database2 owned by DBOwner_App1
  • App2Database1 owned by DBOwner_App2
  • App2Database owned by  DBOwner_App2

 Another approach is kind of a compromise between 1 Database-Owner Account per Server and One per database: Define the level of security needed per database. Then create a dedicated account for the most critical Databases. And for the others use a shared owner/account, possibly divided in 2 or more groups.

Example for (8):

  • CriticalDatabase1 owned by DBOwner_Level1Dedicated1
  • CriticalDatabase2 owned by DBOwner_ Level1Dedicated2
  • Level2Database1 owned by DBOwner_Level2
  • Level2Database2 owned by DBOwner_Level2

 I hope my samples give you an idea. :-)

So why this effort?
Let me put it this way: ”Why not sa?”.
First: If you think about it, it actually makes little sense that the highest privileged account in SQL Server is being recommended by so many, even professionals + in Whitepapers (!) – when security is the focus. It is really wrong, as wrong as it could possibly get.
I mean, as you can see, there are other options out there.
The top reason why SA keeps getting recommended is administration itself: It eases the setup for failover and regular database restores, since SA is always available at any server and hence a broken database owner can be avoided with almost no extra work.
But that’s “only” from a perspective of maintenance.
With regard to security it is totally on contrary to the Principle of least privilege.

It may not matter a lot, if everything else is tightened, but that’s hardly a thing to rely on especially in bigger environments where things change and many people have access and permissions to.
Especially in the context of the trustworthy-setting for a database, this completely opens the system for privilege escalation attacks from inside. It is then a piece of cake to gain system level permissions once you are for example in the db_owner database group – like many applications are, if they are not sysadmin already.
- Remember: the owner of a database cannot be denied anything inside and with his database. So he can change structure, create backups, break log-backup-chain and also drop it completely.

And since the attack starts from inside, it really doesn’t matter whether the sa/sysadmin account is disabled as you may now realize.

Having a dedicated account with zero special permissions as database owner prevents database principals from gaining system level permissions as a sysadmin has, even in the case of the database being trustworthy.
And trustworthy is one of the dirty little shortcuts for developers implementing CLR code inside the database and avoiding the hassle of having to use certificates under certain conditions. The same is often done for code that needs to get server-level data from inside the database.

Meine Empfehlung:

Abhängig von eurer Umgebung: eine von 5, 6, 7 oder 8:

Ein spezifisches Login errichten ohne extra  Rechte + Deny Connect.

Die einfachste Herangehensweise und doch besser als sa ist: ein Datenbankbesitzer pro Server.

Beispiel für (5):

  • Datenbank1 im Besitz von DBOwner
  • Datenbank2 im Besitz von DBOwner
  • Datenbank3 im Besitz von DBOwner

 Einfach und selbsterklärend.

 Das andere Extrem und dabei die sicherste ist: pro Datenbank.

Beispiel für (6):

  • Datenbank1 in Besitz von DBOwner_Database1
  • Datenbank2 in Besitz von DBOwner_Database2
  • Datenbank3 in Besitz von DBOwner_Database3
  • Datenbank4 in Besitz von DBOwner_Database4

Einige Anwendungen verwenden eine Reihe von unterschiedlichen Datenbanken. Für sie ist es völlig ausreichend, das gleiche Datenbankbesitzerkonto zu verwenden. Erstellt also ein Konto pro Anwendung.

Beispiel für (7):

  • App1Database1 in Besitz von DBOwner_App1
  • App1Database2 in Besitz von DBOwner_App1
  • App2Database1 in Besitz von DBOwner_App2
  • App2Database in Besitz von DBOwner_App2

Eine andere Herangehensweise ist eine Art Kompromiss zwischen 1 Datenbankenbesitzerkonto pro Server und einem pro Datenbank: Definiere das Sicherheitslevel, das je Datenbank gebraucht wird. Dann erstelle ein spezielles Konto für die kritischsten Datenbanken. Und für die anderen Besitzer einen gemeinsamen Besitzer-/Konto verwenden, möglicherweise in 2 oder mehr Gruppen geteilt.

Beispiel für (8):

  •  CriticalDatabase1 in Besitz von DBOwner_Level1Dedicated1
  • CriticalDatabase2 in Besitz von DBOwner_ Level1Dedicated2
  • Level2Database1 in Besitz von DBOwner_Level2
  • Level2Database2 in Besitz von DBOwner_Level2

 Ich hoffe, meine Beispiele geben euch eine Vorstellung. :-)

Aber warum diese Mühe?
Lasst es mich so ausdrücken: “Warum nicht sa?”
Zuallererst: Denkt man darüber nach, ergibt es eigentlich wenig Sinn, dass das höchstprivilegierte Konto beim SQL Server von so vielen empfohlen wird, selbst von Profis + in Whitepapers (!) – wenn Sicherheit im Fokus steht. Es ist wirklich falsch, so falsch wie es nur irgend sein kann.

Schließlich gibt es da draußen, wie ihr sehen könnt, noch andere Optionen.

Die Grund Nr. 1, warum SA immer wieder empfohlen wird, ist die Administration selbst: Es erleichtert das Einrichten für Failover und regelmäßige Datenbankenwiederherstellungen, da SA immer auf jedem Server verfügbar ist und damit ein kaputter Datenbankbesitzer mit wenig zusätzlichem Aufwand verhindert werden kann.
Aber das ist „nur“ aus Sicht der Wartung.
Was die Sicherheit angeht, steht es völlig im Gegensatz zum Prinzip des geringsten Privilegs.

Es mag nicht viel ausmachen, wenn alles andere straff sitzt, aber darauf sollte man sich nicht verlassen, besonders in größeren Umgebungen, wo sich Dinge ändern und viele Leute Zugriff und Befugnisse haben.

Besonders im Kontext der Trustworthy-Einstellung für eine Datenbank öffnet dies das System komplett für privilege escalation-Angriffe von innen. Dann ist es ein Kinderspiel, Systemlevel-Befugnisse zu erlangen, wenn man einmal z.B. in der db_owner Datenbankengruppe ist – wie es viele Anwendungen sind, wenn sie nicht bereits sysadmin sind.

Denkt dran: dem Datenbankenbesitzer kann weder innerhalb noch mit seiner Datenbank etwas verweigert werden. Er kann also die Struktur verändern, Backups erstellen, Log-Backup-Chain brechen und sie auch komplett löschen.

Und da der Angriff von innen anfängt, ist es wirklich egal, ob das sa/sysadmin Konto deaktiviert ist, wie ihr jetzt realisiert haben werdet.
Ein spezielles Konto mit Null speziellen Befugnissen als Datenbankbesitzer zu haben hindert Datenbank-Prinzipale daran, System-Level-Befugnisse zu erlangen, wie sie ein sysadmin hat, selbst in dem Fall, dass die Datenbank vertrauenswürdig ist.
Und „trustworthy“ ist eine der unsauberen kleinen Abkürzungen für Entwickler, die CLR-Code im Innern der Datenbank ausführen und sich dabei die Umstände sparen, unter bestimmten Bedingungen Zertifikate benutzen zu müssen. Dasselbe wird oft für Code gemacht, der Server-Level-Daten aus dem Innern der Datenbank erreichen muss.

Call for actions:

Check your databases. You can find my script here: Security-Check-Script & Survey: SQL Server Security - Database-Owners, critical Permissions and role membership
Now when you start with securing your databases from database-ownership standpoint, you have to make sure that the very account does exist at any sever where this database gets restored/failed over. Usually you will have a technique in place already to synchronize your server-level principals to your other servers. So this is just one or several more of them.

Also make sure you fully understand your environment and possibly application needs before you just change the owner of your databases. You can start by reading through the links at the bottom.

Vote for an improvement in SQL Server:
I have created a suggestion as Connect Item which tackles this problem. My idea is having Microsoft include a special “DBOwner” Account at server level by default, which not only pre-exists and has not permissions, but also never compares to another. I think this would make it much easier to get rid of the habit of “sa” everywhere by also making it simple to maintain.
Please vote here: Providing a special Server principal for Database Ownership

Handlungsaufruf:

Überprüft eure Datenbanken. Ihr könnt meinen Skript hier finden: Sicherheitsprüfungs-Script & Umfrage: SQL Server Datenbankbesitzer, kritische Rechte und Rollenmitgliedschaft

Wenn ihr jetzt anfangt, eure Datenbanken aus der Perspektive von Datenbanken-Besitz zu sichern, müsst ihr dabei sicherstellen, dass dasselbe Konto auf jedem Server existiert, wo diese Datenbank wiederhergestellt/failed over wird. Normalerweise werdet ihr bereits eine Technik haben, wie ihr eure Server-Level-Prinzipale mit euren anderen Servern synchronisiert. Das sind also nur eine oder einige mehr davon.

Stellt außerdem sicher, dass ihr eure Umgebung und möglicherweise Anwendungsbedürfnisse vollständig versteht, bevor ihr den Besitzer eurer Datenbanken einfach ändert. Ihr könnt damit anfangen, indem ihr euch unten aufgelisteten Links durchlest.

Abstimmen für eine Verbesserung im SQL Server:
Ich habe einen Vorschlag als Connect Item erstellt, der dieses Problem behandelt. Meine Vorstellung ist es, Microsoft dazu zu bringen, standardmäßig ein spezielles „DBOwner“ Konto auf Server-Level auszuliefern, das nicht nur bereits immer vorab existiert und keine Rechte hat, sondern auch nie mit anderen vergleichbar ist. Ich denke, dass dies es viel einfacher machen würde, die allgegenwärtige Gewohnheit des „sa“ loszuwerden und es gleichzeitig auch einfach Wartbar machen würde.
Bitte hier Eure Stimme abgeben: Providing a special Server principal for Database Ownership

I hope this was helpful.

If you have any questions feel free to comment.
Let me finish up with some links for further readings:

Ich hoffe, das war hilfreich.

Wenn ihr noch Fragen habt, kommentiert gern.
Zum Abschluss einige Links für weiterführende Lektüre:

 

Highly recommended reading:

Dringend empfohlen:

Giving Permissions through Stored Procedures
Ownership Chaining, Certificates and the Problematic EXECUTE AS from Erland Sommarskog

More on Disabling and Deny Connect:

Mehr zu…

DISABLE and DENY LOGIN, DENY USER & Effect on Impersonation and Permissions

More on trustworthy:

 

The TRUSTWORHY bit database property in SQL Server 2005

TRUSTWORTHY Database Property

Extending Database Impersonation by Using EXECUTE AS

Discussions:

Database/Object Ownership Misalignment

database ownership - sa disabled

 

Happy Securing

 

Andreas

New Permissions in SQL Server 2014: IMPERSONATE ANY LOGIN, SELECT ALL USER SECURABLES, CONNECT ANY DATABASE and the old CONTROL SERVER

(DE)
SQL Server 2014 bringt insgesamt 5 neue Berechtigungen. Zwei von diesen sind auf Datenbank-Ebene und nur in der Windows Azure SQL Database Edition verfügbar – nicht im „Box-Produkt“.
(Danke an Erland Sommarskog für die Bestätigung und Hinweis auf die recht versteckte Notiz in der Dokumentation: GRANT Database Permissions)
Die neuen Berechtigungen sind wie folgt:

(EN)
SQL Server 2014 brings altogether 5 new permissions. Two of those are on database level and only available in the Windows Azure SQL Database Edition – not in the box-version (Thanks Erland Sommarskog for confirming this and pointing me to the quite hidden note in the documentation: GRANT Database Permissions)
The new permissions are as follows:

 

Class Desc.

Permission Name

Type

Parent Covering Permission Name

DATABASE

ALTER ANY DATABASE EVENT SESSION

AADS

ALTER ANY EVENT SESSION

DATABASE

KILL DATABASE CONNECTION

KIDC

ALTER ANY CONNECTION

SERVER

CONNECT ANY DATABASE

CADB

 

SERVER

IMPERSONATE ANY LOGIN

IAL

 

SERVER

SELECT ALL USER SECURABLES

SUS

 

 

Und wofür und wie können wir diese neuen Berechtigungen auf Server Ebene verwenden?

 

IMPERSONATE ANY LOGIN

 

Erinnert Ihr Euch an das Problem mit CONTROL SERVER?

Das größte Problem war, das dieses Recht auch die Impersonifizierung eines jeden Kontos, inklusive der Privilegien Erweiterung zum sysadmin erlaubte.

Die Details und auch andere Probleme mit CONTROL SERVER habe ich hier umfassend dokumentiert:

CONTROL SERVER vs. sysadmin/sa: permissions, system procedures, DBCC, automatic schema creation and privilege escalation - caveats

 

SQL Server 2014 gibt uns mit der Einführung der IMPERSONATE ANY LOGIN-Berechtigung Munition, dieses Problem anzugehen.

-           Diese Berechtigung erlaubt es, jeden Login und User zum impersonieren(!).

 

Wenn wir dieses mit einem DENY gegenüber dem Principal mit CONTROL SERVER Recht verwenden, verhindert es diesen, irgendeinen Login direkt zu impersonifizieren. (Warum sage ich “direkt”? –  Das sehen wir ein Stück weiter unten.)
Also sehen wir uns an, wie man einen Login mit CONTROL SERVER an einer Pivilegienerweiterung hindert, mithilfe der neuen Berechtigung

So, what for and how can we use those permissions on Server level?

 

IMPERSONATE ANY LOGIN

 

Do you remember the problem with CONTROL SERVER?
The biggest flaw of this permission was, that this permission also allowed Impersonation of any account, including privilege elevation to any sysadmin.
I have documented this and other problems with CONTROL SERVER in detail here:

CONTROL SERVER vs. sysadmin/sa: permissions, system procedures, DBCC, automatic schema creation and privilege escalation - caveats

 

Now in SQL Server 2014, by introducing the permission IMPERSONATE ANY LOGIN, gives us ammunition to tackle this problem.

-           This Permission permits to impersonate any Login and User(!).

 

If we DENY this to the Principal with CONTROL SERVER permission, it prevents him from impersonating any Login directly. (Why do I say “directly”? – We’ll see a bit further down.)

So let’s see how to prevent a Login with CONTROL SERVER from elevating privileges by impersonating another login with help of the new permission:

 

USE [master]

GO

 

CREATE LOGIN DBA_TheDude WITH PASSWORD=N'www', DEFAULT_DATABASE=[master], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF

GO

 

CREATE SERVER ROLE [Role_DBA]

 

ALTER SERVER ROLE [Role_DBA]

ADD MEMBER DBA_TheDude

 

GRANT CONTROL SERVER TO [Role_DBA]

GO

DENY IMPERSONATE ANY LOGIN TO [Role_DBA]

GO

 

CREATE DATABASE ControlServer_Schema_Demo

GO

 

-- ====================

-- === Test

 

EXECUTE AS LOGIN = 'DBA_TheDude'

 

-- Attempt impersonation:

EXECUTE AS LOGIN = 'sa';

-->

Msg 15406, Level 16, State 1, Line 9

Cannot execute as the server principal because the principal "sa" does not exist, this type of principal cannot be impersonated, or you do not have permission.

//

Die Ausführung als Serverprinzipal ist nicht möglich, weil der Prinzipal 'sa' nicht vorhanden ist, für diesen Typ von Prinzipal kein Identitätswechsel möglich ist, oder Sie nicht die erforderliche Berechtigung haben.

 

 

USE ControlServer_Schema_Demo

 

EXECUTE AS USER = 'dbo';

 

-->

Msg 15517, Level 16, State 1, Line 15

Cannot execute as the database principal because the principal "dbo" does not exist, this type of principal cannot be impersonated, or you do not have permission.

//

Die Ausführung als Datenbankprinzipal ist nicht möglich, weil der Prinzipal 'dbo' nicht vorhanden ist, für diesen Typ von Prinzipal kein Identitätswechsel möglich ist, oder Sie nicht die erforderliche Berechtigung haben.

 

Hurra!(?)

Privilege-Escalation-Risiko:

Wirklich? Immer noch?
Natürlich.

Wir laufen immer noch unter dem Kontext DBA_TheDude:

Hooray!(?)

Privilege-Escalation-risc:

Really? Still?
Of course.

 

Still we are running under the context of DBA_TheDude:

 

 

USE master;

 

CREATE LOGIN UtilizeMe WITH PASSWORD=N'www', DEFAULT_DATABASE=[master], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF

GO

 

GRANT CONTROL SERVER TO UtilizeMe

GO

 

Wir können den Login “UtilizeMe” nicht impersonifizieren, aber wir können und einfach mit seinem Passwort anmelden!

-           Nebenbei ein weiterer Grund, SQL Authentifizierung nicht zu verwenden, da er ansonsten die Credentials eines validen Windows-Login’s finden müsste – viel schwieriger, als einfach seinen eigenen Backdoor-account anzulegen.

We cannot Impersonate the “UtilizeMe” Login, but we can just Log On using his password!

-           Another reason to not use SQL authentication by the way, as he would then need to find a valid Windows-Login’s Credentials – much harder to just creating his own backdoor-account.

 

 

Um also unseren Administrator wirklich daran zu hindern, seine Privilegien zum Sysadmin zu erweitern, müssen wir auch mit DENY ALTER ANY LOGIN  und ALTER ANY SERVER ROLE arbeiten.

So in order to further prevent our Administrator from elevating privileges to sysadmin, we also need to work with DENY ALTER ANY LOGIN  and ALTER ANY SERVER ROLE.

 

Und kann DANN CONTROL SERVER endlich sicher verwendet werden?

NEIN!

 

Tatsächlich gibt es noch ein paar andere Dinge, die man tun kann, um die Berechtigungen von einem CONTROL SERVER-berechtigten Konto zu erweitern. Etwas trickreicher vielleicht, aber ein Angreifer mit einem guten Wissen über SQL Server (ich spreche also nicht von „Raketenwissenschaft“), wird in der Lage sein soetwas durchzuführen.

Mir ist bewusst, dass das “Separation of Duties in SQL Server 2014”-Whitepaper (Enthalten im Microsoft® SQL Server® 2014 Product Guide) die Kombination von GRANT CONTROL SERVER + DENY IMPERSONATE ANY tatschlich als Best Practice listet, aber dennoch…

 

Also, empfehle ich die Verwendung in irgendeiner Weise?
Das ist für mich persönlich eine harte Frage, da ich gerne viel weniger Leute sehen würde, die sa/sysadmin für tägliche Aufgaben verwenden/vergeben.

Leider ist es jedoch weit davon entfernt, perfekt zu sein, und in Sicherhit-belangen, alles, was nicht lupenrein ist, ist ein Risiko.
Aber ich sehe es durchaus als ersten Schritt, um Leute davon abzuhalten, von Anfang an die höchsten Berechtigungen zu verwenden, da viele einfach nicht die Zeit und Kenntnisse haben werden, dort auszubrechen.
Ich empfehle es in Kombination mit soliden Überwachung und Alarmen.

Wer das also anstelle von sa/sysadmin verwendet, verdient dennoch Applaus, da es zeigt, dass man sich kümmert und es wagt, Berechtigungen einzuschränken.

Can we THEN finally use CONTROL SERVER completely safely?

 

NO!

 

In fact there are a few other things one can do to elevate permissions from a CONTROL SERVER-permitted account. More tricky in a way, but an attacker with some good knowledge about SQL Server (note, I am not saying “rocket-scientist”) will be able to do that.

I am aware that the “Separation of Duties in SQL Server 2014”-Whitepaper (Contained in the Microsoft® SQL Server® 2014 Product Guide) does in fact list the combination of GRANT CONTROL SERVER + DENY IMPERSONATE ANY LOGIN as a best practice, but yet…

 

So do I recommend using it in any way?

That is a hard question for me personally, as I would like to see much less people using/granting sa/sysadmin for daily tasks, and this permission had the potential to make an end to it.

Unfortunately it is far from perfect, and in security-terms, anything not flawless, is a risk.

But in terms of getting people away from using the highest privileges from the very beginning, I do see it as a step, since many may just not have the time and skills to break out of it.

I do recommend using it in combination with some solid Auditing and alerts in place.
So anyone using this instead sa/sysasdmin still gets applause, as it shows you care and dare to limit permissions.

 

SELECT ALL USER SECURABLES


Diese Berechtigung kann verwendet werden, um einen hochgradig berechtigten Principal, der z.B. Troubleshooting/Analysen des Servers durchführt daran zu hindern, Nutzer-Daten auszulesen. – Vergesst nicht, auch EXECUTE in alle Nutzerdatenbanken zu verbieten, ansonsten kann derjenige immer noch alle gespeicherten Prozeduren (sofern vorhanden) ausführen, um an die Daten zu gelangen.
Auch das ist nicht Bombenfest, wie wir bereits von CONTROL SERVER und seinen Einschränkungen wissen.

Was sicherer ist, ist die Verwendung für eine Art Auditor, der ALLE Daten lesen (aber nicht ändern) können soll – ohne den Aufwand, in sämtlichen Nutzerdatenbanken Benutzer und Rechte zu vergeben.

SELECT ALL USER SECURABLES


This permission can be used for preventing a highly privileged Principal that may be troubleshooting/analyzing the server from reading any user data. - Do not forget to also deny EXECUTE in all User databases though, otherwise he can just execute the stored procedures (if any exist) to get to the data.
Also this is not bullet-proof as we already know from CONTROL SERVER and it’s restrictions.

What’s more safe, is the use for an Auditor that needs to read ALL data, but not change it - without the effort of creating users and permissions in all user databases.

 

CONNECT ANY DATABASE

 

Diese Berechtigung kann gut für Logins verwendet werden, die sich im Wesentlichen mit jeder Datenbank verbinden können and zum Beispiel Code Reviews durchführen sollen – indem man diese mit der VIEW ANY DEFINITION Berechtigung kombiniert.
Das ist in meinen Augen tatsächlich sehr gut verwendbar für viele Szenarien.

CONNECT ANY DATABASE

 

This permission can be used quite well for having logins that can basically connect to any database and for example do code reviews - by combining it with the VIEW ANY DEFINITION permission.
I do think this is actually of quite some use for many scenarios.

 

Happy “Server controlling”,

 

Andreas

DISABLE and DENY LOGIN, DENY USER & Effect on Impersonation and Permissions

DISABLE und DENY LOGIN, DENY USER & Effekt auf Impersonierung und Berechtigungen

(de)
Ein kurzer Artikel zu den Effekten – oder fehlenden Effekten – in Bezug auf das Deaktivieren & Verbieten von Connect für Logins und Users auf Impersonierung und Berechtigungen.

(en)
A short article on the effects - or missing effects - regarding the disabling & denying connect of Logins & Users on impersonation and permission.

Immer mal wieder kann man beobachten, dass Logins oder Usern die Connect-Berechtigung verboten bekommen wurde, oder ein Login deaktiviert wurde.

Die richtige Erwartung und Verständnis kann daher kritisch sein.

Sehen wir uns also eine einfache Demo an:
Wir werden das eingebaute sa-Konto, welches von vielen unter anderem als Datenbankbesitzer (mehr dazu bald in einem anderen Artikel – zwischenzeitlich lade ich Sie dazu ein, noch Daten zu der Umfrage zu diesem Thema einzusenden), ein weiteres frisch angelegtes Konto und eine Datenbank, genannt ImpersonateLogin mit dem entsprechenden User + einem weiteren User ohne Login: SQLUser.

Every once in a while one can observe that Logins or Users have been denied the Connect permission or a Login has been disabled.

Therefore a correct expectation and understanding can be critical.

So let’s see a simple demo:
We will use the built-in sa-Account, which is used by many as database owner among other (more on that soon in another article - meanwhile I do invite you to still send in data for the survey on that topic), another freshly created Account DeniedLogin and a database called ImpersonateLogin with the according User + another User without Login: SQLUser.

 DisabledPrincipals_Script

Ich deaktiviere also das sa-Konto ebenso wie das „DeniedLogin“-Konto – letzterem verbiete ich außerdem die Connect-Berechtigung (Erinnern wir uns daran: „Berechtigungen können nicht für sa, dbo, Entitäts-Besitzer, information_schema, sys oder für den Benutzer selbst erteilt, verweigert oder aufgehoben werden.“)

Der Datenbank-User „SQLUser“ bekommt die Connect-Berechtigung auf die Datenbank verboten.
In der GUI sieht das Ergebnis so aus:

So I am disabling the sa-account as well as the “DeniedLogin”-Account – the latter I also Deny the Connect permission (Remember we “Cannot grant, deny, or revoke permissions to sa, dbo, entity owner, information_schema, sys, or yourself.”)

The Database-User “SQLUser” gets denied the Connect permission on the database.

In the GUI the result looks like this:

 DisabledPrincipals_Setup_Disabled_Login

DisabledPrincipals_Setup_Disabled_sa

Nun führen wir 4 Tests durch:

Now let’s run 4 tests.

 DisabledPrincipals_Test1

Was diese Abfragen im Wesentlichen machen, ist, zu versuchen, den entsprechenden Login oder User zu impersonieren – und den Erfolg dadurch belegen, dass sie die dann jeweils aktiven Rollen-Mitgliedschaften zurückgeben.
Ergebnisse:

So essentially what those queries do, is trying to impersonate the respective Login or User – and proofing success by returning the then respective active role-memberships.

Results:

 DisabledPrincipals_Result

DeniedLogin: Impersonierung funktioniert + kein Verlust an Berechtigungen.
In other words: Denying Connect to a Login does not disallow Impersonation.
Impersonation is actually another permission which one can use and is not affected even by Disabling the Login!

DeniedLogin: Impersonation works + No loss of permissions.
In other words: Denying Connect to a Login does not disallow Impersonation.
Impersonation is actually another permission which one can use and is not affected even by Disabling the Login!

 DisabledPrincipals_Result

Dasselbe gilt für den sa: Impersonierung funktioniert + kein Verlust a Berechtigungen.

Im Folgenden ein Test für den User, dem die Connect-Berechtigung auf die Datenbank entzogen worden ist – und nicht als Login verwendet werden kann.

Same applies for sa: Impersonation works + No loss of permissions.

In the following test for the User which has been denied the Connect-permission onto the database – and cannot be used as a Login.

 DisabledPrincipals_Test2

Ergebnisse:

Msg 15517, Level 16, State 1, Line 3

Die Ausführung als Datenbankprinzipal ist nicht möglich, weil der Prinzipal 'DeniedLogin' nicht vorhanden ist,
für diesen Typ von Prinzipal kein Identitätswechsel möglich ist, oder Sie nicht die erforderliche Berechtigung haben.

 

Msg 916, Level 14, State 1, Line 3

Der Serverprinzipal 'S-1-9-3-4049223906-1289824279-1154161590-488313048.'
kann unter dem aktuellen Sicherheitskontext nicht auf die ImpersonateLogin-Datenbank zugreifen.

Results:

Msg 15517, Level 16, State 1, Line 3

Cannot execute as the database principal because the principal "DeniedLogin" does not exist,
this type of principal cannot be impersonated, or you do not have permission.

 

Msg 916, Level 14, State 1, Line 3

The server principal "S-1-9-3-4049223906-1289824279-1154161590-488313048."
is not able to access the database "ImpersonateLogin" under the current security context.

 

Das Ergebnis ist für beide Datenbank-User effektiv das gleiche.

Die GUID repräsentiert keinen reellen Server-Prinzipal, denn der User SQLUser hat keinen entsprechenden Login.
Daher sagt es uns, dass die User nicht innerhalb der Datenbank impersoniert werden können.

Der Unterschied für den 2. User ist, dass dieser User nur innerhalb der Datenbank existiert, aber zugleich expliziert verboten wurde, sich mit ihr zu verbinden Das hat im Endeffekt dasselbe Resultat, wie ihn zu deaktivieren – genau wie der Guest-User es ist.

The GUID does not represent a real server-principal, because the User SQLUser does not have a matching Login.
So it tells us, that the users cannot be impersonated inside the database.

The difference for the second user is, that this user only exists inside the database but at the same time has been explicitly denied to connect to it. This has essentially the same result as “disabling” it – just as the guest-user is.

 

Damit wäre gezeigt, dass das Deaktivieren von Logins keinerlei Sicherheit gegenüber Angriffen von Innen gibt. Und sogenannte Privilegien Erweiterung findet in aller Regel z.B. von innen heraus statt.

Auch der alte „Trick“, die Standard-Datenbank des Logins zu löschen, ist da keine Hilfe.

Für Datenbank-User hat es durchaus Effekt und verhindert das Anmelden an der jeweiligen Datenbank – auch „von Innen heraus“.

 

Thereby it is shown, that disabling of Logins does not give any security against attacks from inside. And so-called privilege elevation (/-escalation) usually takes part from internal.

Also the old “trick”, to drop the default-database of a Login, is of little help.

For database-users is indeed does have an effect and prevents logon/connect to the respective database – also “from inside”.

 

Konsequenterweise bleiben alle Berechtigungen (natürlich abgesehen von dem jeweiligen Deny) der jeweiligen Logins und User absolut unbeeinflusst von einer Deaktivierung jeglicher Weise.

Das gilt auch im Zusammenhang mit „External Access“-Berechtigung für Logins basierend auf asymmetrischen Schlüsseln.
(Hier ein Forum-Thread, in dem die Frage auftauchte: “SQL Login "disabled" flag does not work with asymmetric key??”)

ALTER LOGIN ist auch hier in BOL erklärt: technet.microsoft.com/en-us/library/ms189828.aspx

 

Ich hoffe, diese Dinge erklären einiges und speziell Empfehlungen in Sicherheits-Aspekten.

Consequentially all permissions (besides the one denied of course) of the respective Login and User stay totally unaffected by and method of deactivation.

This is also true in the context of “external access”-permission for Logins based on asymmetric keys.
(Here a forum-thread where the question appeared: “SQL Login "disabled" flag does not work with asymmetric key??”)

ALTER LOGIN is also explained in BOL here: technet.microsoft.com/en-us/library/ms189828.aspx

 

I hope those things clarified some things and especially recommendations in security-matters

 

Happy securing

Andreas

SQL Server Row- and Cell-Level Security – Disclosure vulnerability // Schwachstellen in Zeilen-basierter Sicherheit

 

(de)
Es ist Zeit für einen weiteren Artikel zum Thema Sicherheit.
Und durch einen Forum Thread zu „Datengesteuerter Sicherheit“ mittels der IS_MEMBER(), USER_NAME(), SUSER_SNAME() – Funktionen kam ich auf die Idee, ein kurzes Beispiel zu zeigen, wie sich solche Konstrukte leicht umgehen lassen und die geschützten/verborgenen Daten offengelegt werden können, wenn sie nicht mit weiteren Mitteln gesichert werden.
Sehen wir uns ein Beispiel an.

(en)
It’s time for another post on security matters.
And through a forum-thread on data-driven security by the means of views using the IS_MEMBER(), USER_NAME(), SUSER_SNAME() – functions, I came up with the idea of giving a short example how such constructs can easily be circumvented and the protected/hidden data become disclosed, when not being secured by further means.
So let’s look at an example.

Im Folgenden werden wir ein recht verbreitetes Szenario sehen, wie Sicherheit auf Zeilenebene / Row-Level Security (und auch Zellenebene/Cell-Level Security) implementiert werden kann.

Die Architektur ist recht einfach:
Eine Tabelle enthält Datenzeilen, von welchen einige von einer bestimmten Gruppe Personen gelesen werden darf, und andere Zeilen von anderen Personen – jeweils exklusiv.
Um das zu erreichen, wird eine Sicht angelegt. Diese Sicht muss natürlich denselben Besitzer haben, so dass der Prinzipal Berechtigungen auf die Sicht alleine erhalten kann, und durch die Besitzerkette an die Daten gelangt.
Innerhalb der Sicht ist eine Where-Klause, die einen Filter auf ein bestimmtes Attribut in der Tabelle enthält, durch das der Benutzer der aktuellen Sitzung erkannt wird und ausschließlich die Daten zurückgeliefert werden, die seiner Rollen-Mitgliedschaft entsprechen.
Natürlich gibt es auch komplexere Designs mit Zwischentabellen und mehrfachen Rollenmitgliedschaften/Rechten, aber am Ende teilen alle dieselbe Schwachstelle, die ich demonstrieren werde.
Im Folgenden zunächst ein Diagramm der Architektur.

In the following we will see a quite common scenario of how Row-Level Security (and also Cell-Level Security) can be implemented.

The architecture is quite simple:
A table is holding rows of data, some of which are supposed to be readable by a certain group of people, and other rows by other people – in each case exclusively.
In order to achieve this, a view is created. This view naturally must have the same owner, so the principal can be granted permissions on nothing but the view and get to the data by means of the ownership-chain.
Within the view there is a Where-clause which contains a filter on a certain attribute in the table, by which the user of the current session is detected and returned solely the data which matches his role-membership.

Of course there are also more complex designs with intermediate tables and multi-role-memberships/permissions, but it all comes down sharing the same vulnerability which I am about to demonstrate.

First of all here's a diagram of the high-level architecture:

 SQL_Row_Level_Security_Schema

 

Sehen wir uns das ganze also an.
Die Einrichtung Tabelle und der Sicht, inklusive 2er Beispieldatensätze:

So let’s see it in action.
The Setup of the Table and the View including 2 sample data rows:

 SQL_Row_Level_Security_Table_View_Setup

Die Spalte „Role“ wird von der Sicht verwendet, um die jeweilige Zeile, unter Verwendung der IS_MEMBER()-Funktion nur Mitgliedern der jeweils hinterlegten Datenbankrolle durchzureichen.

The column “Role” is used by the view to return the respective row by using the IS_MEMBER()-function only to members of the respectively stored database-role.

 SQL_Row_Level_Security_Table_View

Benutzer, Rollen und Berechtigungen:

User(s), Roles and Permissions:

 SQL_Row_Level_Security_User_Roles_Permissions

Erinnern wir uns, was die Tabelle enthält:

Now, remember what our table contains:

 SQL_Row_Level_Security_Data

In einer heilen Welt, vor dem Sündenfall, wäre dies ausreichend.
(Nachdem wir uns als „Andreas“, der Mitglied der Datenbankrolle RoleAlpha ist, einloggen) würden unsere Abfragen wie folgt aussehen, und lediglich die Zeilen zurückliefern, die der RoleAlpha „gehören“:

So in an innocent world, before the fall of mankind, this would be sufficient.
(After logging in as “Andreas”, who is member of the RoleAlpha database-role) our queries would look like this and only return the rows which “belong” to RoleAlpha:

 SQL_Row_Level_Security_Query

- Natürlich wird die Funktion User_Name() nur für Demo-Zwecke eingesetzt.
Ergebnis:

- Of course the function User_Name() is only used for demo-purposes.
Result:

 SQL_Row_Level_Security_Filtered_Data

Angriff
Aber Andreas spielt nicht fair. Er ist neugierig, was sonst noch in der Tabelle stehen könnte.
Also schreibt er eine Abfrage wie diese:

Attack
But, Andreas does not play nice.  He is curious on what else might be in the table.
So he crafts a query like this:

 SQL_Row_Level_Security_Attack

Und das Ergebnis ist:

And the result is:

 SQL_Row_Level_Security_Disclosure

Nicht „schön“, aber wir haben, was wir wollten: die „geschützten“ Daten.

Der bereits geschulte Leser erkennt diese Form des Angriffs vielleicht aus einem anderen Bereich wieder: SQL Injection.
Es ist eine Form des alten Freundes „Error Based Attack“ oder „Error Disclosure“, die auch bei schlecht geschriebenen Webanwendungen zum Zuge kommt. Das habe ich u.a. 2013 auf diversen Konferenzen gezeigt (Vortragsreihe).
Der Kontext ist ein wenig anders, aber die Idee dahinter ist dieselbe.

Not exactly “pretty”, but we got what we want: the “protected” data.

The well-educated reader may remember this kind of attack from a different area as well: SQL Injection.
It’s a form of the old fried “error based attack” or “error-disclosure”, which can also be used for badly written web-applications. I have also shown that amongst others in 2013 at several conferences (series of sessions).
The context is a little bit different, but the idea is the same.

 Security-Gate-Fail

Einigen kommt das Bild vielleicht schon bekannt vor :-)

Stellt sicher, dass das nicht Euer "Vorgarten" ist!

Wo wir davon reden:

To some, this picture may already look familiar :-)

Make sure it’s not your "front-yard"!

Speaking of which:

 

Schutzmaßnahmen

Was kann man gegen solche Angriffe tun?
Im Wesentlichen stehen einem 3 bekannte Möglichkeiten zur Verfügung:

1) Einsatz von gespeicherten Prozeduren, die alle Fehler abfangen, oder, wenn man unbedingt mit Sichten Arbeiten möchte, der Einsatz einer dazwischengeschalteten Multi-Statement-Tabellenwertfunktion

2) Datenverschlüsselung (Nicht TDE!)

3) Ähnlich wie 1, Aufbau einer Mittelschicht in der Anwendung, die derartiges unterbindet.

Und schlussendlich sollte man für kritische Daten auch über eine Überwachungslösung nachdenken.

Security-measures

What can prevent such forms of attack?
Essentially there are 3 well-known methods at hand:

1) The use of stored procedures which catch all errors, or, if one really wants to use views for some reason, using of a multi-statement table valued function which will be put between.

2) Data encryption (Not TDE!)

3) Similar to 1, implementation of a mid-tier in the application which prohibits such actions.

Finally one should also think about an Auditing solution for critical data.

Die hier gezeigte Technik der Row-Level Disclosure ist nicht wirklich etwas Neues, wird aber gerne immer mal vergessen.
Nachlesen kann man darüber zum Beispiel auch in diesem (alten, aber immer noch zutreffenden) Whitepaper:

The technique of Row-Level Disclosure shown above isn’t really new, but frequently forgotten about.
One can read about this, for example, in this (old, but still applicable) whitepaper:

Implementing Row- and Cell-Level Security in Classified Databases Using SQL Server 2005

 

Happy securing,

Andreas

 

Wer sich ermuntert fühlt, nun einmal richtig in das Thema „Sicherheit mit SQL Server“ einzusteigen, für den habe ich auch 3 erstklassige Trainings im Angebot:

If you now feel encouraged to really dive into the subject of “Security with SQL Server”, I do have 3 first-class Trainings on offer:

Für Beginner, die hier einen guten Überblick erhalten und Grundlegende Kenntnisse erlernen:

For Starters, who gain a good overview and learn essential knowledge in the basics:

(SES) SQL Server Security Essentials for Developers & Administrators (1 day)
3. April 2014 in Düsseldorf

Für Administratoren, die fortgeschrittene Sicherheitskonzepte umsetzen müssen:

For Administrators that have to implement advanced security concepts:

(SIA) Securityworkshop for SQL Server Administrators (advanced) (1 day)
4. April 2014 in Düsseldorf

Für Entwickler, die fortgeschrittene Sicherheitskonzepte umsetzen müssen:

For Developers that have to implement advanced security concepts:

(SID) Securitysworkshop for SQL Server Developers (advanced) (1 day)
24. April 2014 in Düsseldorf

Security-Check-Script & Survey: SQL Server Security - Database-Owners, critical Permissions and role membership / Sicherheitsprüfungs-Script & Umfrage: SQL Server Datenbankbesitzer, kritische Rechte und Rollenmitgliedschaft

(de)
In dieser Umfrage möchte ich einmal in einem größeren Kreis ermitteln, welche Accounts typischerweise als Datenbankbesitzer eingetragen werden. Die kumulierten Ergebnisse werde ich anschließend hier veröffentlichen um sie mit der Community zu teilen, zusammen mit einigen Empfehlungen hinsichtlich Sicherheits-Härtung.

Dabei interessieren vor allem bestimmte serverweite Berechtigungen nicht nur des verwendeten Logins selber, sondern auch, falls er Mitglied einer (custom) Server Role ist, bestimmte, kritische Rechte dieser Rolle.

Wer meine Vorträge zum Thema „Sicherheit in SQL Server“ in den letzten Jahren, und insbesondere der im Sommer 2013 gestarteten Reihe „SQL Server Attacked“ verfolgt hat, wird sich vielleicht hat erinnern, wie ich dort auch gezeigt habe, wie man aus einer Datenbank ausbrechen und volle Systemrechte erlangen kann („Privilegien Erweiterung“) – basierend auf einer Kombination von Datenbankbesitzer, -Konfiguration und Impersonierung.

Hier stelle ich nun einen T-SQL Script zur Verfügung, welcher

  • Den jeweiligen Datenbankbesitzer aller Datenbanken ermittelt
  • Ungültige/Fehlende Datenbankbesitzer erkennt
  • Anzeigt, ob der Besitzer direkt über sicherheitskritische systemweite Rechte verfügt
  • Mitgliedschaft in hochprivilegierten Server-Rollen anzeigt – inklusive der benutzerdefinierten Serverrollen (ab SQL 2012 möglich)
  • Die kritischen Datenbankeinstellungen „Vertrauenswürdig“ und „Datenbankverkettung“ anzeigt.

Und hier ist der Script:

(en)
In this survey, I would like to explore in a greater radius which accounts are typically used as database owners. I will subsequently publish the cumulated results here to share them with the community together with some recommendations for hardening security.

In this instance, particular server-wide permissions both of the used account as well as, in case of membership of a (custom) Server Role, critical permissions of that role, are of interest.

Those who have followed my presentations on the topic “Security in SQL Server” in the last years, and especially the „SQL Server Attacked“ series launched in the summer of 2013, may remember how I had also demonstrated there how to break out of a database and be granted full system rights (“Elevation of privileges”), - based on a combination of database owner, configuration and impersonation.

Here, I am providing a T-SQL Script which

  • Identifies the respective database owners of all databases
  • Detects invalid/missing database owners
  • Indicates whether the owner directly possesses security-critical system-wide rights
  • Indicates membership in high privilege Server Roles – including the user defined Server Roles (possible since SQL 2012)
  • Indicates the critical database configurations “trustworthy” and “database chaining”.

Here you can find the script:

 

Server 1: http://j.mp/13_SQL_DBO_Survey
Server 2: gallery.technet.microsoft.com/scriptcenter/Database-Owners-role-3af181f5/

 

- Er sollte auf allen SQL Servern ab der Version 2005 funktionieren (getestet 2008-2014).

Zum Zwecke der Umfrage bitte ich Euch, die anonymisierten Ergebnisse (am Besten in Excel-Format) an die Email survey@SarpedonQualityLab.com zu senden, oder auch hier in den Kommentaren zu posten.
Zum Zwecke der Anonymisierung kann man einfach die letzten 3 Spalten aus dem Resultset auslassen – diese haben für eine statistische Erhebung auch keinen Nutzen sondern sind nur für Eure internen Zwecke bestimmt :-).

Hier seht ihr ein Beispiel-Ergebnis:

-           It should be working on all SQL Servers since the 2005 version (tested: 2008-2014).

For the purpose of the survey, I would like to ask you to send the anonymized results (preferably in excel-format) to the email survey@SarpedonQualityLab.com, or as well post them here in the comments.

For anonymization purposes, you can simply leave out the last three columns from the result set – these are not of use to a data collection and only meant for your internal usage :-).

Here, you can see a sample result:

Database_Ownership_Permissions_Sample_Result

 -> click to enlarge

Mehrere Einträge für dieselbe Datenbank entstehen, wenn der Datenbankbesitzer – oder seine Serverrolle(!) über mehrere, der von mir als sicherheitskritisch klassifizierten Rechte verfügt. Diese stehen dann in der Spalte login_permission bzw. role_permission. Hinter den Kürzeln verbergen sich:
ALLG = ALTER ANY LOGIN
ALSR = ALTER ANY SERVER ROLE
CL  = CONTROL SERVER
XA  = EXTERNAL ACCESS ASSEMBLY
(mehr dazu auch hier: CONTROL SERVER vs. sysadmin/sa: permissions, system procedures, DBCC, automatic schema creation and privilege escalation - caveats).

Die Inhalte der Spalten DatabaseNo, database_owner und external_owner sind absichtlich allgemein gehalten – die exakten Namen sind wie gesagt in den letzten 3 Spalten zu finden.

Die Spalte db_owner_valid zeigt an, ob die Datenbank einen gültigen Besitzer hat. In diesem Fall besteht ein match zwischen dem „externen Besitzer“ und dem in der Datenbank selber hinterlegten. In der Spalte external_owner steht nur ob dieser „externe Besitzer“ sa ist oder nicht – der genaue Login steht dann in *External_Owner.Der Script speichert keine Daten dauerhaft im System ab und beseitigt seine temporären Zwischenergebnisse selbst.

Ich hoffe, ihr findet die Auswertung hilfreich – und ich hoffe, ihr könnt die (anonymisierten) Ergebnisse mit der Community teilen. Ich werde keine Email speichern oder verwenden, sondern nur die anonymisierten Abfrageergebnisse.

Ich bedanke mich für eure Teilnahme und Unterstützung der Community!
Ich verspreche, die kumulierten Ergebnisse in den nächsten Monaten zusammen mit entsprechenden Hinweisen auf Best & Bad Practices sowie auf möglichen Einfallstoren für Privilegienerweiterungs-Angriffen zu veröffentlichen.

Multiple entries for the same database occur when the database owner – or his serverrole(!) possess multiple of the permissions which I classified as security-wise critical. These are listed in the column login_permission respectively role_permission. The codes stand for:
ALLG = ALTER ANY LOGIN
ALSR = ALTER ANY SERVER ROLE
CL  = CONTROL SERVER
XA  = EXTERNAL ACCESS ASSEMBLY
(you can read more on that here: CONTROL SERVER vs. sysadmin/sa: permissions, system procedures, DBCC, automatic schema creation and privilege escalation - caveats).

The contents of the columns DatabaseNo, database_owner and external_owner are left general on purpose – the exact names can be found in the last 3 columns s mentioned above.

The column db_owner_valid indicates, whether the database has a valid owner. In this case there is a match between the „external owner“ and the one stored within the database itself. The column external_owner only shows whether that „external owner“ is sa or not –the exact Login is shown in *External_Owner.

The script does not permanently save any data in the system and removes its temporary intermediary results by itself.

I hope you find the report useful and I hope you can share the (anonymized) results with the community.
I will not store or use any email but only use the anonymized Query-results.

 Thank you in advance for your participation and support of the community!
I promise to publish the cumulated results with according details on best & bad practices as well as on to possible gateways to elevation of privilege attacks in the next months.

 

Andreas

1 3 5