How do I exploit "EXEC #sql"? - sql-server

My co-worker is being unsafe with his code and is allowing a user to upload an SQL file to be run on the server.
He strips out any key words in the file such as "EXEC", "DROP", "UPDATE", "INSERT", "TRUNC"
I want to show him the error of his ways by exploiting his EXEC ( #sql )
My first attempt will be with 'EXEXECEC (N''SELECT ''You DRDROPOPped the ball Bob!'')'
But he might filter that all out in a loop.
Is there a way I can exploit my co-worker's code? Or is filtering out the key words enough?
Edit: I got him to check in his code. If the code contains a keyword he does not execute it. I'm still trying to figure out how to exploit this using the binary conversion.

Tell your co-worker he's a moron.
Do an obfuscated SQL query, something like:
select #sql = 0x44524f5020426f627350616e7473
This will need some tweaking depending on what the rest of the code looks like, but the idea is to encode your code in hex and execute it (or rather, let it be executed). There are other ways to obfuscate code to be injected.
You've got a huge security hole there. And the funny part is, this is not even something that needs to be reinvented. The proper way to stop such things from happening is to create and use an account with the correct permissions (eg: can only perform select queries on tables x, y and z).

Have a look at ASCII Encoded/Binary attacks ...
should convince your friend he is doomed.. ;)
And here some help on how to encode the strings ..
Converting a String to HEX in SQL

Related

How to escape a null character in T-SQL?

