New Techniques in SQLi Obfuscation SQL never before used in SQL Injection Nick Galbreath @ngalbreath nick0client9 . com DEFCON 20 at the Rio in sunny Las Vegas 2012-07-27 Friday 4:20 pm! along or get the latest version: http: //slidesha. re/ MfOiNR That's an OH, not a zer0 SQL Specification http://www.contrib.andrew.cmu.edu/ ~shadow/sql/sql 1 992.txt 625 pages of plain text http://savage.net.au/SQI_/sql-2003-2.bnf I 1 9 pages of pure BNF No one implements exactly Everyone has extensions, exceptions, bugs Regexp Based WAF (?:\)\s*when\s*\d+\s*then) | ( ?: "\s*( ? :#|— | {) ) | (?:\/\*!\s?\d+) | (?:ch(?:a)?r\s*\(\s*\d) | (?:(?:( n?and |x?or | not )\s+ | \ | \ | |\&\&)\s*\w+\( ) (?: [\s()]case\s*\0 | (?:\)\s*like\s*\() | ( ? : having\s* [~\s] +\s* [~\w\s] ) |(?:if\s?\( [\d\w] \s* [=<>~] ) (?:'As*or\s*"?\d) |(?:\\x(?:23|27|3d)) |(?:~.?"$) |(?:(?:~["\\]*(?: [\d"]+| [—]+") )+\s*( ?: n?and |x?or | not | \ | \ | | \&\&)\s* [\w" [+&!(§(),.-]) | (? : [~\w\s]\w+\s*[ |-] \s*"\s*\w) | (?:@\w+\s+(and|or)\s*["\d]+) | (?:@[\w-]+\s(and |or)\s*[~\w\s] ) |(?: [~\w\s: ]\s*\d\W+r\w\s]\s*". ) | (?:\Winformation_schema | table_name\W) (?:"\s*\*.+(?:or|id)\W*"\d) |(?:\~") | ( ?:"[\w\s"-]+(?<=and\s) (?<=or\s) ( ?<=xor\s) ( ?<=nand\s) (?<=not\s) (?<=\ |\ | ) ( ?<=\&\S,)\w+\( ) | ( ? : M\s\d]*[^\w\s]+\W*\d \W*.*["\d] ) | ( ? : "\s* [~\w\s? ] +\s* [~\w\s] +\s*" ) | (?:"\s*r\w\s]+\s*[\W\d] .*(?:# |— ) ) | ( ? : " .*\*\s*\d) | (?: "\s*or\s [~\d] + [\w-] +.*\d) | ( ?: [()*<>%+-] [\w-]+[~\w\s] +"[-,]) (?:\d"\s+"\s+\d) |(?:~admin\s*"|(\/\*)+"+\s?(?:— |#|\/\*|{)?) | ( ?: "\s*or [\w\s-]+\s*[+<>=( ) ,-]\s*[\d"] ) |(?:"\s*^\w\s]?=\s*") |(7:"\W*[4=]+\W*") |(?:"\s*[!=|] [\d\s !=+-]+.*["(] .*$) |(?:"\s*[!=|] [\d\s!=]+.*\d+$) | (?:"\s*like\W+[\w"(] ) | (?:\sis\s*0\W) | (?:where\s [\s\w\. ,-]+\s=) | (?:"[<>-]+") (?:union\s*(?:all|distinct | [ ( !@] *) ?\s* [ ( []*\s*select) | (?:\w+\s+like\s+\") | ( ? : like\s*"\%) | (?:"\s*like\W*["\d] ) | (?:"\s*(?:n?and|x?or|not |\|\| |\&\&)\s+[\s \w] +=\s*\w+\s*having) | ( ? : "\s*\*\s*\w+\W+" ) | ( ? : "\s* [~?\w\s=. , ; ) ( ] +\s* [((§"] *\s*\w+\W+\w) | ( ? : select\s* [\ [\] ( ) \s\w\ . , "-] +f rom) | ( ? : f ind_in_set\s*\ ( ) (?:in\s*\(+\s*select) | (?: (?:n?and|x?or|not |\|\| ]\&\&)\s+[\s\w+]+(?: regexp\s*\( | sounds\s+like\s*" | [=\d]+x) ) | ("\s*\d\s*(?:— |#) ) | (?:" [%&<> /v =]+\d\s*(=| or)) | (?:"\W+[\w+-]+\s*=\s*\d\W+") | (?:"\s*is\s*\d.+"?\w) | (?:"\ | ? [\w-] {3,} [~\w\s. , ]+") | (?:"\s*is\s*[\d. ]+\s*\W.*") (?: [\d\W] \s+as\s* ["\w] +\s*f rom) | ( TiMWAd] +\s*(?: union | select j create | rename | truncate j load | alter [delete | update | insert |desc) ) | ( ? : ( ? : select | create | rename | truncate | load | alter | delete | update | insert |desc)\s+( ?: (?:group_)concat j char | load_f ile)\s?\( ?) | (?:end\s*\) ; ) | ("\s+regexp\W) | ( ? : [\s( ] load_f ile\s*\( ) (?:@.+=\s*\(\s*select) | (?:\d+\s*or\s*\d+\s*[\-+] ) | (?:\/\w+; ?\s+(?: having | and | or | select )\W) | (?:\d\s+group\s+by.+\( ) | (?:(?: ; |#|— )\s*(?: drop | alter) ) | (?: (?:; |#|— )\s*(?: update |insert)\s*\w{2,}) |(?: [~\w] SET\s*, and ), pass a string literal representing a SQL statement to a subprogram, without doubling the quotation marks around 'INVALID' as follows: func_call(q' [SELECT index_name FROM user_indexes WHERE status = ' INVALID ' ] ' ) ; Operators and Expressions Operators! ! and !! Factorial (pgsql) \l square root (pgsql) ||/ cube root (pgsql) # bitwise XOR (pgsql, conflicts with MySQL) ** exponents (oracle) More Operators! !=, <=> (mysql), <> (mssql), A = (oracle) !>, !< not less than, (mssql) A Bitwise XOR (oracle) Expressions! Using the common query extension of "OR 1 = 1" Besides using literals, one can use functions: • COS(O) = SIN(PI()/2) • COS(@VERSION) = -SIN(@VERSION + PI()/2) EXCEPT (mssql) MINUS (Oracle) • Like UNION, UNION ALL • But returns all results from first query minus/except the ones from the second query • There is also INTERSECT as well. • I think someone clever could use these, typically not in WAF rules. Side Note: "IN" lists e.g WHERE id IN (1,2,3,4) .... These have to be manually created. There is no API or parameter binding for this construct in any platform,framework or language. There is no consistent, safe way to make this (other than convention, validation) Why don't we see more attacks using these techniques? • Dumb attacks work (for now) • I don't get see the more advanced attacks What's Next? Add more parsing rules to libinjection More testing frameworks Investigate BIG I NT types pgsql has a regexp engine, and various other datatypes Worry about various character encodi Primary References • http://dev.mysql.eom/doc/refman/5.6/en/ func-op-summary-ref.html • http://www.postgresql.Org/docs/9. 1 /static/ functions.html • http://msdn.microsoft.com/en-us/library/ bb5 1 074 1 • http://docs.oracle.com/cd/B28359_0 1 / Thanks! Nick Galbreath @ngal breath nickg@client9.com https://github.com/client9/libinjection