From b4a55a809e5a209ccb316757468dc925aa6660a8 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 20 Jan 2013 13:45:58 +0100 Subject: [PATCH] Refactoring DBMS string escaping functions --- lib/controller/checks.py | 1 - lib/techniques/error/use.py | 1 - plugins/dbms/access/syntax.py | 34 +++---------------------- plugins/dbms/db2/syntax.py | 33 +++--------------------- plugins/dbms/firebird/syntax.py | 41 +++++------------------------- plugins/dbms/mssqlserver/syntax.py | 25 +++--------------- plugins/dbms/mysql/syntax.py | 20 ++++++--------- plugins/dbms/oracle/syntax.py | 24 +++-------------- plugins/dbms/postgresql/syntax.py | 24 +++-------------- plugins/dbms/sqlite/syntax.py | 17 +++++-------- plugins/dbms/sybase/syntax.py | 24 +++-------------- plugins/generic/syntax.py | 14 ++++++++++ 12 files changed, 52 insertions(+), 206 deletions(-) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index a5a817d1a..e9c387b41 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -7,7 +7,6 @@ See the file 'doc/COPYING' for copying permission import copy import httplib -import random import re import socket import time diff --git a/lib/techniques/error/use.py b/lib/techniques/error/use.py index e84f0680a..b6ea7f79f 100644 --- a/lib/techniques/error/use.py +++ b/lib/techniques/error/use.py @@ -23,7 +23,6 @@ from lib.core.common import incrementCounter from lib.core.common import initTechnique from lib.core.common import isListLike from lib.core.common import isNumPosStrValue -from lib.core.common import isTechniqueAvailable from lib.core.common import listToStrValue from lib.core.common import readInput from lib.core.common import unArrayizeValue diff --git a/plugins/dbms/access/syntax.py b/plugins/dbms/access/syntax.py index 677c1012b..0e7184081 100644 --- a/plugins/dbms/access/syntax.py +++ b/plugins/dbms/access/syntax.py @@ -5,7 +5,6 @@ Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/) See the file 'doc/COPYING' for copying permission """ -from lib.core.exception import SqlmapSyntaxException from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @@ -14,34 +13,7 @@ class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): - if quote: - while True: - index = expression.find("'") - if index == -1: - break - - firstIndex = index + 1 - index = expression[firstIndex:].find("'") - - if index == -1: - raise SqlmapSyntaxException("Unenclosed ' in '%s'" % expression) - - lastIndex = firstIndex + index - old = "'%s'" % expression[firstIndex:lastIndex] - unescaped = "" - - for i in xrange(firstIndex, lastIndex): - unescaped += "CHR(%d)" % (ord(expression[i])) - if i < lastIndex - 1: - unescaped += "&" - - expression = expression.replace(old, unescaped) - else: - unescaped = "".join("CHR(%d)&" % ord(c) for c in expression) - if unescaped[-1] == "&": - unescaped = unescaped[:-1] - - expression = unescaped - - return expression + def escaper(value): + return "&".join("CHR(%d)" % ord(_) for _ in value) + return Syntax._escape(expression, quote, escaper) diff --git a/plugins/dbms/db2/syntax.py b/plugins/dbms/db2/syntax.py index 20fc3262c..9a8186336 100644 --- a/plugins/dbms/db2/syntax.py +++ b/plugins/dbms/db2/syntax.py @@ -5,8 +5,6 @@ Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/) See the file 'doc/COPYING' for copying permission """ -from lib.core.data import logger -from lib.core.exception import SqlmapSyntaxException from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @@ -15,32 +13,7 @@ class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): - if expression == u"'''": - return "CHR(%d)" % (ord("'")) + def escaper(value): + return "||".join("CHR(%d)" % ord(_) for _ in value) - if quote: - while True: - index = expression.find("'") - if index == -1: - break - - firstIndex = index + 1 - index = expression[firstIndex:].find("'") - - if index == -1: - raise SqlmapSyntaxException("Unenclosed ' in '%s'" % expression) - - lastIndex = firstIndex + index - old = "'%s'" % expression[firstIndex:lastIndex] - unescaped = "" - - for i in xrange(firstIndex, lastIndex): - unescaped += "CHR(%d)" % (ord(expression[i])) - if i < lastIndex - 1: - unescaped += "||" - - expression = expression.replace(old, unescaped) - else: - expression = "||".join("CHR(%d)" % ord(c) for c in expression) - - return expression + return Syntax._escape(expression, quote, escaper) diff --git a/plugins/dbms/firebird/syntax.py b/plugins/dbms/firebird/syntax.py index a77359249..1722c3d8f 100644 --- a/plugins/dbms/firebird/syntax.py +++ b/plugins/dbms/firebird/syntax.py @@ -6,7 +6,6 @@ See the file 'doc/COPYING' for copying permission """ from lib.core.common import isDBMSVersionAtLeast -from lib.core.exception import SqlmapSyntaxException from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @@ -15,38 +14,10 @@ class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): - if isDBMSVersionAtLeast('2.1'): - if expression == u"'''": - return "ASCII_CHAR(%d)" % (ord("'")) - - if quote: - while True: - index = expression.find("'") - if index == -1: - break - - firstIndex = index + 1 - index = expression[firstIndex:].find("'") - - if index == -1: - raise SqlmapSyntaxException("Unenclosed ' in '%s'" % expression) - - lastIndex = firstIndex + index - old = "'%s'" % expression[firstIndex:lastIndex] - unescaped = "" - - for i in xrange(firstIndex, lastIndex): - unescaped += "ASCII_CHAR(%d)" % (ord(expression[i])) - if i < lastIndex - 1: - unescaped += "||" - - expression = expression.replace(old, unescaped) - else: - unescaped = "".join("ASCII_CHAR(%d)||" % ord(c) for c in expression) - if unescaped[-1] == "||": - unescaped = unescaped[:-1] - - expression = unescaped - - return expression + def escaper(value): + retVal = value + if isDBMSVersionAtLeast('2.1'): + retVal = "||".join("ASCII_CHAR(%d)" % ord(_) for _ in value) + return retVal + return Syntax._escape(expression, quote, escaper) diff --git a/plugins/dbms/mssqlserver/syntax.py b/plugins/dbms/mssqlserver/syntax.py index e4dca77c0..21a0503dc 100644 --- a/plugins/dbms/mssqlserver/syntax.py +++ b/plugins/dbms/mssqlserver/syntax.py @@ -5,7 +5,6 @@ Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/) See the file 'doc/COPYING' for copying permission """ -from lib.core.exception import SqlmapSyntaxException from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @@ -14,25 +13,7 @@ class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): - if quote: - while True: - index = expression.find("'") - if index == -1: - break + def escaper(value): + return "+".join("%s(%d)" % ("CHAR" if ord(value[i]) < 256 else "NCHAR", ord(value[i])) for i in xrange(len(value))) - firstIndex = index + 1 - index = expression[firstIndex:].find("'") - - if index == -1: - raise SqlmapSyntaxException("Unenclosed ' in '%s'" % expression) - - lastIndex = firstIndex + index - old = "'%s'" % expression[firstIndex:lastIndex] - - unescaped = "+".join("%s(%d)" % ("CHAR" if ord(expression[i]) < 256 else "NCHAR", ord(expression[i])) for i in xrange(firstIndex, lastIndex)) - - expression = expression.replace(old, unescaped) - else: - expression = "+".join("CHAR(%d)" % ord(c) for c in expression) - - return expression + return Syntax._escape(expression, quote, escaper) diff --git a/plugins/dbms/mysql/syntax.py b/plugins/dbms/mysql/syntax.py index 3e672220e..f1ff5afc9 100644 --- a/plugins/dbms/mysql/syntax.py +++ b/plugins/dbms/mysql/syntax.py @@ -6,10 +6,8 @@ See the file 'doc/COPYING' for copying permission """ import binascii -import re from lib.core.convert import utf8encode -from lib.core.exception import SqlmapSyntaxException from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @@ -18,14 +16,12 @@ class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): - if quote: - unescaped = expression - for item in re.findall(r"'[^']+'", expression, re.S): - try: - unescaped = unescaped.replace(item, "0x%s" % binascii.hexlify(item.strip("'"))) - except UnicodeEncodeError: - unescaped = unescaped.replace(item, "CONVERT(0x%s USING utf8)" % "".join("%.2x" % ord(_) for _ in utf8encode(item.strip("'")))) - else: - unescaped = "0x%s" % binascii.hexlify(expression) + def escaper(value): + retVal = None + try: + retVal = "0x%s" % binascii.hexlify(value.strip("'")) + except UnicodeEncodeError: + retVal = "CONVERT(0x%s USING utf8)" % "".join("%.2x" % ord(_) for _ in utf8encode(value.strip("'"))) + return retVal - return unescaped + return Syntax._escape(expression, quote, escaper) diff --git a/plugins/dbms/oracle/syntax.py b/plugins/dbms/oracle/syntax.py index 076d74b30..3cd775e57 100644 --- a/plugins/dbms/oracle/syntax.py +++ b/plugins/dbms/oracle/syntax.py @@ -5,7 +5,6 @@ Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/) See the file 'doc/COPYING' for copying permission """ -from lib.core.exception import SqlmapSyntaxException from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @@ -14,24 +13,7 @@ class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): - if quote: - while True: - index = expression.find("'") - if index == -1: - break + def escaper(value): + return "||".join("%s(%d)" % ("CHR" if ord(value[i]) < 256 else "NCHR", ord(value[i])) for i in xrange(len(value))) - firstIndex = index + 1 - index = expression[firstIndex:].find("'") - - if index == -1: - raise SqlmapSyntaxException("Unenclosed ' in '%s'" % expression) - - lastIndex = firstIndex + index - old = "'%s'" % expression[firstIndex:lastIndex] - unescaped = "||".join("%s(%d)" % ("CHR" if ord(expression[i]) < 256 else "NCHR", ord(expression[i])) for i in xrange(firstIndex, lastIndex)) - - expression = expression.replace(old, unescaped) - else: - expression = "||".join("CHR(%d)" % ord(c) for c in expression) - - return expression + return Syntax._escape(expression, quote, escaper) diff --git a/plugins/dbms/postgresql/syntax.py b/plugins/dbms/postgresql/syntax.py index 5be99a155..6b887a773 100644 --- a/plugins/dbms/postgresql/syntax.py +++ b/plugins/dbms/postgresql/syntax.py @@ -5,7 +5,6 @@ Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/) See the file 'doc/COPYING' for copying permission """ -from lib.core.exception import SqlmapSyntaxException from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @@ -19,24 +18,7 @@ class Syntax(GenericSyntax): e.g. SELECT 1 WHERE 'a'!='a'||'b' will trigger error ("argument of WHERE must be type boolean, not type text") """ - if quote: - while True: - index = expression.find("'") - if index == -1: - break + def escaper(value): + return "(%s)" % "||".join("CHR(%d)" % ord(_) for _ in value) # Postgres CHR() function already accepts Unicode code point of character(s) - firstIndex = index + 1 - index = expression[firstIndex:].find("'") - - if index == -1: - raise SqlmapSyntaxException("Unenclosed ' in '%s'" % expression) - - lastIndex = firstIndex + index - old = "'%s'" % expression[firstIndex:lastIndex] - unescaped = "(%s)" % "||".join("CHR(%d)" % (ord(expression[i])) for i in xrange(firstIndex, lastIndex)) # Postgres CHR() function already accepts Unicode code point of character(s) - - expression = expression.replace(old, unescaped) - else: - expression = "(%s)" % "||".join("CHR(%d)" % ord(c) for c in expression) - - return expression + return Syntax._escape(expression, quote, escaper) diff --git a/plugins/dbms/sqlite/syntax.py b/plugins/dbms/sqlite/syntax.py index c1832eeb6..9ff9ff382 100644 --- a/plugins/dbms/sqlite/syntax.py +++ b/plugins/dbms/sqlite/syntax.py @@ -6,10 +6,8 @@ See the file 'doc/COPYING' for copying permission """ import binascii -import re from lib.core.common import isDBMSVersionAtLeast -from lib.core.exception import SqlmapSyntaxException from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @@ -18,13 +16,10 @@ class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): - unescaped = expression + def escaper(value): + retVal = value + if isDBMSVersionAtLeast('3'): + retVal = "X'%s'" % binascii.hexlify(value) + return retVal - if isDBMSVersionAtLeast('3'): - if quote: - for item in re.findall(r"'[^']+'", expression, re.S): - unescaped = unescaped.replace(item, "X'%s'" % binascii.hexlify(item.strip("'"))) - else: - unescaped = "X'%s'" % binascii.hexlify(expression) - - return unescaped + return Syntax._escape(expression, quote, escaper) diff --git a/plugins/dbms/sybase/syntax.py b/plugins/dbms/sybase/syntax.py index 61188d533..add401260 100644 --- a/plugins/dbms/sybase/syntax.py +++ b/plugins/dbms/sybase/syntax.py @@ -5,7 +5,6 @@ Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/) See the file 'doc/COPYING' for copying permission """ -from lib.core.exception import SqlmapSyntaxException from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @@ -14,24 +13,7 @@ class Syntax(GenericSyntax): @staticmethod def escape(expression, quote=True): - if quote: - while True: - index = expression.find("'") - if index == -1: - break + def escaper(value): + return "+".join("%s(%d)" % ("CHAR" if ord(value[i]) < 256 else "TO_UNICHAR", ord(value[i])) for i in xrange(len(value))) - firstIndex = index + 1 - index = expression[firstIndex:].find("'") - - if index == -1: - raise SqlmapSyntaxException("Unenclosed ' in '%s'" % expression) - - lastIndex = firstIndex + index - old = "'%s'" % expression[firstIndex:lastIndex] - unescaped = "+".join("%s(%d)" % ("CHAR" if ord(expression[i]) < 256 else "TO_UNICHAR", ord(expression[i])) for i in xrange(firstIndex, lastIndex)) - - expression = expression.replace(old, unescaped) - else: - expression = "+".join("CHAR(%d)" % ord(c) for c in expression) - - return expression + return Syntax._escape(expression, quote, escaper) diff --git a/plugins/generic/syntax.py b/plugins/generic/syntax.py index 1a1b5a904..b6f4df1fc 100644 --- a/plugins/generic/syntax.py +++ b/plugins/generic/syntax.py @@ -5,6 +5,8 @@ Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/) See the file 'doc/COPYING' for copying permission """ +import re + from lib.core.exception import SqlmapUndefinedMethod class Syntax: @@ -15,6 +17,18 @@ class Syntax: def __init__(self): pass + @staticmethod + def _escape(expression, quote=True, escaper=None): + retVal = expression + + if quote: + for item in re.findall(r"'[^']+'", expression, re.S): + retVal = retVal.replace(item, escaper(item[1:-1])) + else: + retVal = escaper(expression) + + return retVal + @staticmethod def escape(expression, quote=True): errMsg = "'escape' method must be defined "