Privilege Escalation to sysadmin via Trustworthy Database setting
In this final Blog-Post before joining the Microsoft SQL Server Security Team , I will tackle an old but important subject: the danger of the trustworthy database setting.
– I have first presented this publicly 2013 at SQL PASS Rally Amsterdam and since then at several other conferences, so it is nothing new in itself.
Since then I never really got to write about it. Seeing ever more databases with CLR or Service Broker enabled, I do believe this is an attack vector that one should really be aware of – both Administrators as well as Developers.
In short: the trustworthy-database option is part of the enabler of a privilege-elevation path from an application user to sysadmin.
Basically, this form of privilege escalation (aka elevation) attack needs 3 prerequisites:
1) A database-owner with high level server-scope-permissions, like sysadmin – aka: target
2) Sufficient permissions for the attacker
3) The Trustworthy Database Property bit set to on
Prerequisite No 1 – highly privileged database owner:
Ask yourself: what account do you use as database owner?
– To get a complete list of all your databases with owners and other security-wise critical settings, you can use my script from Technet: https://gallery.technet.microsoft.com/scriptcenter/Database-Owners-role-3af181f5/
My guess: More than half of you are using “sa”. (see: SQL Server Database Ownership: survey results & recommendations ). Most others will be using a Windows Account with sysadmin-membership.
Here you can find the database-owner in SSMS:
I have always advocated against using sa as a database owner, and here is now another piece, why.
Prerequisite No 2 – permissions to impersonate:
This one may seem a bit more complex at first. But in the end this one is very simple as well:
We need to run this under an account that has just sufficient permissions to impersonate the database owner.
Question 1: Who can impersonate dbo?
Answer: Anyone with IMPERSONATE-permission on dbo. You will probably not see this explicit permission being used often.
BUT: The built-in role “db_owner” has this permission (!).
Question 2: What Database roles are your Database applications member of?
Based on what I have seen in practice, most often Applications use either of the following:
1) Membership in db_datareader and db_datawriter-Roles + a form of a “db_executor” role.
2) some custom roles
3) db_owner – sadly and mostly because it is considered too time-taking to think about custom permission sets and schema-constraints.
Prerequisite No 3 – database trustworthy:
Now the final piece: The last mechanism that prevents us to get access outside of the database is that database code needs to explicitly be trusted to run outside the database level. The “clean” way to do this is to use certificate-signed modules.
But there is another method, and that is the Trustworthy-bit. Essentially it means that any code originating from within this database is trusted and can be executed. Then it is just a matter of permissions (which is why sa is so handy for an attacker).
Let’s demo this:
This property is also visible within SSMS:
Using my script from above you will see the problematic setting all at once:
And if we are running code as sysadmin, we have ALL the permissions, don’t we?
All it takes, is to be able to execute code as the database owner, who in turn is sysadmin. For that we have the “EXECUTE AS” command.
So, putting all the pieces together, this is ho we are going to…
Let’s take SQL-Injection, an age-old attack method, that until now has not gone away (If I am grated a wish: “Please educate your new Developers”.) Imagine the attacker is able to inject SQL Code with his own commands. Like the following:
?’ UNION SELECT IS_SRVROLEMEMBER (‘sysadmin’) , IS_MEMBER (‘db_owner’) , USER_NAME() — checking the account this command is running under
If the current Application user, in my case a SQL Account “WebAppOwner” is granted the “db_owner” role, can then run the following command via SQL-Injection:
He has just made himself sysadmin.
Alternatively, he could create a different Login for his own needs and try to hide it by manipulating system code (that’s another story, but I will most likely never get to blog this ;-)).
From here on he can do whatever he feels like. A skilled individual can then even install Windows Services on the machine (In my demo-sessions I added an FTP-server-role to the system, just to give you some idea.). Your imagination is the limit. Even elevation up to Windows Domain Administrator is very well possible once you own SQL Server. This I will not describe further though.
I hope I have convinced you:
PLEASE DO NOT USE “TRUSTWORTHY” as a shortcut to enable certain code. Use properly signed code. Use Certificates.
By the way:
now you know the reason why this setting is NOT passed on during a database Restore or Attach: It is simply too dangerous and has to be explicitly set by a sysadmin after bringing the database online (you need to take this into account when you are using Availability Groups also!).
Hopefully I have reached some of you who were unsure yet if trustworthy matters and convinced you to avoid it. Even if you may not have the combination of all those 3 prerequisites active right now: Systems are prone to change and you may lose track and miss the moment when it all comes together. Don’t be sorry, be pre-emptive.