views:

129

answers:

4

So I was playing with my MS SQL Server 2008 app to see how good it is protected against SQL injections. The app lets users to create views in the database.

Now consider the following:

create view dbo.[]]; drop database foo--] as select 1 as [hi!]

This creates a view with a name of ]; drop database foo--. It is valid and you can select from it (returns the number 1, obviously).

Strange thing #1:

In SQL Management Studio, the query SELECT [hi!] FROM [dbo].[]]; drop database foo--] is red-underlined as incorrect, claiming that the object name is not valid. Nevertheless, it executes and returns the 1.

Strange thing #2:

Call to OBJECT_ID(']; drop database foo--') yields NULL (which means the object does not exist), but the following query returns information about the view properly:

select * from sys.objects where name = ']; drop database foo--';

Are those bugs or am I missing a point?

+16  A: 

You're missing the point. SQL Server can't protect itself against SQL injection - if somebody has direct access to your database then you've already been pwned. It's your application that needs to protect against SQL injection by parameterizing queries, and preventing these kinds of statements from ever making it to the database.

Aaronaught
No, you miss the point here.The `drop database` clause is not executed because my app properly escaped it. The view `is` created, it's just got a strange name. Why SQL server fails to report about this view with OBJECT_ID function? Why the syntax in wrongly highlighted, but executed properly?
GSerg
@GSerg: Because SQL Server Management Studio has a syntax highlighting bug? Who cares? Escaping SQL is not the correct way to prevent SQL injection. Database Security 101: Parameterize your commands.
Aaronaught
Also, this quote: "The app lets users create views in the database." If you're allowing untrusted users to execute DDL statements, then in my opinion, you've already lost.
Aaronaught
Users are not allowed to execute anything. But then can provide a name for the view. If they are mean and provide a name like shown above, they will get a view with a mean name. No sql injection here. Please read the question again.
GSerg
@GSerg: I don't know what you're trying to say. If users can provide a name for a view, then obviously they are causing DDL to be executed which creates the view. So the only relevant question is: Are these users trusted? If so, it's a non-issue, and if not, then you have an insecure design. I'm not saying that there are no conceivable reasons for such a design - there might be - but in that case it's up to **you** to make sure you've sanitized the input properly, it's not up to SQL Server. The only "SQL Injection" vulnerability here, if there is one, is in your app design.
Aaronaught
>> If users can provide a name for a view, then obviously they are causing DDL to be executed which creates the view. That is not true. The view is created inside a stored procedure. Users do not have permissions to create views, but they have execute perms on the procedure, and procedure owner has perms to create views. No untrusted DDL here.
GSerg
@GSerg: So what does the stored procedure do? Execute some dynamic SQL? You can't parameterize the name in `CREATE VIEW` so I see no alternative. Either way you have privilege escalation and a potential injection vulnerability of **your** making - it's not a bug in SQL server.
Aaronaught
@Aaronaught: you keep insisting that the name of the view is actually (or can be) executed as a command, whereas it never is. Neither me nor SQL server will try to do it. I wasn't saying there was a vulnerability **in this part**. I was only asking why SQL Server fails to see a view with a fancy looking-like-injection name, and whether that could mean there is a hidden vulnerability that can be exploited **in some other way**, not by creating yet another view. There is no potential vulnerability in my `create view` statement. It always succeeds regardless the name.
GSerg
A: 

That's like using your key to get into your car and then saying "hey there's a security hole, I'm allowed to steal the radio"

Jack Marchetti
+6  A: 
  • #1: that only means the intellisense parser is not up to par witht the finer details of SQL syntax. While it may be an intellisense bug, it is not an injection vector.
  • #2: object_id() accepts multipart names, so it needs the name in quotes if ambiguous: select object_id('[]]; drop database foo--]')
Remus Rusanu
+1. The only sane answer so far.
GSerg
GSerg I did test the object_id() before posting and it returns an object for me. Make sure you execute it correctly (in the right database, properly escaped name, view actually exists etc). SQL 2008 SP1.
Remus Rusanu
Thanks, that was it. I was sure that since object_id accepts variables as its argument, it does not need brackets when only one part of the name is provided. I'm glad it's not a bug.
GSerg
A: 

It seems the problem is that you are yourself causing SQL injection by accepting user input and using it as SQL statement text.

The fact that you "properly escaped" the ] (by substituting with ]]) really doesn't matter - it's you allowing the user input to be used as anything else but a value by definition means you allow SQL injection.

Roland Bouman
Do you have a reference to this definition of SQL injection that specifies that it applies to all user input besides values?
Gabe
gabe: no - don't need one. It is easy to see why: the user-defined identifier becomes part of the SQL statement. Hence, it is injected into the statement. By definition this is SQL injection. This is very different from the case where the user supplies a value which is bound to a parameter/placeholder: in that case, the form of the SQL statement remains unchanged, only a value is bound. Hope that clears it up.
Roland Bouman