I'm using a library that doesn't support parametrized queries, so I'm trying to write a function to emulate them like this:
let params = [ String "\x00'blah" ] in
Mssql.execute ~params "SELECT $1"
To test this, I'm sending it a string of every ASCII character, and the only two that seem to need escaping are:
' - Needs to be escaped as ''
\0' - Seems like it has to be changed to CHAR(0)
The null character part makes my escaping function ridiculously complicated because it has to keep track of whether a string is open and if it needs to add +. I could write a much simpler version that converts it to something like CODE(0)+''''+'a'+'s'+'d' but I suspect that's going to be very inefficient when sending megabytes of data to the server. My version is also going to be crazy inefficient if I send a megabyte of null characters (not that I plan to do that, but I don't like leaving time-bombs in code).
What I'm wondering is -- Is there any other way to escape these null chars?
(Also, am I missing anything? I can't find any documentation for this since everyone seems to assume you have access to a decent T-SQL library).
EDIT: It looks like null-characters should work in T-SQL, but I'm running into a limitation of the library I'm using, where it calls FreeTDS's dbcmd, which assumes the string is null-terminated, and I can't seem to find any alternative function. It looks like rewriting the library I'm using to support real parameterized queries might be the only option :\
I don't know your library, but I know good library for that simple sql operations. This library is have simple methods to insert, update or delete records without write SQL command. Also support Merge command. Its mean if you don't know the record is exists or not but you want to save this.
If you want to encrypt sensitive data, also have a methods for this.
Here is example;
crypto.SetCryptoKey("DB-TEST-CUST");
dRec cust = new dRec("dbo.customer");
cust.fields["email"] = "john.lennon#gmail.com";
cust.fields["name"] = "John Lennon";
cust.fields["description"] = "John's secret world";
cust.fields["password"] = "abc123xyz".dEncryption(); //encryption text include some special characters, but methods support this.
if (cust.Insert() >= 0)
return "record inserted";
else
return "record error:" + db.LastException_Message;
for more information library's web site : https://www.dbdll.com/Documentation

Identify all strings in SQL Server code (red color - like in SSMS)

I was not able to solve this by myself so I hope I didn't miss any similar post here and I'm not wasting your time.
What I want is to identify (get a list) of all strings used in SQL Server code.
Example:
select 'WordToCatch1' as 'Column1'
from Table1
where Column2 = 'WordToCatch2'
If you put above code to SSMS all three words in apostrophes will be red but only words 'WordToCatch1' and 'WordToCatch2' are "real" strings used in code.
My goal is to find all those "real" strings in any code.
For example if I will have stored procedure 10k rows long it would be impossible to search them manually so I want something what will find all those "real" strings for me and return a list of them or something.
Thanks in advance!
The trouble is, Column1 is nothing particular different compared to WordToCatch1 and WordToCatch2 - not unless you parse the SQL yourself. You could modify your query to take the quotes away from Column1 and it will show up coloured black.
I guess a simple regex will show up all identifiers after an AS keyword, which would be easier than fully parsing SQL, if all the unwanted strings are like that, and its not just an example.

Proper-Casing Street names in SSRS

With the application that I am working with and writing reports for, the user is entering the Location in all upper case. It has been requested by those who my reports are going to that the Location be in proper case. This was fine till I realized that proper case does not recognize abbreviations. Is there a way to write an expression in SSDT that will, while converting the street name into proper case, also make is so abbreviations like "SE" or "DR" are upper case?
John Saunders is right, it's not simple, and it'd be better if you can fix the data at the source. But you can wrap your Proper Case function in a series of outer REPLACE Functions. It's not simple because you'll have to analyze your data and figure out all the abbreviations you want to handle, and manually code each one. It will get huge, so you might consider creating this function in SSRS custom code, so it doesn't look so cluttered in the expression builder.
Psuedo code would look something like this:
REPLACE(
REPLACE(
ProperCase(MyFieldName)
,"Se","SE")
,"Dr","DR")
Add a REPLACE(InnerExpression,ProperCaseExpression,UpperCaseExpression) for each individual abbreviation you want to handle. It won't be fun, but it will work.

Trying to escape a sp_executesql variable

I've run in to a problem with a software I'm configuring. I do not have access to the source code, only the config.
The issue is as follows, in the configuration the software expects me to enter a string, but I would like the string to jump out of the compare and instead execute a funtion.
Using sql profiler I get something like this:
exec sp_executesql N'SELECT * FROM dummyTable WHERE (Name LIKE #Pattern)',N'
This does not work in my setup, because pattern is not clearly defind in advanced. I need to take the
variable passed as pattern and run it trough a sql function but I can't figure out how. Typically Pattern contains a single char, in my example "1". I've tried altering the Pattern to use an escape char and run my function on it, but I think I'm missing someting (If this is at all possible).
The variable I've send from config is as follows:
{0}' or Name like dbo.RunCalulation({0})
Giving me the following:
'…#Pattern nvarchar(43)',#Pattern=N'1'' or Name like dbo.RunCalulation(1) '
This executes, but does not give any response, so I think the esacpe char does not work, and it compares the whole string to Name.
I'm real stuck at this, hope someone has a good idea what to do (I know that not having the source code is a real problem here.
One of the huge advantages of query parameters (such as #Pattern) is that they help protect against SQL injection (which is what you are trying to do).
So the answer is that you cannot do what you want. There's no way to escape the #Pattern parameter and add some of your own SQL to that query, because everything you pass as #Pattern will be interpreted as data, and never as SQL command text (which is the reason why your SQL text ends up inside the single quotes, and why your quote is automatically escaped to ''.).

Is this sufficient to prevent query injection while using SQL Server?

I have recently taken on a project in which I need to integrate with PHP/SQL Server. I am looking for the quickest and easiest function to prevent SQL injection on SQL Server as I prefer MySQL and do not anticipate many more SQL Server related projects.
Is this function sufficient?
$someVal = mssql_escape($_POST['someVal']);
$query = "INSERT INTO tblName SET field = $someVal";
mssql_execute($query);
function mssql_escape($str) {
return str_replace("'", "''", $str);
}
If not, what additional steps should I take?
EDIT:
I am running on a Linux server - sqlsrv_query() only works if your hosting environment is windows
The best option: do not use SQL statements that get concatenated together - use parametrized queries.
E.g. do not create something like
string stmt = "INSERT INTO dbo.MyTable(field1,field2) VALUES(" + value1 + ", " + value2 + ")"
or something like that and then try to "sanitize" it by replacing single quotes or something - you'll never catch everything, someone will always find a way around your "safe guarding".
Instead, use:
string stmt = "INSERT INTO dbo.MyTable(field1,field2) VALUES(#value1, #value2)";
and then set the parameter values before executing this INSERT statement. This is really the only reliable way to avoid SQL injection - use it!
UPDATE: how to use parametrized queries from PHP - I found something here - does that help at all?
$tsql = "INSERT INTO DateTimeTable (myDate, myTime,
myDateTimeOffset, myDatetime2)
VALUES (?, ?, ?, ?)";
$params = array(
date("Y-m-d"), // Current date in Y-m-d format.
"15:30:41.987", // Time as a string.
date("c"), // Current date in ISO 8601 format.
date("Y-m-d H:i:s.u") // Current date and time.
);
$stmt = sqlsrv_query($conn, $tsql, $params);
So it seems you can't use "named" parameters like #value1, #value2, but instead you just use question marks ? for each parameter, and you basically just create a parameter array which you then pass into the query.
This article Accessing SQL Server Databases with PHP might also help - it has a similar sample of how to insert data using the parametrized queries.
UPDATE: after you've revealed that you're on Linux, this approach doesn't work anymore. Instead, you need to use an alternate library in PHP to call a database - something like PDO.
PDO should work both on any *nix type operating system, and against all sorts of databases, including SQL Server, and it supports parametrized queries, too:
$db = new PDO('your-connection-string-here');
$stmt = $db->prepare("SELECT priv FROM testUsers WHERE username=:username AND password=:password");
$stmt->bindParam(':username', $user);
$stmt->bindParam(':password', $pass);
$stmt->execute();
No, it's not sufficient. To my knowledge, string replacement can never really be sufficient in general (on any platform).
To prevent SQL injection, all queries need to be parameterized - either as parameterized queries or as stored procedures with parameters.
In these cases, the database calling library (i.e. ADO.NET and SQL Command) sends the parameters separately from the query and the server applies them, which eliminates the ability for the actual SQL to be altered in any way. This has numerous benefits besides injection, which include code page issues and date conversion issues - for that matter any conversions to string can be problematic if the server does not expect them done the way the client does them.
I partially disagree with other posters. If you run all your parameters through a function that double the quotes, this should prevent any possible injection attack. Actually in practice the more frequent problem is not deliberate sabotague but queries that break because a value legitimately includes a single quote, like a customer named "O'Hara" or a comment field of "Don't call Sally before 9:00". Anyway, I do escapes like this all the time and have never had a problem.
One caveat: On some database engines, there could be other dangerous characters besides a single quote. The only example I know is Postgres, where the backslash is magic. In this case your escape function must also double backslashes. Check the documentation.
I have nothing against using prepared statements, and for simple cases, where the only thing that changes is the value of the parameter, they are an excellent solution. But I routinely find that I have to build queries in pieces based on conditions in the program, like if parameter X is not null then not only do I need to add it to the where clause but I also need an additional join to get to the value I really need to test. Prepared statements can't handle this. You could, of course, build the SQL in pieces, turn it into a prepared statement, and then supply the parameters. But this is just a pain for no clear gain.
These days I mostly code in Java that allows functions to be overloaded, that is, have multiple implementations depending on the type of the passed in parameter. So I routine write a set of functions that I normally name simply "q" for "quote", that return the given type, suitably quoted. For strings, it doubles any quote marks, then slaps quote marks around the whole thing. For integers it just returns the string representation of the integer. For dates it converts to the JDBC (Java SQL) standard date format, which the driver is then supposed to convert to whatever is needed for the specific database being used. Etc. (On my current project I even included array as a passed in type, which I convert to a format suitable for use in an IN clause.) Then every time I want to include a field in a SQL statement, I just write "q(x)". As this is slapping quotes on when necessary, I don't need the extra string manipulation to put on quotes, so it's probably just as easy as not doing the escape.
For example, vulnerable way:
String myquery="select name from customer where customercode='"+custcode+"'";
Safe way:
String myquery="select name from customer where customercode="+q(custcode);
The right way is not particularly more to type than the wrong way, so it's easy to get in a good habit.
String replacement to escape quotes IS sufficient to prevent SQL injection attack vectors.
This only applies to SQL Server when QUOTED_IDENTIFIER is ON, and when you don't do something stoopid to your escaped string, such as truncating it or translating your Unicode string to an 8-bit string after escaping. In particular, you need to make sure QUOTED_IDENTIFIER is set to ON. Usually that's the default, but it may depend on the library you are using in PHP to access MSSQL.
Parameterization is a best practice, but there is nothing inherently insecure about escaping quotes to prevent SQL injection, with due care.
The rel issue with escaping strings is not the efficacy of the replacement, it is the potential for forgetting to do the replacement every time.
That said, your code escapes the value, but does not wrap the value in quotes. You need something like this instead:
function mssql_escape($str) {
return "N'" + str_replace("'", "''", $str) + "'";
}
The N above allows you to pass higher Unicode characters. If that's not a concern (i.e., your text fields are varchar rather than nvarchar), you can remove the N.
Now, if you do this, there are some caveats:
You need to make DAMNED SURE you call mssql_escape for every string value. And therein lies the rub.
Dates and GUID values also need escaping in the same manner.
You should validate numeric values, or at least escape them as well using the same function (MSSQL will cast the string to the appropriate numeric type).
Again, like others have said, parameterized queries are safer--not because escaping quotes doesn't work (it does except as noted above), but because it's easier to visually make sure you didn't forget to escape something.

Resources