From 34580f56fc8e8b4e977bed3364e008cd42d71c2b Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 12 Oct 2010 22:45:25 +0000 Subject: [PATCH] added --tamper option --- lib/core/option.py | 123 +++++++++++++++++++++++++------------- lib/parse/cmdline.py | 3 + lib/request/connect.py | 6 +- tamper/__init__.py | 0 tamper/dummy.py | 6 ++ tamper/ifnull2ifisnull.py | 11 ++++ 6 files changed, 107 insertions(+), 42 deletions(-) create mode 100644 tamper/__init__.py create mode 100644 tamper/dummy.py create mode 100644 tamper/ifnull2ifisnull.py diff --git a/lib/core/option.py b/lib/core/option.py index 547115143..97dac9880 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -542,6 +542,45 @@ def __setDBMS(): errMsg += "fingerprint it for you." raise sqlmapUnsupportedDBMSException, errMsg +def __setTamperingFunctions(): + """ + Loads tampering functions from given module path(s). + """ + if conf.tamper: + kb.tamperFunctions = [] + import inspect + import sys + for file in conf.tamper.split(';'): + if not file: + continue + elif not os.path.exists(file): + errMsg = "missing tampering module file '%s'" % file + raise sqlmapFilePathException, errMsg + elif os.path.splitext(file)[1] != '.py': + errMsg = "tampering module file should have an extension '.py'" + raise sqlmapSyntaxException, errMsg + dirname, filename = os.path.split(file) + dirname = os.path.abspath(dirname) + if not os.path.exists(os.path.join(dirname, '__init__.py')): + errMsg = "make sure that there is an empty file '__init__.py' " + errMsg += "inside of tampering module directory '%s'" % dirname + raise sqlmapGenericException, errMsg + if dirname not in sys.path: + sys.path.insert(0, dirname) + try: + module = __import__(filename[:-3]) + except ImportError, msg: + raise sqlmapSyntaxException, "can't import module file '%s' (%s)" % (file, msg) + + found = False + for name, function in inspect.getmembers(module, inspect.isfunction): + if name=="tamper" and function.func_code.co_argcount == 2: + kb.tamperFunctions.append(function) + found = True + break + if not found: + raise sqlmapGenericException, "missing function 'tamper(place, value)' in tampering module '%s'" % filename + def __setThreads(): if not isinstance(conf.threads, int) or conf.threads <= 0: conf.threads = 1 @@ -989,58 +1028,59 @@ def __setKnowledgeBaseAttributes(): debugMsg = "initializing the knowledge base" logger.debug(debugMsg) - kb.absFilePaths = set() - kb.assumeEmpty = False - kb.bannerFp = advancedDict() + kb.absFilePaths = set() + kb.assumeEmpty = False + kb.bannerFp = advancedDict() - kb.cache = advancedDict() - kb.cache.regex = {} + kb.cache = advancedDict() + kb.cache.regex = {} - kb.commonOutputs = None - kb.data = advancedDict() + kb.commonOutputs = None + kb.data = advancedDict() # Basic back-end DBMS fingerprint - kb.dbms = None - kb.dbmsDetected = False + kb.dbms = None + kb.dbmsDetected = False # Active (extensive) back-end DBMS fingerprint - kb.dbmsVersion = [ "Unknown" ] + kb.dbmsVersion = [ "Unknown" ] - kb.dep = None - kb.docRoot = None - kb.dynamicContent = [] - kb.lastErrorPage = None - kb.headersCount = 0 - kb.headersFp = {} - kb.htmlFp = [] - kb.injParameter = None - kb.injPlace = None - kb.injType = None - kb.injections = xmlobject.XMLFile(path=paths.INJECTIONS_XML) - kb.hintValue = None - kb.nullConnection = None + kb.dep = None + kb.docRoot = None + kb.dynamicContent = [] + kb.lastErrorPage = None + kb.headersCount = 0 + kb.headersFp = {} + kb.htmlFp = [] + kb.injParameter = None + kb.injPlace = None + kb.injType = None + kb.injections = xmlobject.XMLFile(path=paths.INJECTIONS_XML) + kb.hintValue = None + kb.nullConnection = None # Back-end DBMS underlying operating system fingerprint via banner (-b) # parsing - kb.os = None - kb.osVersion = None - kb.osSP = None + kb.os = None + kb.osVersion = None + kb.osSP = None - kb.parenthesis = None - kb.partRun = None - kb.lastRequestUID = 0 - kb.queryCounter = 0 - kb.resumedQueries = {} - kb.stackedTest = None - kb.targetUrls = set() - kb.testedParams = set() - kb.timeTest = None - kb.unionComment = "" - kb.unionCount = None - kb.unionPosition = None - kb.unionNegative = False - kb.unionFalseCond = False - kb.valueStack = [] + kb.parenthesis = None + kb.partRun = None + kb.lastRequestUID = 0 + kb.queryCounter = 0 + kb.resumedQueries = {} + kb.stackedTest = None + kb.tamperFunctions = None + kb.targetUrls = set() + kb.testedParams = set() + kb.timeTest = None + kb.unionComment = "" + kb.unionCount = None + kb.unionPosition = None + kb.unionNegative = False + kb.unionFalseCond = False + kb.valueStack = [] def __saveCmdline(): """ @@ -1185,6 +1225,7 @@ def init(inputOptions=advancedDict()): __basicOptionValidation() __setRequestFromFile() __setMultipleTargets() + __setTamperingFunctions() parseTargetUrl() parseTargetDirect() diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index e241187aa..f6c4127dd 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -204,6 +204,9 @@ def cmdLineParser(): action="store_true", default=False, help="Use operator BETWEEN instead of default '>'") + injection.add_option("--tamper", dest="tamper", + help="Use given module(s) for tampering injection data") + # Techniques options techniques = OptionGroup(parser, "Techniques", "These options can " "be used to test for specific SQL injection " diff --git a/lib/request/connect.py b/lib/request/connect.py index d4c96b847..0106518fd 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -305,9 +305,13 @@ class Connect: if not place: place = kb.injPlace + + if kb.tamperFunctions: + for function in kb.tamperFunctions: + value = function(place, value) if "GET" in conf.parameters: - get = conf.parameters["GET"] if place != "GET" or not value else value + get = conf.parameters["GET"] if place != "GET" or not value else value if "POST" in conf.parameters: post = conf.parameters["POST"] if place != "POST" or not value else value diff --git a/tamper/__init__.py b/tamper/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tamper/dummy.py b/tamper/dummy.py new file mode 100644 index 000000000..a924869fb --- /dev/null +++ b/tamper/dummy.py @@ -0,0 +1,6 @@ +def tamper(place, value): + print "Hi, World!" + print value + if place=="GET" and value: + value=value.upper() + return value diff --git a/tamper/ifnull2ifisnull.py b/tamper/ifnull2ifisnull.py new file mode 100644 index 000000000..7b43e651e --- /dev/null +++ b/tamper/ifnull2ifisnull.py @@ -0,0 +1,11 @@ +import re + +#not finished (watch for number of parenthesis) +#IFNULL(A,B) -> IF(ISNULL(A),B,A) +def tamper(place, value): + if value: + if value.find("IFNULL") > -1: + import pdb + pdb.set_trace() + value = re.sub(r"IFNULL(\(|%28)(?P.+?)(,|%2C)(?P.+?)(\)|%29)", lambda match: "IF%%28ISNULL%%28%s%%29%%2C%s%%2C%s%%29" % ("A="+match.group("A"), "B="+match.group("B"), "A="+match.group("A")), value) + return value